Uruchamiam kod korekcyjny, który działa na dużym stosie jednostek, ponieważ jego prędkość maleje, to znaczy, ponieważ liczba śledzonych obiektów w kontekście rośnie z każdą iteracją, może to zająć dużo czasu, więc zapisuję zmiany na końcu każdej iteracji. Każda iteracja jest niezależna i nie zmienia wcześniej załadowanych jednostek.
Wiem, że mogę wyłączyć śledzenie zmian, ale nie chcę, ponieważ nie jest to kod wstawiania zbiorczego, ale ładowanie encji i obliczanie kilku rzeczy i jeśli liczby są nieprawidłowe ustaw nowe liczby i zaktualizuj / usuń / utwórz kilka dodatkowych podmiotów. Wiem, że mogę utworzyć nowy DbContext dla każdej iteracji i prawdopodobnie działałoby to szybciej niż robienie wszystkiego w tej samej instancji, ale myślę, że może być lepszy sposób.
Więc pytanie brzmi; Czy istnieje sposób na wyczyszczenie jednostek załadowanych wcześniej w kontekście bazy danych?
źródło
context.Entry(entity).State = EntityState.Detached
i przestanie śledzić tę konkretną jednostkę.Odpowiedzi:
Możesz dodać metodę do swojej
DbContext
lub metody rozszerzenia, która używa ChangeTracker do odłączenia wszystkich jednostek Added, Modified i Deleted:public void DetachAllEntities() { var changedEntriesCopy = this.ChangeTracker.Entries() .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted) .ToList(); foreach (var entry in changedEntriesCopy) entry.State = EntityState.Detached; }
źródło
var entity
powinno byćvar entry
tak, jak jest to wpis, a nie rzeczywisty Podmiot)1. Możliwość: wypięcie wjazdu
Po odłączeniu wpisu moduł śledzenia zmian przestanie go śledzić (i powinien skutkować lepszą wydajnością)
Zobacz: http://msdn.microsoft.com/de-de/library/system.data.entitystate(v=vs.110).aspx
2. Możliwość: praca z własnym
Status
polem + rozłączonymi kontekstamiMoże chcesz niezależnie kontrolować status swojej encji, aby móc używać odłączonych wykresów. Dodaj właściwość dla statusu jednostki i przekształć ten status w
dbContext.Entry(entity).State
podczas wykonywania operacji (użyj do tego repozytorium)public class Foo { public EntityStatus EntityStatus { get; set; } } public enum EntityStatus { Unmodified, Modified, Added }
Zobacz poniższy link, aby zapoznać się z przykładem: https://www.safaribooksonline.com/library/view/programming-entity-framework/9781449331825/ch04s06.html
źródło
Używam usługi systemu Windows, która aktualizuje wartości co minutę i miałem ten sam problem. Próbowałem uruchomić rozwiązanie @DavidSherrets, ale po kilku godzinach to również zwolniło. Moim rozwiązaniem było po prostu utworzenie nowego kontekstu, takiego jak ten dla każdego nowego przebiegu. Proste, ale działa.
_dbContext = new DbContext();
źródło
Właśnie natknąłem się na ten problem i ostatecznie natknąłem się na lepsze rozwiązanie dla osób korzystających z typowego wstrzykiwania zależności .NET Core. Dla każdej operacji można użyć zakresu DbContext. To zresetuje się,
DbContext.ChangeTracker
abySaveChangesAsync()
nie ugrzęznąć w sprawdzaniu jednostek z poprzednich iteracji. Oto przykładowa metoda kontrolera ASP.NET Core:/// <summary> /// An endpoint that processes a batch of records. /// </summary> /// <param name="provider">The service provider to create scoped DbContexts. /// This is injected by DI per the FromServices attribute.</param> /// <param name="records">The batch of records.</param> public async Task<IActionResult> PostRecords( [FromServices] IServiceProvider provider, Record[] records) { // The service scope factory is used to create a scope per iteration var serviceScopeFactory = provider.GetRequiredService<IServiceScopeFactory>(); foreach (var record in records) { // At the end of the using block, scope.Dispose() will be called, // release the DbContext so it can be disposed/reset using (var scope = serviceScopeFactory.CreateScope()) { var context = scope.ServiceProvider.GetService<MainDbContext>(); // Query and modify database records as needed await context.SaveChangesAsync(); } } return Ok(); }
Biorąc pod uwagę, że projekty ASP.NET Core zwykle używają DbContextPool, nie powoduje to nawet tworzenia / niszczenia obiektów DbContext. (Na wypadek, gdybyś był zainteresowany, DbContextPool faktycznie wywołuje
DbContext.ResetState()
iDbContext.Resurrect()
, ale nie polecałbym wywoływać ich bezpośrednio z twojego kodu, ponieważ prawdopodobnie zmienią się w przyszłych wersjach.) Https://github.com/aspnet/EntityFrameworkCore/blob/v2 .2.1 / src / EFCore / Internal / DbContextPool.cs # L157źródło
Z EF Core 3,0 istnieje wewnętrzny interfejs API, który może zresetować ChangeTracker. Nie używaj tego w kodzie produkcyjnym, wspominam o tym, ponieważ może to pomóc komuś w testowaniu w zależności od scenariusza.
using Microsoft.EntityFrameworkCore.Internal; _context.GetDependencies().StateManager.ResetState();
Jak mówi komentarz do kodu;
źródło
EntityFramework Core 5,0 wprowadził nową metodę czyszczenia śledzonych zmian.
https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.changetracking.changetracker.clear?view=efcore-5.0
źródło
Cóż, moim zdaniem, z mojego doświadczenia wynika, że EF lub bycie jakimkolwiek orm nie działa dobrze pod zbyt dużą presją lub złożonym modelem.
Jeśli nie chcesz śledzić, naprawdę powiedziałbym, dlaczego w ogóle robisz orm?
Jeśli główną siłą jest szybkość, nic nie przebije procedur składowanych i dobrego indeksowania.
A poza tym, jeśli twoje zapytania są zawsze według identyfikatora, rozważ użycie nosql lub sql z tylko kluczem i json. Pozwoliłoby to uniknąć problemu impedancji między klasami i tabelami.
W twoim przypadku ładowanie rzeczy w obiektach w ten sposób wydaje mi się bardzo powolne. Naprawdę w twoim przypadku procedury składowane są lepsze, ponieważ unikasz przesyłania danych przez sieć, a sql jest znacznie szybszy i zoptymalizowany pod kątem zarządzania agregacją i tym podobnymi.
źródło