实体框架代码优先 IQueryable
Posted
技术标签:
【中文标题】实体框架代码优先 IQueryable【英文标题】:Entity Framework Code First IQueryable 【发布时间】:2011-06-24 15:42:34 【问题描述】:我首先使用实体框架代码并遇到了一个小障碍。我有一个这样定义的“人”类:
public class Person
public Guid Id get; set;
public virtual ICollection<History> History get; set;
以及这样定义的“历史”类:
public class History
public Guid Id get; set;
public virtual Person Owner get; set;
public DateTime OnDate get; set;
但是,当我打电话时:
IEnumerable<History> results = person.History
.OrderBy(h => h.OnDate)
.Take(50)
.ToArray();
它似乎为该人提取了所有历史记录,然后在内存中对其进行排序等。关于我缺少什么的任何建议?
提前致谢!
【问题讨论】:
您希望看到什么行为?是否未能将结果限制为 50 条记录? 我认为预期的行为是在数据库中订购它 我期待它通过服务器发送订单和限制,导致 SQL 服务器进行排序和限制。相反,它似乎将所有历史记录拉入内存,该联系人的所有 30,000 多个元素,然后在内存中执行顺序和限制。 为什么你确定它正在将它加载到内存中?看到生成的sql了吗? 【参考方案1】:因为您查询的是 IEnumerable
(即:LINQ to Objects)而不是 EF 给出的 IQueryable
(即:LINQ to Entities)。
你应该使用
IEnumerable<History> results = context.History.Where(h => h.Person.Id = "sfssd").OrderBy(h => h.OnDate).Take(50)
【讨论】:
这是 EF 代码优先 - 假设Person
是从数据库中检索到的,因此其导航属性 History
连接到上下文。
@BrokenGlass 是的,它已连接。但它的类型为ICollection<History>
而不是IQueryable<History>
。因此,当您访问person.History
时,它将加载所有历史对象。
啊,你当然是对的,因为延迟加载会启动并加载完整的集合。得到了我的 +1
那太糟糕了。我想这一切都是有道理的,我只是希望有办法做到这一点。 EF 5 有一个想法... IQueryableCollection。 :-)
您总是可以编写一个 [NotMapped] 属性来完成 IQueryable 的工作。【参考方案2】:
这个问题和接受的答案都有点老了。作为原始问题点,这样的代码会从数据库中加载该人的整个历史记录 - 不好!
var results = person
.History
.OrderBy(h => h.OnDate)
.Take(50)
.ToArray();
使用 EF 6 有一个简单的解决方案。在不重新排列查询的情况下,您可以通过使用DbContext.Entry
method、DbEntryEntity.Collection
method 和DbCollectionEntry.Query
method 使其以IQueryable
的方式工作。
var results = dbContext
.Entry(person)
.Collection(p => p.History)
.Query()
.OrderBy(h => h.OnDate)
.Take(50)
.ToArray();
【讨论】:
以上是关于实体框架代码优先 IQueryable的主要内容,如果未能解决你的问题,请参考以下文章