2016-02-12 57 views
1

我最近開始在.Net Web應用程序中使用EF和MVC,並且遇到了一個問題,並且想知道您的想法是什麼以及是否你將能夠指向正確的方向。一對多使用ICollection與實體框架,以及如何提高性能

所以,我有兩個類:DataGroup和DataElements。 DataElement可以在一個DataGroup中,也可以不在一個DataGroup中。我用流利的API中的DataContext來實現這一點:

modelBuilder.Entity<DataGroup>() 
      .HasMany(dg => dg.DataElements) 
      .WithOptional() 
      .HasForeignKey(de => de.DataGroup_Id); 

在我DATAGROUP類我有以下幾點:

public virtual ICollection<DataElement> DataElements { get; set; } 

    [NotMapped] 
    public ICollection<DataElement> RecentDataElements //returns the last 15 data elements 
    { 
     get 
     { 
      return DataElements.OrderByDescending(de => de.GeneratedDateTime).Take(15).Reverse().ToList(); 
     } 
    } 

    [NotMapped] 
    public DataElement LatestDataElement //returns the latest data element (if any) 
    { 
     return DataElements.OrderByDescending(de => de.GeneratedDateTime).FirstOrDefault(); 
    } 

所以我有上面的代碼的問題是,當我打電話LatestDataElement或RecentDataElements,我最終等了很多。

我相信這是因爲DataGroup類中的DataElements屬性是ICollection,RecentDataElements和LatestDataElement最終導致EF在排序和返回子集之前將所有DataElement加載到內存中(可能有數千個DataElements一個DataGroup)。

有沒有辦法讓這個更高效?

我玩過了直接查詢datacontext的想法,而不是使用DataElements屬性,但我想看看是否有其他選項我應該考慮。有同事告訴我,把數據上下文放在模型中是不好的做法(不管它們是對還是錯都是不同的問題)。

感謝您的幫助和建議。非常感謝:)

回答

1

總之:沒有

由於NotMapped屬性的名稱已經表明,這是一個屬性,linq-to-entities沒有任何知識,並且不可能通過對數據庫進行過濾來填充它。我會做什麼在你的地方是移除模型中的Notmapped特性一起,並創建一個視圖模型:

public class DataGroupViewModel 
{ 
    public DataGroup DataGroup {get; set;} 

    public ICollection<DataGroup> RecentDataElements {get; set;} 
} 

並使用投影在你的查詢來填充這個觀點:

var result = ctx.DataGroups.Where(...).Select(d => new DataGroupViewModel 
{ 
    DataGroup = d; 
    RecentDataElements = d.DataElements.OrderByDescending(de => de.GeneratedDateTime) 
     .FirstOrDefault(); 
} 

這當然迫使你創建另一個模型,但它是最乾淨和最快速的方法。同樣你的同事是對的,它在你的模型中做數據庫調用的一種不好的方式,模型是數據的容器,無非就是,它不應該有用於查詢數據庫的邏輯。

爲了使它有點清潔,你可以寫一些擴展方法,你可以重複使用,以獲得型號:

Func<IQueryable<DataGroup>,IEnumerable<DataGroupViewModel>> GetDataGroupDTO = 
    d => d.Select(dt => new DataGroupViewModel 
    { 
     DataGroup = dt; 
     RecentDataElements = dt.DataElements.OrderByDescending(de => de.GeneratedDateTime) 
     .FirstOrDefault(); 
    } 

然後,你可以寫你的查詢更乾淨:

IEnumerable<DataGroupViewModel> result = ctx.DataGroups.Where(...).GetDataGroupDTO();