实体框架Include()在复杂查询中不起作用

时间:2015-01-20 21:19:14

标签: c# linq entity-framework

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

4 个答案:

答案 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已分别从数据库中提取SampleEntityNavProp1个实体,但它通过名为 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导航属性映射没有任何问题。