2011-06-24 9 views
8

Używam Entity Framework Code First i wpadłem na mały blok drogi. Mam klasy "osoba" zdefiniowany jako takie:Kod struktury Entity Najpierw IQueryable

public class Person 
{ 
    public Guid Id { get; set; } 
    public virtual ICollection<History> History { get; set; } 
} 

i klasy "Historia" zdefiniowany jako takie:

public class History 
{ 
    public Guid Id { get; set; } 
    public virtual Person Owner { get; set; } 
    public DateTime OnDate { get; set; } 
} 

Jednak kiedy zadzwonić: Wydaje

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

wyciągnąć całą historię dla osoby, a następnie zamówić ją i takie w pamięci. Wszelkie zalecenia dotyczące tego, czego mi brakuje?

Z góry dziękuję!

+0

Jakiego zachowania się spodziewałeś? Czy nie ogranicza wyniku do 50 rekordów? –

+3

Myślę, że oczekiwanym zachowaniem jest zamówienie go w bazie danych –

+1

Spodziewałem się, że wyśle ​​zamówienie i ograniczy do serwera, powodując, że serwer SQL wykonuje zamawianie i ograniczanie. Zamiast tego wydaje się wciągać całą historię do pamięci, wszystkie ponad 30 000 elementów tego kontaktu, a następnie wykonuje kolejność i ogranicza pamięć. – Terry

Odpowiedz

5

Ponieważ kwerenda do IEnumerable (tj .: LINQ do obiektów) nie IQueryable (tj .: LINQ do jednostek) podane przez EF.

Zamiast tego należy użyć

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

To jest najpierw kod EF - zakłada się, że "Osoba" została pobrana z DB, stąd jego właściwość nawigacji "Historia" jest połączona z kontekstem. – BrokenGlass

+0

@BrokenGlass tak, jest podłączony. Ale jego typu 'ICollection ' nie 'IQueryable '. Tak więc, gdy otworzysz 'person.History', załaduje on wszystkie obiekty historii. – Eranga

+0

Ach, masz rację, skoro leniwy ładunek się pojawi i załaduje całą kolekcję. Mam mój +1 – BrokenGlass

0

To pytanie i odpowiedź są akceptowane zarówno nieco stary. Kod taki jak ten, jak pierwotnie wskazuje, ładuje całą historię osoby z bazy danych - nie jest dobra!

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

EF 6 jest proste rozwiązanie. Bez zmiany kolejności kwerendy, możesz mieć to działa na sposób IQueryable, korzystając z DbContext.Entry method, DbEntryEntity.Collection method i DbCollectionEntry.Query method.

var results = dbContext 
    .Entry(person) 
    .Collection(p => p.History) 
    .Query() 
    .OrderBy(h => h.OnDate) 
    .Take(50) 
    .ToArray(); 
Powiązane problemy