może to być trywialne pytanie, ale: Ponieważ struktura encji ADO.NET automatycznie śledzi zmiany (w wygenerowanych jednostkach) i dlatego zachowuje oryginalne wartości, w jaki sposób mogę wycofać zmiany wprowadzone w obiektach jednostek?
Mam formularz, który umożliwia użytkownikowi edycję zbioru encji „Klient” w widoku siatki.
Teraz mam dwa przyciski „Akceptuj” i „Przywróć”: po kliknięciu „Akceptuj” wywołuję, Context.SaveChanges()
a zmienione obiekty są zapisywane z powrotem do bazy danych. Jeśli kliknięto „Przywróć”, chciałbym, aby wszystkie obiekty otrzymały oryginalne wartości właściwości. Jaki byłby na to kod?
Dzięki
źródło
Context.Refresh()
jest kontrprzykładem na twoje twierdzenie, że nie ma operacji przywracania? StosowanieRefresh()
wydaje się lepszym podejściem (tj. Łatwiejszym do nakierowania na określone podmioty) niż pozbycie się kontekstu i utrata wszystkich śledzonych zmian.Zapytanie ChangeTracker o DbContext dla brudnych elementów. Ustaw stan elementów usuniętych na niezmieniony i elementy dodane do odłączenia. W przypadku zmodyfikowanych pozycji użyj oryginalnych wartości i ustaw bieżące wartości pozycji. Na koniec ustaw stan zmodyfikowanego wpisu na niezmieniony:
źródło
State
do EntityState.Unchanged zastąpi wszystkie wartości zOriginal Values
tak dobrze, więc nie ma potrzeby, aby zadzwonić doSetValues
metody.Zgodnie z MSDN :
Zwróć uwagę, że powrót przez żądanie do bazy danych ma pewne wady:
źródło
To zadziałało dla mnie:
Gdzie
item
jest jednostka klienta, która ma zostać cofnięta.źródło
Łatwy sposób bez śledzenia zmian. Powinno być szybsze niż patrzenie na wszystkie podmioty.
źródło
Rollback
procedura, co czyni go znacznie lepszym wyborem, jeśli chce się przywrócić stan całej bazy danych. Rollback może mimo wszystko wybierać.50ms+0*n= 50ms
. O (n) oznacza, że wydajność zależy od liczby obiektów ... wydajność może być2ms+0.5ms*n
... więc poniżej 96 obiektów byłoby szybciej, ale czas wzrósłby liniowo wraz z ilością danych.U mnie zadziałało. Musisz jednak ponownie załadować dane z kontekstu, aby przywrócić stare dane. Źródło tutaj
źródło
„To zadziałało dla mnie:
Gdzie
item
jest jednostka klienta, która ma zostać przywrócona. "Wykonałem testy z ObjectContext.Refresh w SQL Azure, a „RefreshMode.StoreWins” odpala zapytanie do bazy danych dla każdej jednostki i powoduje przeciek wydajności. Na podstawie dokumentacji Microsoft ():
ClientWins: zmiany właściwości wprowadzone w obiektach w kontekście obiektu nie są zastępowane wartościami ze źródła danych. Przy następnym wywołaniu SaveChanges te zmiany są wysyłane do źródła danych.
StoreWins: zmiany właściwości wprowadzone w obiektach w kontekście obiektu są zastępowane wartościami ze źródła danych.
ClientWins też nie jest dobrym pomysłem, ponieważ odpalenie .SaveChanges spowoduje „odrzucenie” zmian w źródle danych.
Nie wiem jeszcze, jaki jest najlepszy sposób, ponieważ usunięcie kontekstu i utworzenie nowego powoduje wyjątek z komunikatem: „Podstawowy dostawca nie powiódł się przy otwieraniu”, gdy próbuję uruchomić dowolne zapytanie w nowo utworzonym kontekście.
pozdrowienia,
Henrique Clausing
źródło
Jak dla mnie lepszą metodą jest ustawienie
EntityState.Unchanged
na każdym obiekcie, na którym chcesz cofnąć zmiany. Zapewnia to cofnięcie zmian w FK i ma nieco bardziej przejrzystą składnię.źródło
Okazało się, że działa dobrze w moim kontekście:
Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);
źródło
DbContext.SaveChanges()
, ale nie zwróci wartości jednostki do oryginalnych wartości. A jeśli stan encji zostanie zmodyfikowany po późniejszej zmianie, być może wszystkie poprzednie modyfikacje zostaną zachowane po zapisaniu?To jest przykład tego, o czym mówi Mrnka. Poniższa metoda zastępuje bieżące wartości jednostki oryginalnymi wartościami i nie wywołuje bazy danych. Robimy to, używając właściwości OriginalValues DbEntityEntry i używamy odbicia do ustawiania wartości w sposób ogólny. (Działa od EntityFramework 5.0)
źródło
Używamy EF 4 z kontekstem Legacy Object. Żadne z powyższych rozwiązań nie odpowiadało mi bezpośrednio na to - chociaż na dłuższą metę NIE odpowiadało, popychając mnie we właściwym kierunku.
Nie możemy po prostu pozbyć się i odbudować kontekstu, ponieważ niektóre z obiektów, które trzymamy w pamięci (do cholery, to leniwe ładowanie !!) są nadal dołączone do kontekstu, ale mają dzieci, które jeszcze nie zostały załadowane. W takich przypadkach musimy przywrócić wszystko do oryginalnych wartości bez wbijania bazy danych i bez porzucania istniejącego połączenia.
Poniżej znajduje się nasze rozwiązanie tego samego problemu:
Mam nadzieję, że to pomoże innym.
źródło
Kilka dobrych pomysłów powyżej, zdecydowałem się zaimplementować ICloneable, a następnie prostą metodę rozszerzenia.
Znaleziono tutaj: Jak sklonować listę ogólną w języku C #?
Do wykorzystania jako:
W ten sposób mogłem sklonować listę jednostek produktów, zastosować rabat do każdej pozycji i nie musiałem martwić się o cofnięcie jakichkolwiek zmian w pierwotnej jednostce. Nie ma potrzeby rozmawiać z DBContext i prosić o odświeżenie lub pracę z ChangeTracker. Można powiedzieć, że nie wykorzystuję w pełni EF6, ale jest to bardzo ładna i prosta implementacja, która pozwala uniknąć trafienia w DB. Nie mogę powiedzieć, czy jest to hit wydajnościowy.
źródło