Kiedy zapisuję jednostkę za pomocą frameworka jednostki, naturalnie zakładałem, że spróbuje tylko zapisać określoną jednostkę. Jednak próbuje również ocalić byty podrzędne tej jednostki. Powoduje to różnego rodzaju problemy z uczciwością. Jak zmusić EF, aby zapisywał tylko jednostkę, którą chcę zapisać, a zatem ignorować wszystkie obiekty podrzędne?
Jeśli ręcznie ustawię właściwości na wartość null, pojawia się błąd „Operacja nie powiodła się: nie można zmienić relacji, ponieważ co najmniej jedna z właściwości klucza obcego nie dopuszcza wartości null”. Jest to wyjątkowo nieproduktywne, ponieważ ustawiłem obiekt podrzędny na null specjalnie, aby EF zostawił go w spokoju.
Dlaczego nie chcę zapisywać / wstawiać obiektów podrzędnych?
Ponieważ jest to omawiane w kółko w komentarzach, podam pewne uzasadnienie, dlaczego chcę, aby moje przedmioty dziecięce zostały pozostawione same.
W aplikacji, którą buduję, model obiektów EF nie jest ładowany z bazy danych, ale używany jako obiekty danych, które wypełniam podczas analizowania pliku płaskiego. W przypadku obiektów podrzędnych wiele z nich odwołuje się do tabel przeglądowych definiujących różne właściwości tabeli nadrzędnej. Na przykład położenie geograficzne jednostki podstawowej.
Ponieważ sam wypełniłem te obiekty, EF zakłada, że są to nowe obiekty i należy je wstawić wraz z obiektem nadrzędnym. Jednak te definicje już istnieją i nie chcę tworzyć duplikatów w bazie danych. Używam obiektu EF tylko do wyszukiwania i wypełniania klucza obcego w mojej głównej encji tabeli.
Nawet w przypadku obiektów podrzędnych, które są prawdziwymi danymi, muszę najpierw zapisać rodzica i uzyskać klucz podstawowy lub EF po prostu robi bałagan. Mam nadzieję, że to daje pewne wyjaśnienie.
źródło
Odpowiedzi:
O ile wiem, masz dwie możliwości.
Opcja 1)
Null wszystkie obiekty podrzędne, dzięki temu EF niczego nie doda. Nie usunie również niczego z Twojej bazy danych.
Opcja 2)
Ustaw obiekty podrzędne jako odłączone od kontekstu przy użyciu następującego kodu
Pamiętaj, że nie możesz odłączyć
List
/Collection
. Będziesz musiał zapętlić listę i odłączyć każdy element z listy w ten sposóbźródło
Krótko mówiąc: użyj klucza obcego, a zaoszczędzi ci to dnia.
Załóżmy, że masz jednostkę szkolną i miejską. Jest to relacja typu „wiele do jednego”, w której miasto ma wiele szkół, a szkoła należy do miasta. I załóżmy, że miasta już istnieją w tabeli przeglądowej, więc NIE chcesz, aby były one ponownie wstawiane podczas wstawiania nowej szkoły.
Początkowo możesz zdefiniować swoje jednostki w ten sposób:
I możesz zrobić wstawienie Szkoła w ten sposób (załóżmy, że masz już właściwość City przypisaną do newItem ):
Powyższe podejście może się sprawdzić w tym przypadku, jednak wolę podejście klucza obcego, które jest dla mnie bardziej przejrzyste i elastyczne. Zobacz zaktualizowane rozwiązanie poniżej:
W ten sposób wyraźnie definiujesz, że Szkoła ma klucz obcy City_Id i odnosi się do jednostki City . Więc jeśli chodzi o wstawianie szkoły , możesz:
W takim przypadku jawnie określasz City_Id nowego rekordu i usuwasz miasto z wykresu, aby EF nie zawracał sobie głowy dodawaniem go do kontekstu wraz ze szkołą .
Chociaż na pierwszy rzut oka podejście klucza obcego wydaje się bardziej skomplikowane, ale uwierz mi, ta mentalność pozwoli Ci zaoszczędzić dużo czasu, jeśli chodzi o wstawianie relacji wiele-do-wielu (wyobrażając sobie, że masz relację Szkoła i Uczeń, a ma właściwość City) i tak dalej.
Mam nadzieję, że to ci pomoże.
źródło
[Range(1, int.MaxValue)]
atrybutu?Jeśli chcesz tylko zapisać zmiany w obiekcie nadrzędnym i uniknąć zapisywania zmian w jakimkolwiek z jego obiektów podrzędnych , dlaczego nie wykonać następujących czynności:
Pierwsza linia dołącza obiekt nadrzędny i cały wykres zależnych od niego obiektów potomnych do kontekstu w
Unchanged
stanie.Druga linia zmienia stan tylko dla obiektu nadrzędnego, pozostawiając jego dzieci w
Unchanged
stanie.Zauważ, że używam nowo utworzonego kontekstu, więc pozwala to uniknąć zapisywania jakichkolwiek innych zmian w bazie danych.
źródło
Jednym z sugerowanych rozwiązań jest przypisanie właściwości nawigacji z tego samego kontekstu bazy danych. W tym rozwiązaniu właściwość nawigacji przypisana spoza kontekstu bazy danych zostanie zastąpiona. Zobacz poniższy przykład dla ilustracji.
Zapisywanie do bazy danych:
Microsoft dodaje to jako funkcję, jednak wydaje mi się to denerwujące. Jeśli obiekt działu powiązany z obiektem firmy ma identyfikator, który już istnieje w bazie danych, to dlaczego EF po prostu nie kojarzy obiektu firmy z obiektem bazy danych? Dlaczego powinniśmy sami zadbać o stowarzyszenie? Dbanie o właściwość nawigacji podczas dodawania nowego obiektu jest czymś w rodzaju przenoszenia operacji bazy danych z SQL do C #, co jest uciążliwe dla programistów.
źródło
Najpierw musisz wiedzieć, że istnieją dwa sposoby aktualizowania jednostki w EF.
W aplikacji, którą buduję, model obiektów EF nie jest ładowany z bazy danych, ale używany jako obiekty danych, które wypełniam podczas analizowania pliku płaskiego.
Oznacza to, że pracujesz z odłączonym obiektem, ale nie jest jasne, czy używasz skojarzenia niezależnego, czy skojarzenia z kluczem obcym .
Dodaj
Podczas dodawania nowej jednostki z istniejącym obiektem podrzędnym (obiektem, który istnieje w bazie danych), jeśli obiekt podrzędny nie jest śledzony przez EF, obiekt podrzędny zostanie ponownie wstawiony. Chyba że najpierw ręcznie dołączysz obiekt podrzędny.
Aktualizacja
Możesz po prostu oznaczyć jednostkę jako zmodyfikowaną, wtedy wszystkie właściwości skalarne zostaną zaktualizowane, a właściwości nawigacji zostaną po prostu zignorowane.
Graph Diff
Jeśli chcesz uprościć kod podczas pracy z odłączonym obiektem, możesz spróbować wyświetlić bibliotekę różnic grafowych .
Oto wprowadzenie, wprowadzenie GraphDiff dla Entity Framework Code First - zezwalanie na automatyczne aktualizacje wykresu odłączonych jednostek .
Przykładowy kod
Wstaw jednostkę, jeśli nie istnieje, w przeciwnym razie zaktualizuj.
Wstaw jednostkę, jeśli nie istnieje, w przeciwnym razie zaktualizuj i wstaw obiekt podrzędny, jeśli nie istnieje, w przeciwnym razie zaktualizuj.
źródło
Najlepszym sposobem na to jest zastąpienie funkcji SaveChanges w kontekście danych.
źródło
Mam ten sam problem, gdy próbuję zapisać profil, mam już powitanie stolika i nowy, aby utworzyć profil. Kiedy wstawiam profil, wstawiam również do pozdrowienia. Więc próbowałem w ten sposób przed savechanges ().
db.Entry (Profile.Salutation) .State = EntityState.Unchanged;
źródło
To zadziałało dla mnie:
źródło
To, co zrobiliśmy, to przed dodaniem elementu nadrzędnego do zestawu dbset, odłączenie kolekcji podrzędnej od elementu nadrzędnego, upewniając się, że istniejące kolekcje są przenoszone do innych zmiennych, aby umożliwić późniejszą pracę z nimi, a następnie zastępując bieżące kolekcje podrzędne nowymi, pustymi kolekcjami. Wydawało się, że ustawienie kolekcji podrzędnych na null / nic nie działa. Po wykonaniu tej czynności dodaj rodzica do zestawu dbset. W ten sposób dzieci nie są dodawane, dopóki tego nie chcesz.
źródło
Wiem, że to stary post, ale jeśli używasz podejścia opartego na kodzie, możesz osiągnąć pożądany rezultat, używając następującego kodu w pliku mapowania.
Po prostu poinformuje EF, aby wykluczył właściwość „ChildObjectOrCollection” z modelu, aby nie była mapowana do bazy danych.
źródło
Miałem podobne wyzwanie, używając Entity Framework Core 3.1.0, moja logika repozytorium jest dość ogólna.
To zadziałało dla mnie:
Należy pamiętać, że „ParentEntityId” to nazwa kolumny klucza obcego w jednostce podrzędnej. Dodałem wyżej wymienioną linię kodu w tej metodzie:
źródło