实体框架5(代码优先)导航属性

时间:2012-11-27 00:50:49

标签: c# entity-framework entity-framework-5

在查询/过滤之前,为导航属性加载具有给定外键的所有项是实体框架的正确行为吗?

例如:

myUser.Apples.First(a => a.Id == 1 && !a.Expires.HasValue);

将加载与该用户关联的所有苹果。 (SQL查询不查询ID或Expires字段。)

还有另外两种方法(生成正确的SQL)但不像使用导航属性一样干净:

myDbContext.Entry(myUser).Collection(u => u.Apples).Query().First(a => a.Id == 1 && !a.Expires.HasValue);

myDbContext.Apples.First(a => a.UserId == myUser.Id && a.Id == 1 && !a.Expires.HasValue);

我查过的东西

  • 已启用延迟加载,并且未在任何位置禁用。
  • 导航属性为virtual

1 个答案:

答案 0 :(得分:2)

修改

根据您的编辑,我认为我对您的要求有错误的想法(现在更有意义)。我会留下前面的答案,因为我认为它可能对解释有用,但与你的具体问题的相关性要低得多。

根据您发布的内容,您的用户对象已启用延迟加载。 EF默认启用延迟加载,但延迟加载有一个要求,即将导航属性标记为虚拟(已完成)。

延迟加载通过附加到导航属性上的get方法并在该点执行SQL查询来检索外部实体。导航属性也不是可查询集合,这意味着当您执行get方法时,您的查询将立即执行。

在上面的示例中,在执行.first调用之前枚举User上的apples集合(使用普通的旧linq到对象)。这意味着SQL将返回与用户关联的所有苹果,并在查询计算机的内存中过滤它们(如您所见)。这也意味着你需要两个查询来拉下你感兴趣的苹果(一个用于用户,一个用于导航属性),如果你想要的只是苹果,这可能对你没有效率。

这样做的一个更好的方法是尽可能长时间地将整个表达式作为查询。这方面的一个例子如下:

myDbContext.Users
   .Where(u=>u.Id == userId)
   .SelectMany(u=>u.Apples)
   .Where(a=>a.Id == 1 && !a.Expires.HasValue);

这应该作为单个SQL语句执行,并且只下拉你关心的苹果。

HTH


根据我对您的问题的理解,您会问为什么EF似乎允许您在查询中使用导航属性,即使它们在结果集中可能为null。

在回答你的问题时,这是预期的行为,这就是为什么:

为什么要编写一个将其翻译成SQL的查询,例如

myDbContext.Apples.Where(a=>a.IsRed)

会变成类似

的东西
Select * from Apples
where [IsRed] = 1

同样类似下面的内容也将直接翻译成SQL

myDbContext.Apples.Where(a=>a.Tree.Height > 100)

会变成类似

的东西
Select a.* from Apples as a
inner join Tree as t on a.TreeId = t.Id
where t.Height > 100

然而,当我们实际下拉结果集时,它有点不同。

为避免过多地删除数据并使其变慢,EF提供了几种机制来指定结果集中的内容。一个是延迟加载(如果你想避免性能问题,则需要小心使用),第二个是include语法。这些方法限制了我们撤回的内容,因此查询很快并且不会消耗不需要的资源。

例如,在上文中,您将注意到只返回Apple字段。

如果我们要在下面添加一个包含,您可能会得到不同的结果:

myDbContext.Apples.Include(a=>a.Tree).Where(a=>a.Tree.Height > 100)

将转换为SQL类似于:

Select a.*, t.* from Apples as a
inner join Tree as t on a.TreeId = t.Id
where t.Height > 100

在上面的例子中(我很确定在语法上不正确,因为myContext.Users应该是一个集合,因此不应该有.Apples)你正在创建一个查询,因为所有变量都可用。当您枚举该查询时,您必须明确说明返回的内容。

有关导航属性及其工作原理(以及.Include语法)的详细信息,请查看我的博客:http://blog.staticvoid.co.nz/2012/07/entity-framework-navigation-property.html