Zapisywanie danych

Podczas wykonywania zapytań można odczytywać dane z bazy danych, zapisywanie danych oznacza dodawanie nowych jednostek do bazy danych, usuwanie jednostek lub modyfikowanie właściwości istniejących jednostek w jakiś sposób. Program Entity Framework Core (EF Core) obsługuje dwa podstawowe podejścia do zapisywania danych w bazie danych.

Podejście 1. Śledzenie zmian i Zapisywanie Zmian

W wielu scenariuszach program musi wykonać zapytanie o dane z bazy danych, wykonać pewne modyfikacje i zapisać te modyfikacje z powrotem; jest to czasami nazywane "jednostką pracy". Załóżmy na przykład, że masz zestaw blogów i chcesz zmienić Url właściwość jednego z nich. W programie EF zwykle odbywa się to w następujący sposób:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Single(b => b.Url == "http://example.com");
    blog.Url = "http://example.com/blog";
    context.SaveChanges();
}

Powyższy kod wykonuje następujące kroki:

  1. Używa zwykłego zapytania LINQ do ładowania jednostki z bazy danych (zobacz Zapytanie o dane). Zapytania ef domyślnie śledzą, co oznacza, że program EF śledzi załadowane jednostki w wewnętrznym monitorze zmian.
  2. Załadowane wystąpienie jednostki jest manipulowane jak zwykle przez przypisanie właściwości platformy .NET. Program EF nie jest zaangażowany w ten krok.
  3. DbContext.SaveChanges() Na koniec jest wywoływana. W tym momencie program EF automatycznie wykrywa wszelkie zmiany, porównując jednostki z migawką od momentu ich załadowania. Wszelkie wykryte zmiany są utrwalane w bazie danych; w przypadku korzystania z relacyjnej bazy danych zwykle wiąże się to z wysłaniem np. bazy danych SQL UPDATE w celu zaktualizowania odpowiednich wierszy.

Należy pamiętać, że powyżej opisano typową operację aktualizacji dla istniejących danych, ale podobne zasady są przechowywane do dodawania i usuwania jednostek. Możesz wchodzić w interakcję z monitorem zmian platformy EF przez wywołanie metody DbSet<TEntity>.Add i Remove, powodując śledzenie zmian. Następnie ef stosuje wszystkie śledzone zmiany do bazy danych, gdy SaveChanges() jest wywoływana (np. za pośrednictwem języka SQL INSERT i DELETE podczas korzystania z relacyjnej bazy danych).

SaveChanges() oferuje następujące korzyści:

  • Nie musisz pisać kodu, aby śledzić, które jednostki i właściwości uległy zmianie — program EF automatycznie to robi i aktualizuje tylko te właściwości w bazie danych, zwiększając wydajność. Wyobraź sobie, że załadowane jednostki są powiązane ze składnikiem interfejsu użytkownika, co umożliwia użytkownikom zmianę dowolnej właściwości; EF zabiera ciężar ustalenia, które jednostki i właściwości zostały rzeczywiście zmienione.
  • Zapisywanie zmian w bazie danych może być czasami skomplikowane! Jeśli na przykład chcesz dodać blog i niektóre wpisy dla tego bloga, może być konieczne pobranie klucza wygenerowanego przez bazę danych dla wstawionego bloga, zanim będzie można wstawić wpisy (ponieważ muszą odwoływać się do bloga). EF robi to wszystko dla Ciebie, zabierając złożoność.
  • Program EF może wykrywać problemy ze współbieżnością, takie jak w przypadku modyfikacji wiersza bazy danych przez inną osobę między zapytaniem a SaveChanges(). Więcej szczegółów można znaleźć w temacie Konflikty współbieżności.
  • W bazach danych, które ją obsługują, SaveChanges() automatycznie opakowuje wiele zmian w transakcji, zapewniając spójność danych w przypadku wystąpienia awarii. Więcej szczegółów można znaleźć w temacie Transakcje.
  • SaveChanges() ponadto dzieli wiele zmian w wielu przypadkach, co znacznie zmniejsza liczbę rund bazy danych i znacznie poprawia wydajność. Więcej szczegółów można znaleźć w temacie Efektywne aktualizowanie.

Aby uzyskać więcej informacji i przykładów kodu dotyczących podstawowego SaveChanges() użycia, zobacz Basic SaveChanges. Aby uzyskać więcej informacji na temat śledzenia zmian w programie EF, zobacz Omówienie śledzenia zmian.

Podejście 2: ExecuteUpdate i ExecuteDelete ("aktualizacja zbiorcza")

Uwaga

Ta funkcja została wprowadzona w programie EF Core 7.0.

Śledzenie zmian i SaveChanges() są zaawansowanym sposobem zapisywania zmian, ale mają pewne wady.

