实体框架代码优先 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&lt;History&gt; 而不是IQueryable&lt;History&gt;。因此,当您访问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的主要内容,如果未能解决你的问题,请参考以下文章

实体框架代码优先 IQueryable

实体框架、代码优先和全文搜索

实体框架代码优先 - 通过主键将子实体添加到父实体

实体框架代码优先:启用迁移错误

实体框架代码优先的性能

无法在 .NET 中的实体框架代码优先方法中迁移 AspNetUser 实体