2011-06-24 180 views
8

我正在使用实体框架Code First,并遇到了一个小路障。我有一类 “人” 定义为这样的:实体框架代码第一个IQueryable

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(); 

看样子把这个人的所有历史都拉下来,然后在内存中排序等等。关于我失踪的任何建议?

在此先感谢!

+0

你期待看到什么行为?它不能将结果限制为50条记录吗? –

+3

我认为预期的行为是在数据库中排序 –

+1

我期待它将订单和限制发送到服务器,导致SQL服务器执行排序和限制。相反,它似乎把所有的历史记录都存入内存中,所有这些联系人都有30,000多个元素,然后在内存中进行排序和限制。 – Terry

回答

5

因为您正在查询由EF给出的IEnumerable(即:LINQ to Objects)而不是IQueryable(即:LINQ to Entities)。

相反,你应该使用

IEnumerable<History> results = context.History.Where(h => h.Person.Id = "sfssd").OrderBy(h => h.OnDate).Take(50) 
+0

这是EF代码优先 - 假设'Person'是从DB中检索的,因此其导航属性'History'连接到上下文。 – BrokenGlass

+0

@BrokenGlass是的,它已连接。但它的类型'ICollection '不'IQueryable '。所以当你访问'person.History'时,它会加载所有的历史对象。 – Eranga

+0

啊,你当然是对的,因为懒惰加载会踢入并加载完整的集合。得到我的+1 – BrokenGlass

0

这个问题和接受的答案都有点老了。像这样的代码会像原始问题一样,从数据库中加载整个人的历史记录 - 不是很好!

var results = person 
    .History 
    .OrderBy(h => h.OnDate) 
    .Take(50) 
    .ToArray(); 

随着EF 6有一个简单的解决方案。在不重新排列查询的情况下,通过使用DbContext.Entry method,DbEntryEntity.Collection methodDbCollectionEntry.Query method,您可以使用IQueryable的方式。

var results = dbContext 
    .Entry(person) 
    .Collection(p => p.History) 
    .Query() 
    .OrderBy(h => h.OnDate) 
    .Take(50) 
    .ToArray(); 
相关问题