2011-06-24 45 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();