Cofanie zmian w encjach ramowych
To może być trywialne pytanie, ale: ponieważ ADO.NET struktura encji automatycznie śledzi zmiany (w generowanych encjach) i dlatego zachowuje oryginalne wartości, jak mogę cofnąć zmiany wprowadzone w obiektach encji?
Mam formularz, który pozwala użytkownikowi edytować zestaw elementów "Klienta" w widoku siatki.
Teraz mam dwa przyciski "Accept " i" Revert": jeśli klikniesz "Accept", wywołuję Context.SaveChanges()
i zmienione obiekty są zapisywane z powrotem do bazy danych. Jeśli "Revert" jest kliknij, chciałbym, aby wszystkie obiekty, aby uzyskać ich oryginalne wartości właściwości. Jaki byłby na to kod?
Thanks
12 answers
Nie ma operacji przywracania lub anulowania zmian w EF. Każda jednostka ma ObjectStateEntry
W ObjectStateManager
. Wpis State zawiera oryginalne i rzeczywiste wartości, więc możesz użyć oryginalnych wartości do nadpisania bieżących wartości, ale musisz to zrobić ręcznie dla każdego elementu. Nie przywróci zmian we właściwościach / relacjach nawigacyjnych.
Powszechnym sposobem na "odwrócenie zmian" jest usuwanie kontekstu i przeładowywanie encji. Jeśli chcesz uniknąć przeładowania, musisz utworzyć klony encji i zmodyfikować te klony w nowym kontekst obiektu. Jeśli Użytkownik anuluje zmiany, nadal będziesz mieć oryginalne elementy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-29 06:09:31
Query ChangeTracker DbContext dla brudnych elementów. Ustaw stan usuniętych elementów na niezmieniony, a dodane elementy na odłączony. Dla zmodyfikowanych pozycji należy użyć wartości oryginalnych i ustawić bieżące wartości wpisu. Na koniec ustaw stan zmodyfikowanego wpisu na niezmieniony:
public void RollBack()
{
var context = DataContextFactory.GetDataContext();
var changedEntries = context.ChangeTracker.Entries()
.Where(x => x.State != EntityState.Unchanged).ToList();
foreach (var entry in changedEntries)
{
switch(entry.State)
{
case EntityState.Modified:
entry.CurrentValues.SetValues(entry.OriginalValues);
entry.State = EntityState.Unchanged;
break;
case EntityState.Added:
entry.State = EntityState.Detached;
break;
case EntityState.Deleted:
entry.State = EntityState.Unchanged;
break;
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-23 04:08:05
dbContext.Entry(entity).Reload();
Do MSDN :
przeładowuje obiekt z bazy danych nadpisując dowolne wartości właściwości wartościami z bazy danych. Jednostka będzie w niezmienionej stan po wywołaniu tej metody.
Zwróć uwagę, że przywrócenie żądania do bazy danych ma pewne wady:
- ruch sieciowy
- DB overload
- wydłużony czas reakcji aplikacji
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-22 23:00:17
To mi pomogło:
dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item);
Gdzie item
jest podmiotem klienta, który ma zostać przywrócony.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-09 00:53:55
Łatwy sposób bez śledzenia zmian. To powinno być szybsze niż patrzenie na wszystkie byty.
public void Rollback()
{
dataContext.Dispose();
dataContext= new MyEntities(yourConnection);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-31 20:56:45
// Undo the changes of all entries.
foreach (DbEntityEntry entry in context.ChangeTracker.Entries())
{
switch (entry.State)
{
// Under the covers, changing the state of an entity from
// Modified to Unchanged first sets the values of all
// properties to the original values that were read from
// the database when it was queried, and then marks the
// entity as Unchanged. This will also reject changes to
// FK relationships since the original value of the FK
// will be restored.
case EntityState.Modified:
entry.State = EntityState.Unchanged;
break;
case EntityState.Added:
entry.State = EntityState.Detached;
break;
// If the EntityState is the Deleted, reload the date from the database.
case EntityState.Deleted:
entry.Reload();
break;
default: break;
}
}
U mnie zadziałało. Musisz jednak przeładować swoje dane z kontekstu, aby przynieść stare dane. Źródło Tutaj Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-25 08:31:07
"to mi się udało:
dataContext.customer.Context.Refresh(RefreshMode.StoreWins, item);
Gdzie item
jest podmiotem klienta, który ma zostać przywrócony."
Wykonałem testy z ObjectContext.Odśwież w SQL Azure i " RefreshMode.StoreWins " wywołuje zapytanie z bazą danych dla każdej jednostki i powoduje wyciek wydajności. Na podstawie dokumentacji microsoft ():
ClientWins: zmiany właściwości obiektów w kontekście obiektu nie są zastępowane wartościami ze źródła danych. Przy kolejnym wezwaniu do ratowania, te zmiany są wysyłane do źródła danych.
StoreWins : zmiany właściwości obiektów w kontekście obiektu zostaną zastąpione wartościami ze źródła danych.
ClientWins też nie jest dobrą ideą, boSaveChanges zatwierdzi "odrzucone" zmiany w źródle danych.I dont 'know what' s the best way yet, because disposing the context and creating a new one is caused a exception with message: "The based provider failed on open" when I spróbuj uruchomić dowolne zapytanie w nowym utworzonym kontekście.
Pozdrawiam,
Henrique Clausing]}Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-04 21:17:03
Jak dla mnie, lepszą metodą jest ustawienie EntityState.Unchanged
Na każdym obiekcie, na którym chcesz cofnąć zmiany. Zapewnia to, że zmiany są przywracane na FK i ma nieco bardziej przejrzystą składnię.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-07 08:31:56
Okazało się, że to działa dobrze w moim kontekście:
Context.ObjectStateManager.ChangeObjectState(customer, EntityState.Unchanged);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-08 15:23:45
To jest przykład tego, o czym mówi Mrnka. Poniższa metoda nadpisuje bieżące wartości encji wartościami oryginalnymi i nie wywołuje bazy danych. Robimy to, korzystając z właściwości OriginalValues DbEntityEntry i używamy reflection do ustawiania wartości w sposób ogólny. (Działa to od EntityFramework 5.0)
/// <summary>
/// Undoes any pending updates
/// </summary>
public void UndoUpdates( DbContext dbContext )
{
//Get list of entities that are marked as modified
List<DbEntityEntry> modifiedEntityList =
dbContext.ChangeTracker.Entries().Where(x => x.State == EntityState.Modified).ToList();
foreach( DbEntityEntry entity in modifiedEntityList )
{
DbPropertyValues propertyValues = entity.OriginalValues;
foreach (String propertyName in propertyValues.PropertyNames)
{
//Replace current values with original values
PropertyInfo property = entity.Entity.GetType().GetProperty(propertyName);
property.SetValue(entity.Entity, propertyValues[propertyName]);
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-23 23:30:57
Używamy EF 4, z kontekstem obiektów starszych. Żadne z powyższych rozwiązań nie odpowiedziało na to bezpośrednio za mnie-chociaż na dłuższą metę odpowiedziało popychając mnie we właściwym kierunku.
Nie możemy po prostu pozbywać się i odbudowywać kontekstu, ponieważ niektóre obiekty, które mamy w pamięci (cholera, leniwe Ładowanie!!) są nadal przywiązane do kontekstu, ale mają dzieci, które są jeszcze do załadowania. W takich przypadkach musimy wszystko przywrócić do pierwotnych wartości bez uruchamianie bazy danych bez utraty istniejącego połączenia.
Poniżej znajduje się nasze rozwiązanie tego samego problemu:
public static void UndoAllChanges(OurEntities ctx)
{
foreach (ObjectStateEntry entry in
ctx.ObjectStateManager.GetObjectStateEntries(~EntityState.Detached))
{
if (entry.State != EntityState.Unchanged)
{
ctx.Refresh(RefreshMode.StoreWins, entry.Entity);
}
}
}
Mam nadzieję, że to pomoże innym.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-26 22:19:43
Kilka dobrych pomysłów powyżej, zdecydowałem się zaimplementować ICloneable, a następnie prostą metodę rozszerzenia.
Znalezione tutaj: Jak sklonować listę generyczną w C#?
Stosować jako:
ReceiptHandler.ApplyDiscountToAllItemsOnReciept(LocalProductsOnReciept.Clone(), selectedDisc);
W ten sposób udało mi się sklonować listę podmiotów produktu, zastosować rabat na każdy przedmiot i nie muszę się martwić o przywrócenie jakichkolwiek zmian na oryginalnym podmiocie. Nie ma potrzeby rozmawiać z DBContext i poprosić 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 i unika trafienia DB. Nie mogę powiedzieć, czy to ma hit wydajności.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:46