SaveChanges() Najpierw należy wykonać zapytanie i śledzić wszystkie jednostki, które będą modyfikowane lub usuwane. Jeśli musisz, powiedzmy, usunąć wszystkie blogi z oceną poniżej określonego progu, musisz wykonać zapytanie, zmaterializować i śledzić potencjalnie ogromną liczbę wierszy i wygenerować SaveChanges() instrukcję DELETE dla każdego z nich. Relacyjne bazy danych zapewniają znacznie wydajniejszą alternatywę: można wysłać pojedyncze DELETE polecenie, określając wiersze do usunięcia za pomocą WHERE klauzuli, ale SaveChanges() model nie zezwala na generowanie tego polecenia.

Aby obsłużyć ten scenariusz aktualizacji zbiorczej, można użyć ExecuteDelete w następujący sposób:

context.Blogs.Where(b => b.Rating < 3).ExecuteDelete();

Dzięki temu można wyrazić instrukcję SQL DELETE za pośrednictwem zwykłych operatorów LINQ — podobnie jak zwykłe zapytanie LINQ — co powoduje wykonanie następującej instrukcji SQL względem bazy danych:

DELETE FROM [b]
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Jest to wykonywane bardzo wydajnie w bazie danych bez ładowania danych z bazy danych lub angażowania monitora zmian ef. ExecuteUpdate Podobnie umożliwia wyrażenie instrukcji SQLUPDATE.

Nawet jeśli jednostki nie są zmieniane zbiorczo, możesz wiedzieć dokładnie, które właściwości jednostki chcesz zmienić. Użycie interfejsu API śledzenia zmian w celu przeprowadzenia zmiany może być nadmiernie złożone, wymagając utworzenia wystąpienia jednostki, śledzenia go za pomocą Attachmetody , wprowadzania zmian i na koniec wywoływania metody SaveChanges(). W przypadku takich scenariuszy ExecuteUpdate i ExecuteDelete może być znacznie prostszy sposób wyrażania tej samej operacji.

Na koniec zarówno śledzenie zmian, jak i SaveChanges() samo w sobie nakładają pewne nakłady pracy związane ze środowiskiem uruchomieniowym. Jeśli piszesz aplikację o wysokiej wydajności i ExecuteDelete pozwalasz uniknąć zarówno tych składników, ExecuteUpdate jak i efektywnie wygenerować odpowiednią instrukcję.

Należy jednak pamiętać, że ExecuteUpdate i ExecuteDelete mają pewne ograniczenia:

  • Te metody są wykonywane natychmiast i obecnie nie mogą być wsadowe z innymi operacjami. Z drugiej strony program SaveChanges()może wsadować wiele operacji razem.
  • Ze względu na to, że śledzenie zmian nie jest związane, musisz wiedzieć dokładnie, które jednostki i właściwości należy zmienić. Może to oznaczać więcej ręcznego śledzenia kodu niskiego poziomu, co należy zmienić i co nie.
  • Ponadto, ponieważ śledzenie zmian nie jest zaangażowane, te metody nie stosują automatycznie kontroli współbieżności podczas utrwalania zmian. Można jednak jawnie dodać klauzulę Where w celu samodzielnego zaimplementowania kontroli współbieżności.
  • Obecnie obsługiwane jest tylko aktualizowanie i usuwanie; wstawienie musi odbywać się za pomocą i DbSet<TEntity>.AddSaveChanges().

Aby uzyskać więcej informacji i przykładów kodu, zobacz ExecuteUpdate i ExecuteDelete.

Podsumowanie

Poniżej przedstawiono kilka wskazówek dotyczących tego, kiedy należy użyć tego podejścia. Należy pamiętać, że nie są to reguły bezwzględne, ale zapewniają przydatne reguły kciuka:

  • Jeśli nie wiesz wcześniej, które zmiany zostaną wprowadzone, użyj polecenia SaveChanges; automatycznie wykryje, które zmiany należy zastosować. Przykładowe scenariusze:
    • "Chcę załadować blog z bazy danych i wyświetlić formularz umożliwiający użytkownikowi zmianę"
  • Jeśli musisz manipulować grafem obiektów (tj. wieloma połączonymi obiektami), użyj metody SaveChanges; określi ona właściwą kolejność zmian i sposób łączenia wszystkich elementów.
    • "Chcę zaktualizować blog, zmieniając niektóre jego wpisy i usuwając inne"
  • Jeśli chcesz zmienić potencjalnie dużą liczbę jednostek na podstawie określonego kryterium, użyj polecenia ExecuteUpdate i ExecuteDelete. Przykładowe scenariusze:
    • "Chcę dać wszystkim pracownikom podwyżkę"
    • "Chcę usunąć wszystkie blogi, których nazwa zaczyna się od X"
  • Jeśli już wiesz, które jednostki chcesz zmodyfikować i jak chcesz je zmienić, użyj polecenia ExecuteUpdate i ExecuteDelete. Przykładowe scenariusze:
    • "Chcę usunąć blog, którego nazwa to 'Foo'"
    • "Chcę zmienić nazwę bloga o identyfikatorze 5 na "Bar"