我正在使用Entity Framework CodeFirst,我使用ICollection作为
使用了Parent Child关系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);
现在,我了解到,当执行该行时,该人员的所有博客都会加载到内存中,然后从内存中进行排序和选择。这对于拥有大量博客的人员的记录来说并不理想。我想将Blog Child设为IQueryable,以便在拉入Memory之前在SQL数据库中完成排序和选择。
我知道我可以在我的上下文中将Blogs声明为IQueryable,以便我可以直接查询为
var theBlogs = _context.Blogs.Where(.....)
但由于设计选择,这对我来说是不可行的,因为序列化问题,我想尽可能避免任何循环引用。所以,我没有在我孩子的父母实体中做任何参考。
我发现,我可以在博客上调用AsQueryable()方法
var theBlogs = thePerson.Blogs.AsQueryable().OrderBy(id).Take(5);
对我来说这看起来很神奇,看起来好得令人难以置信。所以我的问题。这个AsQueryable是否真的使ICollection成为现实中的IQueryable并在SQL Server中进行所有查询过程(延迟加载)或者它只是将博客像以前一样加载到内存中,但是将接口从ICollection更改为IQueryable?
答案 0 :(得分:6)
实际上,将导航属性显示为IQueryable<T>
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,以及实际从数据库请求的内容。
答案 1 :(得分:2)
Ladislav's answer中描述了一种更好的方法。在你的情况下:
var theBlogs = _context.Entry(thePerson)
.Collection(x => x.Blogs)
.Query()
.OrderBy(x => x.id)
.Take(5);