10

我正在使用实体框架 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 ?

4

2 回答 2

7

所以实际上似乎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 中实际请求的内容。

于 2012-02-08T10:15:36.117 回答
3

Ladislav 的回答中描述了一种更好的方法。在你的情况下:

var theBlogs = _context.Entry(thePerson)
                       .Collection(x => x.Blogs)
                       .Query()
                       .OrderBy(x => x.id)
                       .Take(5);
于 2012-02-09T03:11:30.607 回答