考虑以下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,我想是什么问题...但是作者提供的解决方案在我的情况下不起作用(因为在最终选择中使用匿名类型而不是实体类型)。

最佳答案

如您所述,Include仅在查询的最终结果由应包含Include -d导航属性的实体组成时才有效。

因此,在这种情况下,Include具有作用:

var list = _db.SampleEntity.Include(s => s.NavProp1).ToList();

SQL查询将包含一个JOIN,并且每个SampleEntity都将加载其NavProp1

在这种情况下,它无效:
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已经从数据库中分别获取了SampleEntityNavProp1实体,但是它通过称为关系修复的过程将它们粘合在一起。如您所见,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

对于引用导航属性,此功能不适用,启用时不会触发延迟加载。

Entity Framework核心中,该区域的情况已经发生了巨大变化。像_db.SampleEntity.Include(s => s.NavProp1).Select(s => new { s })这样的查询现在将在最终结果中包括NavProp1。 EF-core在最终结果中寻找“包含”实体方面更为明智。因此,我们不会倾向于像Select(s => new { s, s.NavProp1 })这样的查询来填充导航属性。但是请注意,如果我们使用不带Include的查询,则当访问s.NavProp1时仍会触发延迟加载。

09-07 01:29