Próbuję wypełnić GridView
przy użyciu Entity Frameworkm, ale za każdym razem otrzymuję następujący błąd:
„Akcesor właściwości„ LoanProduct ”na obiekcie„ COSIS_DAL.MemberLoan ”spowodował następujący wyjątek: Instancja ObjectContext została usunięta i nie może być już używana do operacji wymagających połączenia."
Mój kod to:
public List<MemberLoan> GetAllMembersForLoan(string keyword)
{
using (CosisEntities db = new CosisEntities())
{
IQueryable<MemberLoan> query = db.MemberLoans.OrderByDescending(m => m.LoanDate);
if (!string.IsNullOrEmpty(keyword))
{
keyword = keyword.ToLower();
query = query.Where(m =>
m.LoanProviderCode.Contains(keyword)
|| m.MemNo.Contains(keyword)
|| (!string.IsNullOrEmpty(m.LoanProduct.LoanProductName) && m.LoanProduct.LoanProductName.ToLower().Contains(keyword))
|| m.Membership.MemName.Contains(keyword)
|| m.GeneralMasterInformation.Description.Contains(keyword)
);
}
return query.ToList();
}
}
protected void btnSearch_Click(object sender, ImageClickEventArgs e)
{
string keyword = txtKeyword.Text.ToLower();
LoanController c = new LoanController();
List<COSIS_DAL.MemberLoan> list = new List<COSIS_DAL.MemberLoan>();
list = c.GetAllMembersForLoan(keyword);
if (list.Count <= 0)
{
lblMsg.Text = "No Records Found";
GridView1.DataSourceID = null;
GridView1.DataSource = null;
GridView1.DataBind();
}
else
{
lblMsg.Text = "";
GridView1.DataSourceID = null;
GridView1.DataSource = list;
GridView1.DataBind();
}
}
Błąd zawiera wzmiankę o LoanProductName
kolumnie Gridview
. Wspomniane: używam C #, ASP.net, SQL-Server 2008 jako zaplecza DB.
Jestem całkiem nowy w Entity Framework. Nie mogę zrozumieć, dlaczego otrzymuję ten błąd. Czy ktoś może mi pomóc, proszę?
c#
asp.net
entity-framework
Barsan
źródło
źródło
query.Include("SomeOtherTable")
db.MemberLoans.Include("LoanProduct").OrderByDescending()
sprawdzić składnię, ponieważ nie mam przed sobą VS.db.MemberLoans.Include("LoanProduct").Include("SomeOtherTable)
. Sprawdź odpowiedzi @Tragedian i @lazyberezovskyOdpowiedzi:
Domyślnie Entity Framework używa ładowania z opóźnieniem dla właściwości nawigacji. Dlatego te właściwości powinny być oznaczone jako wirtualne - EF tworzy klasę proxy dla Twojej jednostki i zastępuje właściwości nawigacji, aby umożliwić ładowanie z opóźnieniem. Np. Jeśli masz ten podmiot:
Entity Framework zwróci serwer proxy dziedziczony z tej jednostki i zapewni wystąpienie DbContext do tego serwera proxy, aby umożliwić późniejsze ładowanie członkostwa z opóźnieniem:
Tak więc jednostka ma wystąpienie DbContext, które zostało użyte do załadowania jednostki. To Twój problem. Masz
using
blokadę wokół wykorzystania CosisEntities. Który usuwa kontekst przed zwróceniem jednostek. Gdy jakiś kod później próbuje użyć właściwości nawigacji ładowanej z opóźnieniem, kończy się to niepowodzeniem, ponieważ kontekst jest usuwany w tym momencie.Aby naprawić to zachowanie, możesz użyć szybkiego ładowania właściwości nawigacji, które będą potrzebne później:
Spowoduje to wstępne załadowanie wszystkich członkostw, a ładowanie z opóźnieniem nie będzie używane. Aby uzyskać szczegółowe informacje, zobacz artykuł Ładowanie powiązanych jednostek w witrynie MSDN.
źródło
db.MemberLoans.Include(m => m.Membership).Include(m => m.LoanProduct).OrderByDescending(m => m.LoanDate);
To wygeneruje zapytanie JOIN i zwróci wszystkie dane naraz.CosisEntities
Klasa jest TwojaDbContext
. Tworząc kontekst wusing
bloku, definiujesz granice operacji zorientowanej na dane.W swoim kodzie próbujesz wyemitować wynik zapytania z metody, a następnie zakończyć kontekst w metodzie. Operacja, do której przekazujesz wynik, próbuje następnie uzyskać dostęp do jednostek w celu wypełnienia widoku siatki. Gdzieś w trakcie tworzenia powiązania z siatką uzyskuje się dostęp do właściwości ładowanej z opóźnieniem, a Entity Framework próbuje przeprowadzić wyszukiwanie w celu uzyskania wartości. Nie udaje się, ponieważ powiązany kontekst już się zakończył.
Masz dwa problemy:
Leniwie ładujesz jednostki, gdy łączysz się z siatką. Oznacza to, że wykonujesz wiele oddzielnych operacji zapytań w SQL Server, co spowolni wszystko. Możesz rozwiązać ten problem, domyślnie ładując powiązane właściwości z przyspieszeniem lub prosząc Entity Framework o uwzględnienie ich w wynikach tego zapytania przy użyciu
Include
metody rozszerzenia.Przedwcześnie kończysz swój kontekst: a
DbContext
powinien być dostępny przez całą wykonywaną jednostkę pracy, usuwając go dopiero po zakończeniu pracy. W przypadku ASP.NET jednostką pracy jest zwykle obsługiwane żądanie HTTP.źródło
Podsumowanie
Twój kod pobrał dane (jednostki) za pośrednictwem platformy jednostek z włączonym ładowaniem z opóźnieniem, a po usunięciu DbContext kod odwołuje się do właściwości (jednostek powiązanych / relacji / nawigacji), które nie zostały jawnie zażądane.
Dokładniej
Z
InvalidOperationException
tym komunikatem zawsze oznacza to samo: żądasz danych (jednostek) z platformy encji po usunięciu DbContext.Prosty przypadek:
(te klasy będą używane we wszystkich przykładach w tej odpowiedzi, przy założeniu, że wszystkie właściwości nawigacji zostały poprawnie skonfigurowane i mają powiązane tabele w bazie danych)
Ostatni wiersz wyrzuci błąd,
InvalidOperationException
ponieważ dbContext nie wyłączył ładowania z opóźnieniem, a kod uzyskuje dostęp do właściwości nawigacji Pet po usunięciu Context przez instrukcję using.Debugowanie
Jak znajdujesz źródło tego wyjątku? Oprócz spojrzenia na sam wyjątek, który zostanie wyrzucony dokładnie w miejscu, w którym wystąpi, obowiązują ogólne zasady debugowania w programie Visual Studio: umieszczaj strategiczne punkty przerwania i sprawdzaj zmienne , albo najeżdżając kursorem myszy na ich nazwy, otwierając znak ( Szybkie) Okno obserwacyjne lub za pomocą różnych paneli debugowania, takich jak Lokalne i Auta.
Jeśli chcesz dowiedzieć się, gdzie odniesienie jest lub nie jest ustawione, kliknij prawym przyciskiem myszy jego nazwę i wybierz „Znajdź wszystkie odwołania”. Następnie możesz umieścić punkt przerwania w każdej lokalizacji, która żąda danych, i uruchomić program z dołączonym debugerem. Za każdym razem, gdy debuger przerywa pracę w takim punkcie przerwania, należy określić, czy właściwość nawigacji powinna zostać wypełniona, czy też wymagane są wymagane dane.
Sposoby uniknięcia
Wyłącz leniwe ładowanie
Zalety: zamiast zgłaszać wyjątek InvalidOperationException, właściwość będzie miała wartość null. Uzyskiwanie dostępu do właściwości null lub próba zmiany właściwości tej właściwości spowoduje zgłoszenie wyjątku NullReferenceException .
Jak jawnie zażądać obiektu w razie potrzeby:
W poprzednim przykładzie Entity Framework zmaterializuje Pet oprócz Person. Może to być korzystne, ponieważ jest to pojedyncze wywołanie bazy danych. (Jednak w zależności od liczby zwracanych wyników i liczby żądanych właściwości nawigacji mogą również wystąpić ogromne problemy z wydajnością, w tym przypadku nie byłoby spadku wydajności, ponieważ oba wystąpienia są tylko jednym rekordem i pojedynczym złączeniem).
lub
W poprzednim przykładzie Entity Framework zmaterializuje Pet niezależnie od osoby, wykonując dodatkowe wywołanie bazy danych. Domyślnie Entity Framework śledzi obiekty pobrane z bazy danych i jeśli znajdzie właściwości nawigacji, które pasują do niego, automatycznie wypełni te jednostki. W tym przypadku, ponieważ
PetId
naPerson
obiekcie dopasowujePet.Id
, Entity Framework przypiszePerson.Pet
doPet
wartości pobranej przed wartość jest przypisana do zmiennej domowych.Zawsze polecam to podejście, ponieważ zmusza programistów do zrozumienia, kiedy i jak kod żąda danych za pośrednictwem Entity Framework. Gdy kod zgłasza wyjątek odwołania zerowego dla właściwości jednostki, prawie zawsze można mieć pewność, że nie zażądano jawnie tych danych.
źródło
To bardzo późna odpowiedź, ale rozwiązałem problem wyłączając leniwe ładowanie:
źródło
W moim przypadku przekazywałem wszystkie modele „Users” do kolumny i nie było to poprawnie zmapowane, więc po prostu przekazałem „Users.Name” i naprawiłem to.
źródło
Większość innych odpowiedzi wskazuje na chęć ładowania, ale znalazłem inne rozwiązanie.
W moim przypadku miałem obiekt EF
InventoryItem
z kolekcjąInvActivity
obiektów potomnych.A ponieważ wyciągałem z kolekcji obiektów potomnych zamiast zapytania kontekstowego (z
IQueryable
),Include()
funkcja nie była dostępna do zaimplementowania zachłannego ładowania. Zamiast tego moim rozwiązaniem było utworzenie kontekstu, z którego użyłemGetLatestActivity()
iattach()
zwróconego obiektu:Dzięki temu nie utkniesz z gorliwym ładowaniem.
źródło
Jeśli używasz ASP.NET Core i zastanawiasz się, dlaczego otrzymujesz ten komunikat w jednej z metod kontrolera asynchronicznego, upewnij się, że zwracasz
Task
zamiastvoid
- ASP.NET Core usuwa wstrzyknięte konteksty.(Publikuję tę odpowiedź, ponieważ to pytanie jest wysoko w wynikach wyszukiwania tego komunikatu o wyjątku i jest to subtelny problem - może jest przydatny dla osób, które w tym celu wyszukują w Google.)
źródło