2014-12-16 10 views
8

Piszę kod dostępu do bazy danych za pomocą EntityFrameWork. Kod jest następujący:Dlaczego potrzebuję funkcji ToList(), aby uniknąć zbędnych błędów kontekstu?

public IEnumerable<Rows> GetRows(int id) 
{ 
    using (var context = new ApplicationDbContext()) 
    { 
     var repository = new EntityFrameWorkRepository<int, RowEntity>(context); 
     //need a ToList() here to prevent disposed dbcontext errors 
     return repository.GetRowsFromDb(id).ToList(); 
    } 
} 

GetRowsFromDb() używa LINQ do wysyłania zapytań do bazy danych i filtrowania wyników za pomocą id.

Oryginalnie napisałem powyższą metodę bez wywoływania ToList(), ale kiedy próbowałem uzyskać dostęp do obiektów w IEnumerable, który został zwrócony, uzyskałbym wyjątek dotyczący już usuniętego dbcontext. Nie rozumiem, jak powyższy kod naprawia pewne rzeczy, mimo że działa. Zakładam, że ToList() głęboko kopiuje obiekt i może to zapewnia wymaganą separację od kontekstu/bazy danych, ale z pewnością oryginalny obiekt powinien być użyteczny?

+4

'IEnumerables' są leniwy, więc kontekst zostanie usunięty zanim jakiekolwiek wyniki zostaną pobrane w metodzie wywołania. 'ToList' sprawia, że ​​rzeczy są chętne. – Lee

+0

Wyszukaj "LINQ deffered execution" – MarcinJuraszek

+0

Losowo powiązane: http://stackoverflow.com/questions/27491762/creating-a-plan-repository- but-using-keyword-in-constructor-body/27491794#27491794 – BradleyDotNET

Odpowiedz

8

Powodem trzeba zadzwonić ToList, ToArray, lub jakaś inna metoda, która wymienia dane zwracane przez EF jest to, że wykonanie zapytania w LINQ jest odroczone: dane nie są przetwarzane dopóki nie brać go wyraźnie. Do czasu, gdy metoda zwróci kontekst, w którym dane zapytania zostały uzyskane, zostanie zamknięty (Twój blok using zajmie się szybko), powodując wyjątek, który widzisz.

Robi się to, aby kod nie spędzał czasu na przetwarzaniu danych, których nie potrzebujesz. Na przykład można napisać kod, który rozpoczyna odczytywanie danych po stronie klienta i zatrzymuje się w środku. Jeśli wykonanie zapytania nie zostało odłożone, spędziłbyś czas i pamięć uzyskując "ogon" zapytania tylko po to, by go wyrzucić. Odroczone wykonanie daje ci kontrolę: decydujesz, które dane chcesz zachować, lub przenosisz całą kolekcję do pamięci na podstawie tego, co planujesz zrobić z danymi.

7

Jeśli nie zadzwonić .ToList() enumerable będą oceniane po zakończy swoją klauzula using, a zatem kontekst dane zostaną usunięte przed oceny zapytania.

IMO, powinieneś rozważyć zrobienie tego w repozytorium (przez wywołanie .ToList()), ponieważ w przeciwnym razie problem ten jest reprezentatywny dla wycieku szczegółów implementacji.

1

Bez ToList() zwraca się tylko moduł wyliczający, a nie faktyczne zbieranie obiektów. Rzeczywiste obiekty są pobierane przy próbie dostępu do kolekcji. Ale w tym przypadku potrzebujesz kontekstu i repozytorium, ponieważ uzyskujesz dostęp do nich z bazy danych. Ale ponieważ jest już poza zakresem klauzuli using, oba są usuwane stąd wyjątek.

1

Zakładam ToList() jest głębokie kopiowanie przedmiotem

Niezupełnie - przed wywołaniem ToList wszystko masz to zapytania. nie dostaniesz wyników, dopóki nie wyliczysz go lub nie zmienisz w konkretny zbiór przez ToList, ToArray, etc.

z pewnością oryginalny obiekt powinien być użyteczny?

Nie - został unieszkodliwiony, co jest twoim sposobem poinformowania systemu, że obiekt wykonał swoją pracę i nie jest już potrzebny.Fakt, że wciąż masz niewykonane zapytanie, nie utrzymuje kontekstu w stanie użytecznym.

Powiązane problemy