Usuwam kilka elementów z tabeli za pomocą Entity Framework. Nie ma klucza obcego / obiektu nadrzędnego, więc nie mogę tego obsłużyć za pomocą OnDeleteCascade.
Teraz robię to:
var widgets = context.Widgets
.Where(w => w.WidgetId == widgetId);
foreach (Widget widget in widgets)
{
context.Widgets.DeleteObject(widget);
}
context.SaveChanges();
Działa, ale Foreach mnie wkurza. Używam EF4, ale nie chcę wykonywać SQL. Chcę się tylko upewnić, że niczego nie przegapię - jest tak dobry, jak to możliwe, prawda? Mogę to streścić za pomocą metody rozszerzenia lub pomocnika, ale gdzieś nadal będziemy robić foreach, prawda?
entity-framework
Jon Galloway
źródło
źródło
Odpowiedzi:
Jeśli nie chcesz bezpośrednio uruchamiać SQL, wywoływanie w pętli DeleteObject to najlepsze, co możesz zrobić dzisiaj.
Jednak możesz wykonać SQL i nadal uczynić go całkowicie ogólnym celem za pomocą metody rozszerzenia, używając podejścia, które tu opisuję .
Chociaż odpowiedź była na 3.5. W przypadku wersji 4.0 prawdopodobnie użyłbym nowego interfejsu API ExecuteStoreCommand pod maską, zamiast zejść do StoreConnection.
źródło
EntityFramework 6 sprawił, że jest to nieco łatwiejsze
.RemoveRange()
.Przykład:
źródło
Cóż, tak, ale możesz zrobić z tego dwuwarstwową:
źródło
źródło
WHERE IN ({0})
, a następnie drugi argument powinien byćString.Join(",", idList)
.EntityFramework.Extended
String.Join
, może być konieczne użyciestring.Format
i przekazanie już utworzonego ciągu SQL do polecenia. Tak długo, jak na liście znajdują się tylko liczby całkowite, nie ma ryzyka ataku iniekcyjnego. Sprawdź to pytanie: jak mogę przekazać tablicę do komendy wykonywania sklepu?Wiem, że jest już dość późno, ale na wypadek, gdyby ktoś potrzebował prostego rozwiązania, fajną rzeczą jest dodanie do niego klauzuli where:
Uwaga: właśnie przetestowano z MSSQL2008.
Aktualizacja:
Powyższe rozwiązanie nie będzie działać, gdy EF wygeneruje instrukcję SQL z parametrami , więc oto aktualizacja dla EF5 :
Wymaga trochę refleksji, ale działa dobrze.
źródło
Dla każdego używającego EF5 można użyć następującej biblioteki rozszerzeń: https://github.com/loresoft/EntityFramework.Extended
źródło
Delete()
funkcji w moich bytach w EF6.context.Widgets.Where(w => w.WidgetId == widgetId).Delete();
jest nowszym sposobem dzięki EntityFramework.ExtendedNadal wydaje się szalone, że trzeba wyciągać cokolwiek z serwera, aby je usunąć, ale przynajmniej odzyskanie samych identyfikatorów jest o wiele prostsze niż ściąganie pełnych elementów:
źródło
Widget
obiekty pośredniczące mają tylko zainicjowanąId
właściwość. Rozwiązaniem jest użyciecontext.Configuration.ValidateOnSaveEnabled = false
(przynajmniej w EF6). To wyłącza sprawdzanie poprawności Entity Framework, ale nadal wykonuje własne sprawdzanie poprawności bazy danych.delete
z podobnym obejściem dlaupdate
tworzenia bytów bez ich ładowania.EF 6.1
Stosowanie:
źródło
W przypadku EF 4.1
źródło
Możesz do tego celu użyć bibliotek rozszerzeń, takich jak EntityFramework.Extended lub Z.EntityFramework.Plus.EF6, są dostępne dla EF 5, 6 lub Core. Te biblioteki mają doskonałą wydajność, gdy trzeba je usunąć lub zaktualizować i używają LINQ. Przykład usuwania ( źródło plus ):
ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2)) .Delete();
lub ( rozszerzone źródło )
context.Users.Where(u => u.FirstName == "firstname") .Delete();
Używają natywnych instrukcji SQL, więc wydajność jest świetna.
źródło
Najszybszym sposobem na usunięcie jest użycie procedury składowanej. Wolę procedury składowane w projekcie bazy danych niż dynamiczny SQL, ponieważ nazwy będą obsługiwane poprawnie i będą miały błędy kompilatora. Dynamiczny SQL może odnosić się do tabel, które zostały usunięte / zmieniono ich nazwy, powodując błędy w czasie wykonywania.
W tym przykładzie mam dwie tabele List i ListItems. Potrzebuję szybkiego sposobu na usunięcie wszystkich ListItems z danej listy.
Teraz interesująca część usuwania elementów i aktualizowania struktury Entity za pomocą rozszerzenia.
Główny kod może teraz go używać jako
źródło
Jeśli chcesz usunąć wszystkie wiersze tabeli, możesz wykonać polecenie sql
TRUNCATE TABLE (Transact-SQL) Usuwa wszystkie wiersze z tabeli bez rejestrowania poszczególnych usuniętych wierszy. TRUNCATE TABLE jest podobna do instrukcji DELETE bez klauzuli WHERE; jednak TRUNCATE TABLE jest szybszy i zużywa mniej zasobów systemowych i dzienników transakcji.
źródło
truncate table
tabel, do których odwołuje się ograniczenie KLUCZ OBCY. (Możesz obciąć tabelę, która ma obcy klucz, który się do niej odwołuje.). Dokumentacja MSDNUUHHIVS
to bardzo elegancki i szybki sposób na usuwanie partii, ale należy go używać ostrożnie:context.SaveChanges()
Te problemy można obejść, przejmując kontrolę nad transakcją. Poniższy kod ilustruje sposób wsadowego usuwania i zbiorczego wstawiania w sposób transakcyjny:
źródło
Entity Framework Core
Podsumowanie :
Uwagi :
źródło
Możesz wykonywać zapytania SQL bezpośrednio w następujący sposób:
Do wybranych możemy użyć
źródło
Możesz także użyć metody DeleteAllOnSubmit () , przekazując wyniki do ogólnej listy zamiast do var. W ten sposób twój foreach ogranicza się do jednej linii kodu:
Prawdopodobnie nadal używa pętli wewnętrznie.
źródło
var
jest.Odpowiedź Thanh działała dla mnie najlepiej. Usunąłem wszystkie moje rekordy podczas jednej podróży do serwera. Miałem problem z wywołaniem metody rozszerzenia, więc pomyślałem, że podzielę się moim (EF 6):
Dodałem metodę rozszerzenia do klasy pomocnika w moim projekcie MVC i zmieniłem nazwę na „RemoveWhere”. Wprowadzam dbContext do moich kontrolerów, ale możesz też zrobić
using
.Wygenerowało to pojedynczą instrukcję usuwania dla grupy.
źródło
EF 6. =>
źródło
Najlepsza :
in EF6 => .RemoveRange()
Przykład:
źródło
Zobacz odpowiedź „ulubiony kawałek kodu”, która działa
Oto jak go użyłem:
źródło
W EF 6.2 działa to doskonale, wysyłając usunięcie bezpośrednio do bazy danych bez uprzedniego ładowania podmiotów:
Przy ustalonym predykacie jest to dość proste:
A jeśli potrzebujesz predykatu dynamicznego, zapoznaj się z LINQKit (dostępny pakiet Nuget), w moim przypadku coś takiego działa dobrze:
źródło
Z.EntityFramework.Plus
lub coś podobnego? ( entityframework.net/batch-delete )Delete()
metoda z natury nie istnieje).