我需要根据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子句
谢谢。
答案 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找到扩展程序