【问题标题】:Does AsQueryable() on ICollection really makes lazy execution?ICollection 上的 AsQueryable() 真的会延迟执行吗?
【发布时间】:2012-02-29 18:09:47
【问题描述】:

我正在使用实体框架 CodeFirst,其中我使用 ICollection 作为父子关系

public class Person
{
   public string UserName { get;set}
   public ICollection<Blog> Blogs { get; set;}
}

public class Blog
{
   public int id { get; set; }
   public string Subject { get; set; }
   public string Body { get; set; }
}

好的,到目前为止一切正常,但我担心的是,每当我想获得一个人的博客时,我都会得到它

var thePerson = _context.Persons.Where(x => x.UserName = 'xxx').SingleOrDefault();
var theBlogs = thePerson.Blogs.OrderBy(id).Take(5);

现在,我了解到,当执行该行时,该人的所有博客都会加载到内存中,然后从内存中进行排序和选择。这对于拥有大量博客的人的记录来说并不理想。我想将博客子设置为 IQueryable,以便在拉入内存之前在 SQL 数据库中完成排序和选择。

我知道我可以在我的上下文中将博客声明为 IQueryable,以便我可以直接查询为

var theBlogs = _context.Blogs.Where(.....)

但由于设计选择,这对我来说是不可行的,由于序列化问题,我想尽可能避免任何循环引用。所以,我没有对我孩子的父实体进行任何引用。

我发现,我可以在博客上调用 AsQueryable() 方法

var theBlogs = thePerson.Blogs.AsQueryable().OrderBy(id).Take(5);

这对我来说似乎是一种魔法,而且好得令人难以置信。所以我的问题。这个 AsQueryable 是否真的使 ICollection 在现实中成为 IQueryable 并在 SQL Server 中进行所有查询过程(延迟加载),或者它只是像以前一样将博客加载到内存中的转换,但是将接口从 ICollection 更改为 IQueryable ?

【问题讨论】:

  • 谢谢 - 谜,所以我的怀疑是真的。很伤心。

标签: c# entity-framework-4.1 ef-code-first iqueryable icollection


【解决方案1】:

所以实际上看起来你的导航属性写成IQueryable&lt;T&gt;is not possible

您可以做的是向Blog 添加一个导航属性:

public class Blog
{
   public int id { get; set; }
   public string Subject { get; set; }
   public string Body { get; set; }
   public virtual Person Owner { get; set; }
}

由此,您可以进行如下查询,这样它就不会将所有内容加载到内存中:

var thePerson = _context.Persons.Where(x => x.UserName = 'xxx').SingleOrDefault();
var results = _context.Blogs.Where(z => z.Person.Name = thePerson.Name).OrderBy(id).Take(5)

我建议你试试LINQPad 看看 LINQ 是如何翻译成 SQL 的,以及从 DB 中实际请求的内容。

【讨论】:

  • 非常感谢您的回复。好的,这是否意味着,ICollection 也是一个像 IQueryable 一样的惰性加载器,我可以在任何地方安全地使用 ICollection 来代替我希望在数据库中进行查询的 IQueryable ?关于 LINQPAD,我认为这给出了关于什么是 SQL 翻译的理论概念,但也许一些 EntityFramework Profiler 可以帮助更好地了解数据库中实际发送的 QUERY 是什么。我没有任何实体框架分析器,但现在我正在研究一些类似的产品。
  • 只是另一个问题,所以如果我之前的问题的答案是肯定的,那么,我不需要再对 ICollection 使用 AsQueryable() 了,对吧?
  • +1 推荐了一种使开发 LINQ 查询更容易的工具。
  • @EmranH。请参阅更新的答案。从您的评论中,我意识到我认为我误解了您的问题...对于 LINQPad,我真的推荐它,它非常有用并返回将针对您的数据库运行的 SQL。当然,您可以分析您的数据库(例如使用 SQL Server Profiler),但它会返回相同的结果并需要编译您的代码(另一方面,LINQPad 允许即时编写一些代码) .
  • 您好 Ken2k,再次感谢您的友好回复。实际上将父级作为导航属性添加到子级会创建循环引用,这是有两个原因的问题。 1.它违反了Domain Driven Design Patterns,DDD建议我应该从parent遍历到Child,而不是直接遍历。 2. 虽然#1 不是什么大问题,因为我们有时会违反规则,但是当通过 WCF/JSON/AJAX 加载通过线路序列化数据时,序列化程序无法序列化循环引用实体。那么,我的问题是,还有其他可用于延迟加载子项的替代方案吗?
【解决方案2】:

Ladislav's answer 中描述了更好的方法。在你的情况下:

var theBlogs = _context.Entry(thePerson)
                       .Collection(x => x.Blogs)
                       .Query()
                       .OrderBy(x => x.id)
                       .Take(5);

【讨论】:

    猜你喜欢
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多