实体框架包含条件

时间:2011-07-14 21:47:29

标签: entity-framework include conditional

我需要根据ID和未完成的签到来过滤经销商

最初,它仅基于id:

返回经销商
    // TODO: limit checkins to those that are not complete
    return this.ObjectContext.Dealers
        .Include("Groups")
        .Include("Groups.Items")
        .Include("Groups.Items.Observations")
        .Include("Groups.Items.Recommendations")
        .Include("Checkins")
        .Include("Checkins.Inspections")
        .Include("Checkins.Inspections.InspectionItems")
        .Where(d => d.DealerId == id)
        .FirstOrDefault();

正如您所看到的,要求是限制签到。 这是我做的:

var query = from d in this.ObjectContext.Dealers
                            .Include("Groups")
                            .Include("Groups.Items")
                            .Include("Groups.Items.Observations")
                            .Include("Groups.Items.Recommendations")
                            .Include("Checkins.Inspections")
                            .Include("Checkins.Inspections.InspectionItems")
                            .Where(d => d.DealerId == id)
                        select new
                        {
                            Dealer = d,
                            Groups = from g in d.Groups
                                     select new
                                     {
                                         Items = from i in g.Items
                                                 select new
                                                 {
                                                     Group = i.Group,
                                                     Observations = i.Observations,
                                                     Recommendations = i.Recommendations
                                                 }
                                     },
                            Checkins = from c in d.Checkins
                                       where c.Complete == true
                                       select new
                                       {
                                           Inspections = from i in c.Inspections
                                                         select new
                                                         {
                                                             InspectionItems = i.InspectionItems
                                                         }
                                       }

                        };

            var dealer = query.ToArray().Select(o => o.Dealer).First();

            return dealer;

有效。 但是,我不相信我做的是正确的事情。

完成我所做的最好的方法是什么?存储过程可能吗?

我不确定我是否必须再使用Include子句

谢谢。

4 个答案:

答案 0 :(得分:3)

如果要使用单个查询加载过滤后的关系,您确实必须执行此类投影,但不需要对Include进行调用。一旦您构建投影,包括不使用 - 您已经在您的控制下返回了数据。

只有当您回归到普通ADO.NET时,存储过程才会有所帮助,因为通过Entity框架执行的存储过程无法填充相关实体(只有扁平化结构)。

@Andreas提到的自动fixupu需要多个数据库查询,因为我知道它只有在禁用延迟加载时才有效,因为代理对象在某种程度上没有关于fixup的信息,并且它仍然有每个关系的内部标志,因为没有加载当您第一次访问它们时,它们仍会执行其他查询。

答案 1 :(得分:2)

也许您可以使用EF ObjectContexts中的关系修复机制。当您在实体的相同上下文中执行多个查询时,这些查询通过关联相关联,这些查询将被解析。 假设经销商和Checkins之间的关联是1:n,每边都有导航属性,你可以这样做:

var dealer = yourContext.Dealers
             .Where(p => p.DealerId == id)
             .FirstOrDefault();
if(dealer != null)
{
    yourContext.Checkins
           .Where(c => c.Complete && c.DealerId == dealer.DealerId)
           .ToList();

我现在还没有对此进行过测试,但由于EF识别出Checkins,它会通过第二个查询从第一个查询中插入属于经销商的上下文,创建相应的引用。

答案 2 :(得分:0)

@Andreas H:

太棒了,非常感谢你。

我必须像这样调整你的建议并且有效:

var dealer = this.ObjectContext.Dealers
                    .Include("Groups")
                    .Include("Groups.Items")
                    .Include("Groups.Items.Observations")
                    .Include("Groups.Items.Recommendations")
                    .Where(p => p.DealerId == id).
                    FirstOrDefault();
        if (dealer != null)
        {
            this.ObjectContext.Checkins
                    .Include("Inspections")
                    .Include("Inspections.InspectionItems")
                   .Where(c => !c.Complete && c.Dealer.DealerId == dealer.DealerId)
                   .ToList();
        }
        return dealer;

我仍然必须使用Include,否则它不会返回引用的实体。

另请注意,Dealer.Groups与Dealer.Checkins无关。

因此,如果没有满足条件的签到,则仍需要返回组。

值得注意的是,首先,我将两张包含在支票上的商品

var dealer = this.ObjectContext.Dealers
                        .Include("Groups")
                        .Include("Groups.Items")
                        .Include("Groups.Items.Observations")
                        .Include("Groups.Items.Recommendations")
                        .Include("Checkins.Inspections")
                        .Include("Checkins.Inspections.InspectionItems")
                        .Where(p => p.DealerId == id).
                        FirstOrDefault();
            if (dealer != null)
            {
                this.ObjectContext.Checkins
                        .Where(c => c.Complete && c.DealerId == id)
                       .ToList();
            }
            return dealer;

但它返回了所有Checkins,包括那些不完整的。

我不明白为什么后者不起作用但前者不起作用,如何解析实体。我不知何故可以直觉说前者返回所有数据。

答案 3 :(得分:0)

您接受的解决方案将生成多个数据库查询。正如Ladislav Mrnka所说,投影是通过一个查询得出结果的唯一方法。你的代码的维护确实很难。也许您可以使用IQueryable-Extension来动态构建投影并保持代码清洁:

var query = this.ObjectContext.Dealers.SelectIncluding( new List<Expression<Func<T,object>>>>(){

    x => x.Groups,
    x => x.Groups.Select(y => y.Items),
    x => x.Groups.Select(y => y.Items.Select(z => z.Observations)),
    x => x.Groups.Select(y => y.Items.Select(z => z.Recommendations)),
    x => x.Checkins.Where(y => y.Complete==true),
    x => x.Checkins.Select(y => y.Inspections),
    x => x.Checkins.Select(y => y.Inspections.Select(z => z.InspectionItems))

});
var dealer = query.First();
return dealer;

您可以在github上的thiscode/DynamicSelectExtensions找到扩展程序