2

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

例如:

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.
4

1 回答 1

2

编辑:

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

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

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

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

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

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

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

高温高压


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

在回答您的问题时,是的,这是预期的行为,原因如下:

为什么你写一个查询它被翻译成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 提供了几种机制来指定结果集中返回的内容。一是延迟加载(如果您想避免性能问题,需要小心使用),二是包含语法。这些方法限制了我们撤回的内容,以便查询快速且不消耗不需要的资源。

例如,在上面你会注意到只返回 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

于 2012-11-27T07:23:21.023 回答