如何在实体框架中查询相关实体(1:N关系)

时间:2011-03-29 21:36:14

标签: .net entity-framework entity-framework-4 entity-relationship foreign-key-relationship

在方案like this: {class diagram here}中获取相关实体的更好方法是什么? 我写了两种方法(请注意类图中的差异)...项目具有ICollection of Tasks的属性,但成员没有。两种方式都有效,我想知道哪一种方法是正确的(更好/更快)。或者,如果没有一个是好的,那么这些简单场景中的正确方法是什么? 代码:

    using (var db = new EntitiesContext())
        {
            // way A
            Project project = db.Projects.Include("Tasks").First();
            List<Task> projectTasks = project.Tasks.ToList();
            count = projectTasks.Count;

            // way B
            Member member = db.Members.First();
            IQueryable<Task> memberTasks = from t in db.Tasks
                                           where t.AssignedTo.Id == member.Id
                                           select t;
            count = memberTasks.Count();
        }

我正在使用EF 4.1 Code First 顺便说一句:不要太担心结果(得数)。这只是一段测试代码,我当然希望将来查询更多有用的信息。

5 个答案:

答案 0 :(得分:2)

执行这些查询时,您的性能瓶颈通常属于以下两种类别之一:

  1. 获取您不需要的太多数据。
  2. 过多地往返数据库。
  3. 你的第一个例子可能受到第一个例子的影响。如果查看从数据库返回的数据,将为与其连接的每个任务重复项目的所有数据。如果您的项目有大量与之关联的数据,则可能会导致大量开销。如果它相当瘦,那就不会花费更多。

    您的第二个示例创建了第二次往返以完成任务。额外的往返会带来额外的开销,但这意味着总体上会返回较少的重复数据。一次额外的往返可能不是什么大问题,但如果你在多个项目中这样做,你可能很容易就会结束几十次不必要的往返。

    因此,根据您的数据通常看起来是什么以及您真正想从中获得什么,决定走哪条路将真正成为一种平衡行为。在这种特殊情况下,你最好还是选择:

    count = db.Tasks.Count(t => t.AssignedTo.Id == db.Members.FirstOrDefault().Id)
    

    ...这将创建一个只返回计数的单个优化查询,没有多余的数据或额外的往返。因此,您可以看到这样的问题的答案将如何真正取决于您试图从数据库中获取的内容。

    回应评论

    如果您尝试获取与某些内容相关的所有任务,那么您的查询应该只是获取任务。有很多方法可以做到这一点:

    var memberTasks = db.Tasks.Where(t => t.AssignedTo.Id == memberId).ToList();
    

    或(如果您还不知道会员的身份证):

    var memberTasks = db.Tasks.Where(t => t.AssignedTo.[your criterion]))
                          .ToList();
    

    或(如果您想同时为多个成员执行任务):

    var tasksByMemberId = (from t in db.Tasks
                           where t.AssignedTo.[your criterion])
                           select new {MemberId = t.AssignedTo.Id, t})
                          .ToLookup(e => e.MemberId, e => e.t);
    

    我可以继续。关键是所有这些查询都专门解决了这些问题,而不必担心会员的数据。

    添加额外的数据层不应该改变很多事情:

    var projectTasks = db.Tasks.Where(t => t.Iteration.Project.Id == projectId).ToList();
    

答案 1 :(得分:1)

方法A更清晰,可以同时优化SQL查询,提取相关数据。方法B类似于在需要时延迟加载相关数据。

当我现在需要数据时,我更喜欢A,而当我甚至无法访问相关数据时,我更喜欢B,除非用户在程序中执行某些操作。

答案 2 :(得分:1)

我认为这两个都无法比较,因为这两个例子都有它们的用法。如果您有导航属性,第一个肯定是要走的路,因为在这种情况下,您将在一次往返中将所有数据返回到数据库。如果您没有可用的导航属性,则第二种方法很有用。

答案 3 :(得分:1)

  

两种方式都有效,我想   要知道,哪一个是正确的   (更好/更快)。

一般使用Linq to Entities导航属性是可行的方法 - 数据会自动加入(如果您使用Include)。

您的第一个查询未针对当前获取计数进行优化,您只需编写:

count = db.Projects.Include("Tasks").First().Tasks.Count();

否则,您将从数据库中加载所有相关的任务实体。

答案 4 :(得分:0)

你为什么不用这个:

project.Tasks.Load();