2011-07-25 43 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