Entity Framework Include() 在复杂查询中不起作用
Entity Framework Include() is not working within complex query
考虑以下 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 我猜是什么问题...但是作者提供的解决方案在我的情况下不起作用(因为在最后使用 anonymous type select 而不是 实体类型 ).
如果您的模型定义正确,它应该可以正常工作。
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);
你怎么发现 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 导航 属性 映射没有任何问题。
如您所述,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 已经分别从数据库中获取了 SampleEntity
和 NavProp1
实体,但是它通过一个名为 relationship fixup[=74 的过程将它们粘合在一起=].如您所见,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 在最终结果中寻找 "Includable" 个实体时更加智能。因此,我们不会倾向于像 Select(s => new { s, s.NavProp1 })
这样的查询来填充导航 属性。但是请注意,如果我们使用这样的查询而没有Include
,当s.NavProp1
时仍然会触发延迟加载已访问。
我知道这可能会引起一些笑声,但不要像我刚才那样忘记显而易见的事情。数据库中的行实际上没有外键引用!在认为 EF Include 不起作用之前,我应该先检查大坝数据!哎呀。我生命中的 30 分钟我不会回来。
考虑以下 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 我猜是什么问题...但是作者提供的解决方案在我的情况下不起作用(因为在最后使用 anonymous type select 而不是 实体类型 ).
如果您的模型定义正确,它应该可以正常工作。
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);
你怎么发现 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 导航 属性 映射没有任何问题。
如您所述,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 已经分别从数据库中获取了 SampleEntity
和 NavProp1
实体,但是它通过一个名为 relationship fixup[=74 的过程将它们粘合在一起=].如您所见,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 在最终结果中寻找 "Includable" 个实体时更加智能。因此,我们不会倾向于像 Select(s => new { s, s.NavProp1 })
这样的查询来填充导航 属性。但是请注意,如果我们使用这样的查询而没有Include
,当s.NavProp1
时仍然会触发延迟加载已访问。
我知道这可能会引起一些笑声,但不要像我刚才那样忘记显而易见的事情。数据库中的行实际上没有外键引用!在认为 EF Include 不起作用之前,我应该先检查大坝数据!哎呀。我生命中的 30 分钟我不会回来。