【问题标题】:entity framework 4.0 multiple joins实体框架 4.0 多连接
【发布时间】:2013-01-26 06:05:33
【问题描述】:

这是我在现实世界中的例子。 我有 4 张桌子:

  • 计划
  • 覆盖范围
  • CoveredMembers

每个人可以有多个计划,每个计划都可以有多个承保范围。这些覆盖范围中的每一个都可以有许多 CoveredMember。

我需要一个对Plan.PlanType == 1CoveredMembers.TermDate == null 应用过滤器的查询。 此查询应带回任何拥有未终止医疗类型计划的人。

这条 SQL 语句可以做到这一点:

SELECT Person.*, Plans.*, Coverages.*, CoveredMembers.* 
FROM Person P 
INNER JOIN Plan PL ON P.PersonID = PL.PersonID 
INNER JOIN Coverage C on PL.PlanID = C.PlanID 
INNER JOIN CoveredMember CM on C.CoverageID = CM.CoverageID 
WHERE CM.TermDate = NULL AND PL.PlanType = 1

我已经知道如何使用匿名类型来做到这一点,但有时我需要更新数据并保存回数据库 - 并且匿名类型是只读的。

我得到了一个使用 JOIN 确实有效的解决方案,但它只带回了人员(尽管过滤了我需要的方式)。然后我可以遍历每个人:

foreach (var person in persons) {
  foreach (var plan in person.Plans{
    //do stuff 
  }
}

但这不会为循环的每次迭代都进行一次数据库调用吗?我有 500 人,每人有 3 个未终止的医疗计划,所以它会调用 db 1500 次?

这就是为什么我想一次性将整个数据树从 Persons 带回 CoveredMembers。这不可能吗?

【问题讨论】:

    标签: entity-framework entity-framework-4


    【解决方案1】:

    我相信这是分两部分完成的:

    1. 根据您之前在此问题中讨论的条件确定您希望返回的人的查询:Entity framework. Need help filtering results

    2. 正确设置您希望集中加载的实体的导航属性:http://msdn.microsoft.com/en-us/data/jj574232.aspx

    例如,如果您的 Person 实体如下所示:

    public class Person {
       public List<Plan> Plans {get; set;}
       ...
    }
    

    当从 dbcontext 返回数据时,您还可以使用带有 include 选项的显式预加载:

     var people = context.People
             .Include(p => p.Plans)
             .ToList();
    ....
    

    如果这些是嵌套的 - 覆盖是计划的一部分,等等(看起来像,它是这样的):

     var people = context.People
             .Include(p => p.Plans.Select(pl=>pl.Coverage).Select(c=>c.CoveredMembers)))
             .ToList();
    ....
    

    我在这里对你的数据模型做了一些假设,我上面的代码可能需要稍微调整一下。

    编辑

    我可能需要其他人在这里权衡,但我认为您不能将 where 子句添加到这样的包含中(我上面的示例通过将包含放在上下文对象上来引导您,而不是返回一个 IQueryable,条件设置为在您的第一篇文章中已解决(没有调用 ToList()),然后使用您在上面编写的不带 Where 子句的代码:

    从第一篇文章开始(您在这篇文章中提供了不同的标准,但概念相同)

     var q = from q1 in dbContext.Parent
        join q2 in dbContext.Children
        on q1.key equals q2.fkey
        join q3 in  ........
        where q4.col1 == 3000
        select q1;
    

    然后:

    List<Person> people = q.Include(p => p.Plans
      .Select(pl => pl.Coverages)
      .Select(c => c.CoveredMembers).ToList();
    

    再一次,在无法排除故障的情况下这样做 - 我相信我也需要尝试几次才能解决这个问题。

    【讨论】:

    • 感谢您的帮助。我认为这非常接近。我可以使用包含进行急切加载,但是当我尝试添加过滤器时它会出错,这很可能导致我对语法不太擅长,所以我确定我只是做错了。我对 EF 还是很陌生,所以请原谅我。这就是我得到的。你能指出我做错了什么吗? 'var people = context.Persons .Include(p => p.Plans.Where(pl => pl.PlanTypeID==1).Select(pl => pl.Coverages.Select(c => c.CoveredMembers.Where ( cm => cm.TerminationDate == null))));'
    • 对不起,这个网站的新手不知道如何在这里很好地格式化代码:(
    • 我认为它已经非常接近了,只是它没有带回正确数量的结果。我有一个查询,我知道肯定是正确的,它带来了 5004 个结果。当我在 EF 中执行此操作时,它只会带回 1314 个结果。我正在查看生成的 sql,它的方式比它需要的更复杂,但 where 子句似乎是正确的。
    • 此时,如果它以您希望的方式(即急切加载)返回结果,则很难确定查询的不同之处。您可以发布您现在使用的实际(当前)SQL 和完整的 linq 查询吗?当我遇到这个问题时(我有:)我通常会简化两个查询并确保我得到相同的数据,然后添加连接等等,直到我确定分歧点。
    • 我在连接中有一个列错误。当我纠正它时,它现在带回了 8800 行。这次太多了。我确实将您的答案标记为正确,因为我很确定它可以正常工作,只是不确定为什么 sql 没有返回正确的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    相关资源
    最近更新 更多