2011-07-25 70 views
3

我們對數據訪問使用Entity Framework 4.1,並在構建對象時,我們開始向自己提問 有關應用程序與數據庫的關聯程度。現在,我們真的開始考慮一個項目下面是:我是否懶惰加載這些屬性?

public MasterPreAward() 
{ 
    public int ID 
    public int MemberID 
    public int CycleID 

    public virtual Cycle 
    public virtual Member 
    public virtual Status 
    public virtual ICollection<DataTracking> DataTrackings 
    public virtual ICollection<ReviewerAssignment> Reviewers 
} 

的MasterPreAward是從數據庫中生成的實體,具有周期的導航性質在會員,有兩個集合的DataTrackings 審稿沿狀態。我們想知道的是,實體框架是如何根據這些項目加載子對象並將我們在以下模型中使用的數據帶回來的? 如您所見,我們傳入MasterPreAward對象,然後訪問基於MasterPreAward加載的兒童屬性。

public ViewHeaderSummary(MasterPreAward masterPreAward) 
{ 
    MasterPreAwardId = masterPreAward.ID; 
    ClientId = masterPreAward.Cycle.Project.Program.ClientID; 
    ApplicationId = masterPreAward.MemberID; 
    ProgramId = masterPreAward.Cycle.Project.ProgramID; 
    ProjectId = masterPreAward.Cycle.ProjectID; 
    EventTypeId = masterPreAward.DataTrackings.FirstOrDefault(x=>x.Finished==true 
         && x.EventTypeID==(int)FormEvents.Application).EventTypeID; 
    CycleId = masterPreAward.CycleID; 
    FormId = masterPreAward.Cycle.CycleForms.FirstOrDefault().FormID; 
} 

,我們想知道什麼,這是爲了訪問這些屬性的最好辦法,還是應該真正思考以不同的方式做這方面的工作?

回答

2

你似乎不是查詢完整的實體,而只是針對一堆標量值。在我看來,這將是它收集在一個數據庫往返所需的所有值的投射一個很好的候選人:

var result = dbContext.MasterPreAwards 
     .Where(m => m.ID == masterPreAward.ID) 
     .Select(m => new 
     { 
      ClientId = m.Cycle.Project.Program.ClientID, 
      ProgramId = m.Cycle.Project.ProgramID, 
      ProjectId = m.Cycle.ProjectID, 
      EventTypeId = m.DataTrackings.Where(d => d.Finished 
       && x.EventTypeID==(int)FormEvents.Application) 
       .Select(d => d.EventTypeID).FirstOrDefault(), 
      FormId = m.Cycle.CycleForms.Select(c => c.FormID).FirstOrDefault() 
     }) 
     .Single(); 

    MasterPreAwardId = masterPreAward.ID; 
    ClientId = result.ClientID; 
    ApplicationId = masterPreAward.MemberID; 
    ProgramId = result.ProgramID; 
    ProjectId = result.ProjectID; 
    EventTypeId = result.EventTypeId; 
    CycleId = masterPreAward.CycleID; 
    FormId = result.FormID; 

正如你所看到的,你需要的DbContext運行這樣的查詢。

你原來的方式懶洋洋地加載所有相關實體將導致5個數據庫查詢,據我可以看到(用於CycleProjectProgramDataTrackingsCycleForms)。最糟糕的是對DataTrackings.FirstOrDefaultCycleForms.FirstOrDefault的查詢,它實際上首先將數據庫中的完整集合加載到內存中,然後在加載的集合的內存中執行FirstOrDefault,以僅返回一個單一元素,然後您只使用一個單一屬性。

編輯:查詢的ApplicationIdCycleId沒有必要的,代碼修改。)

+0

感謝您的代碼示例。當我們構建模型或存儲庫時,這給了我們更多的想法。 – Chris

3

我相信默認設置是延遲加載每個嵌套的集合獨立,這可能會導致大量的數據庫流量。

驗證生成的SQL的最佳方法是啓動SQL事件探查器並確認查詢的數量。

您可以通過調用.Include方法強制EF迫切加載相關實體。有關更多詳情,請參閱here

+0

感謝您的EF博客鏈接。但我認爲我們真正想要做的是避免事物的急切加載,並且只在需要時拉動我們需要的東西。 – Chris