ICollection上的AsQueryable()真的会导致延迟执行吗

本文关键字:延迟 执行 真的 上的 AsQueryable ICollection | 更新日期: 2023-09-27 18:23:39

我使用的是实体框架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);

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

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

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

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

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

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

这对我来说就像是一种魔法,似乎太好了,不可能是真的。所以我的问题。这个AsQueryable是否真的让ICollection在现实中成为IQueryable,并使SQL Server中的所有查询过程(懒惰加载),或者它只是一个像以前一样将博客加载到内存中的转换,但将接口从ICollection更改为IQueryaable?

ICollection上的AsQueryable()真的会导致延迟执行吗

所以实际上,将导航属性写入IQueryable<T>似乎是不可能的。

您可以做的是向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实际请求了什么。

Ladislav的回答中描述了一种更好的方法。在您的情况下:
var theBlogs = _context.Entry(thePerson)
                       .Collection(x => x.Blogs)
                       .Query()
                       .OrderBy(x => x.id)
                       .Take(5);