考虑遵循LINQ查询:
var item = (from obj in _db.SampleEntity.Include(s => s.NavProp1)
select new
{
ItemProp1 = obj,
ItemProp2 = obj.NavProp2.Any(n => n.Active)
}).SingleOrDefault();
此操作按预期运行,但item.ItemProp1.NavProp1
NULL 。
正如它解释here这是因为查询在使用Include()
后实际发生了变化。但问题是这种情况的解决方案是什么?
当我像这样更改查询时,每件事都可以正常工作:
var item = (from obj in _db.SampleEntity.Include(s => s.NavProp1)
select obj).SingleOrDefault();
关于this article我想问题是什么......但作者提供的解决方案在我的情况下不起作用(因为在最终选择中使用匿名类型而不是实体类型)。
答案 0 :(得分:48)
正如您所提到的,Include
仅在查询的最终结果包含应包含Include
- d导航属性的实体时才有效。
所以在这种情况下Include
有效:
var list = _db.SampleEntity.Include(s => s.NavProp1).ToList();
SQL查询将包含JOIN
,每个SampleEntity
都会加载NavProp1
。
在这种情况下,它具有 no 效果:
var list = _db.SampleEntity.Include(s => s.NavProp1)
.Select(s => new { s })
.ToList();
SQL查询甚至不包含JOIN
,EF完全忽略Include
。
如果在后一个查询中您希望SampleEntity
包含他们的NavProp1
,您可以这样做:
var list = _db.SampleEntity
.Select(s => new { s, s.NavProp1 })
.ToList();
现在,Entity Framework已分别从数据库中提取SampleEntity
和NavProp1
个实体,但它通过名为 relationship fixup 的进程将它们粘合在一起。如您所见,Include
没有必要实现这一目标。
但是,如果Navprop1
是一个集合,您会注意到......
var navprop1 = list.First().s.Navprop1;
...仍将通过延迟加载执行查询以获取Navprop1
。那是为什么?
虽然关系修正确实会填充Navprop1
属性,但它并不会将其标记为已加载。只有在Include
加载属性时才会发生这种情况。现在我们SampleEntity
已经拥有了Navprop1
个,但是您无法在不触发延迟加载的情况下访问它们。你唯一能做的就是
_db.Configuration.LazyLoadingEnabled = false;
var navprop1 = list.First().s.Navprop1;
(或通过禁用代理创建或不使Navprop1
虚拟来阻止延迟加载。)
现在,您将在没有新查询的情况下获得Navprop1
。
对于参考导航属性,这不适用,延迟加载在启用时不会被触发。
在实体框架核心中,这方面的情况发生了巨大变化。像_db.SampleEntity.Include(s => s.NavProp1).Select(s => new { s })
这样的查询现在会在最终结果中包含NavProp1
。 EF-core在寻找" Includable"实体到底是什么结果。因此,为了填充导航属性,我们不会感觉像Select(s => new { s, s.NavProp1 })
这样的查询。但请注意, if 如果我们使用 { Include
这样的查询,则在访问s.NavProp1
时仍会触发延迟加载。
答案 1 :(得分:1)
我知道这可能会有一些笑声,但不要忘记像我刚才那样的明显。数据库中的行实际上没有外键引用!在考虑EF Include还没有工作之前,我应该先检查一下大坝数据!哎呀。我生命中的30分钟我没有回来。
答案 2 :(得分:0)
如果您的模型定义正确,它应该没有任何问题。
using System.Data.Entity;
var item = _db.SampleEntity
.Include(p => p.NavigationProperty)
.Select(p => new YourModel{
PropertyOne = p.Something,
PropertyTwo = p.NavigationProperty.Any(x => x.Active)
})
.SingleOrDefault(p => p.Something == true);
答案 3 :(得分:0)
您是如何发现item.ItemProp1.NavProp1
为空的。当您尝试访问时,EF使用代理加载所有必需的属性。
怎么样?
var item = (from obj in _db.SampleEntity.Include(s => s.NavProp1)
select obj).SingleOrDefault();
Assert.IsNotNull(obj.NavProp1);
Assert.IsNotNull(obj.NavProp2);
您也可以尝试使用
var item = (from obj in _db.SampleEntity.Include(s => s.NavProp1)
select new
{
ItemProp1 = obj,
NavProp1 = obj.NavProp1,
ItemProp2 = obj.NavProp2.Any(n => n.Active)
}).SingleOrDefault();
Assert.IsNotNull(item.NavProp1)
当然我假设您对EF导航属性映射没有任何问题。