2

遇到问题,希望有人可以提供帮助。

这是我在现实世界中的例子。我有 4 个表格:
Person
Plan
Coverage 和 CoveredMembers

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

我需要一个查询,它将对 Plan.PlanType == 1 和 CoveredMembers.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 

在 EF (4.0 vs 2010) 我已经做到了

var Q from p in context.Persons
join pp in context.Plans
on p.PersonID  equals pp.PersonD
join c in context.Coverages
on pp.PlanID equals c.PlanID 
join cm in context.CoveredMember
on c.CoverageID equals cm.CoverageID
where cm.TermDate == null && pp.PlanType = 1 && 
pp.ActiveFlag == true 
select p;

然后

var people = Q.Include(people => 
people.Plans.Select(plans => plans.Coverages.Select(cc =>  cc.CoveragedMembers)))
.ToList ();

如果我在 var people = Q 行上设置断点并执行

((System.Data.Objects.ObjectQuery)Q).ToTraceString();

在使用 ToList() 将查询实际发送到数据库之前(在包含语句之前),我接受该查询并取回我应该取回的确切记录数量。

然后我运行一个 sql 跟踪(在 SQL Profiler 中)并将查询发送到数据库(包含语句)。我看到发送到数据库的 sql 语句已经失去了所有的过滤。它基本上返回相同的人,但子对象上的过滤器消失了,正在返回这些人的所有数据。(缺少 plan.PlanType = 1 和coveredMember.TermDate = null)

也许这不是实现这一目标的方法?有人有什么想法吗?EF甚至可以吗?这是一个非常简单的 SQL 语句(尽管跨越 4 个表),所以我认为这应该不是什么大问题,尽管我确定我没有正确地做某事

4

2 回答 2

1

我认为这是Include. Include将s 直接放在它们适用的实体后面或多或少是常见的。我将向您展示我的意思,同时使用导航属性重写您的查询:

var q = from p in context.Persons
                         .Include(people => people.Plans
                         .Select(plans => plans.Coverages
                         .Select(cc =>  cc.CoveragedMembers)))
        from pp in p.Plans
        from c in pp.Coverages
        from cm in c.CoveragedMembers
        where cm.TermDate == null && pp.PlanType = 1 && pp.ActiveFlag
        select p;

(使用导航属性本质上并没有改变任何东西,但它让生活变得更轻松)。我已经看到放在 linq 语句末尾的包含被解释为外部连接,但同样包含在内部连接的开头。

Include我可能会补充一点,如果可以事先决定您需要哪些数据,并将 ( select) 投射到(命名或匿名)类型中,那么您根本不需要s,即类似

select new { Person = p, Plan = pp, CoveredMember = cm }

而不是select p. 更好的是,选择特定的属性:

select new { Person = p.Name, Plan = pp.Plan, CoveredMember = cm.Name }

您将大大减少您获取的数据量。Includes有办法在宽度和长度上放大查询结果。

于 2013-01-26T21:31:01.540 回答
0

cannot use filtering with Eager loading (Include)

所以你可以做下面的事情(这是一个示例代码)

public Company Get(int id)
{
    var query = from c in
                    (from co in db.Companies
                        where co.Id == id
                        select new
                        {
                            Company = co,
                            CompanyPerson = from person in co.Persons
                                            where person.IsActive && !person.IsDeleted
                                            select person
                        })
                select c;

    //Create my company object
    Company company = new Company();
    foreach (var item in query)
    {
        company = item.Company;

        //Add persons to my company object
        foreach (var companyPerson in item.CompanyPerson)
        {
            company.Persons.Add(companyPerson);
        }
    }
    return company;
}

有关更多信息,请查看这篇文章Eager Loading (include) with filter in Entity Framework

我希望这对你有帮助。

于 2013-01-26T16:44:02.807 回答