Jak usunąć obiekt według identyfikatora za pomocą struktury jednostki


105

Wydaje mi się, że muszę pobrać obiekt, zanim go usunę za pomocą struktury encji, jak poniżej

var customer = context.Customers.First(c => c.Id == 1);

context.DeleteObject(customer);

context.Savechanges();

Więc muszę dwukrotnie trafić do bazy danych. Czy jest łatwiejszy sposób?


j.mp/f0x0Bh to Twoja odpowiedź. To miły i ogólny sposób na zrobienie tego
BritishDeveloper

Odpowiedzi:


94

W Entity Framework 6 akcja usuwania to Remove. Oto przykład

Customer customer = new Customer () { Id = id };
context.Customers.Attach(customer);
context.Customers.Remove(customer);
context.SaveChanges();

16
Dlaczego Attach? Dlaczego nie tylko Removei SaveChanges?
runeks

3
Musisz dołączyć swój podmiot w kontekście, ponieważ jeśli tego nie zrobisz, podczas usuwania pojawi się błąd. EF może usuwać jednostki tylko w tym kontekście
Pierre-Luc

3
@runeks zgodnie z instrukcją, jednostka musi istnieć w kontekście, zanim będzie można wykonać operację usuwania. Zobacz tutaj docs.microsoft.com/en-us/dotnet/api/…
dwkd

1
nie
użyłem

58

To samo co @Nix z małą zmianą do silnego wpisania:

Jeśli nie chcesz wykonywać zapytań, po prostu utwórz jednostkę, a następnie ją usuń.

                Customer customer = new Customer () { Id = id };
                context.Customers.Attach(customer);
                context.Customers.DeleteObject(customer);
                context.SaveChanges();

7
Nie jest doskonały, ponieważ zgłasza wyjątek, jeśli brakuje obiektu: „DbUpdateConcurrencyException: Instrukcja aktualizacji, wstawiania lub usuwania magazynu wpłynęła na nieoczekiwaną liczbę wierszy (0)”. Chciałbym, żeby to zignorował, tak jak zrobiłaby to instrukcja DELETE.
Dunc

przepraszam, powoduje to walidację, która nie jest zawsze potrzebna i oczekiwana!
Hamed Zakery Miab,

32

Podobne pytanie tutaj .

W przypadku Entity Framework istnieje EntityFramework-Plus (biblioteka rozszerzeń).
Dostępne w NuGet. Następnie możesz napisać coś takiego:

// DELETE all users which has been inactive for 2 years
ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2))
     .Delete();

Jest również przydatny do usuwania zbiorczego.


37
Jest to sprzeczne z powodem, że nie jest to teraz część podstawowej biblioteki EF.
nathanchere

1
@FerretallicA - zgodził się.
akarlon

2
ta metoda jest przestarzała use: context.Users.Where (user => user.Id == id) .Delete ();
Manuel,

Nie działa z Azure SQL DataWarehouse z powodu błędu „Klauzula FROM nie jest obecnie obsługiwana w instrukcji DELETE”. Ale surowy kod SQL, jak w odpowiedzi Jonika, działa.
Michael Freidgeim,

1
Czy jest potrzebna funkcja context.SaveChanges ()?
Tomas Kubes

23

Jeśli nie chcesz zapytać o to, po prostu utwórz jednostkę, a następnie ją usuń.

Customer customer  = new Customer() {  Id = 1   } ; 
context.AttachTo("Customers", customer);
context.DeleteObject(customer);
context.Savechanges();

6

W jednym z moich projektów używam następującego kodu:

    using (var _context = new DBContext(new DbContextOptions<DBContext>()))
    {
        try
        {
            _context.MyItems.Remove(new MyItem() { MyItemId = id });
            await _context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            if (!_context.MyItems.Any(i => i.MyItemId == id))
            {
                return NotFound();
            }
            else
            {
                throw ex;
            }
        }
    }

W ten sposób dwukrotnie wysyła zapytanie do bazy danych tylko wtedy, gdy wystąpi wyjątek podczas próby usunięcia elementu o określonym identyfikatorze. Następnie, jeśli element nie zostanie znaleziony, zwraca znaczący komunikat; w przeciwnym razie po prostu odrzuca wyjątek z powrotem (możesz to obsłużyć w sposób bardziej dopasowany do twojego przypadku, używając różnych bloków catch dla różnych typów wyjątków, dodaj więcej niestandardowych sprawdzeń za pomocą bloków if itp.).

[Używam tego kodu w projekcie MVC .Net Core / .Net Core z Entity Framework Core.]


2

Przypuszczam, że surowe zapytanie sql jest najszybszym sposobem

public void DeleteCustomer(int id)
{
   using (var context = new Context())
   {
      const string query = "DELETE FROM [dbo].[Customers] WHERE [id]={0}";
      var rows = context.Database.ExecuteSqlCommand(query,id);
      // rows >= 1 - count of deleted rows,
      // rows = 0 - nothing to delete.
   }
}

19
To mija się z celem używania silnie typizowanej funkcji obiektów w EF.
LawMan

4
To naraża pieniądze na tożsamość EF. Po tym EF nadal wróci do Ciebie usunięta jednostka.
epox

1
Działa z Azure SQL DataWarehouse, gdy inne rozwiązania nie.
Michael Freidgeim,

1
Jeśli to robisz, równie dobrze możesz nie używać ORM. Wyobrażam sobie, że zagroziłoby to pamięci podręcznej EF.
Storm Muller

Ten styl jest podatny na ataki typu SQL Injection. W tym konkretnym przykładzie jesteś chroniony, ponieważ zmienna jest liczbą całkowitą, ale nigdy nie używaj tego wzorca ze zmienną łańcuchową.
thelem

2

Odpowiedź dwkd działała głównie dla mnie w rdzeniu Entity Framework, z wyjątkiem sytuacji, gdy widziałem ten wyjątek:

InvalidOperationException: nie można śledzić wystąpienia typu jednostki „Klient”, ponieważ jest już śledzone inne wystąpienie z tą samą wartością klucza dla {„Id”}. Podczas dołączania istniejących jednostek upewnij się, że dołączone jest tylko jedno wystąpienie jednostki z daną wartością klucza. Rozważ użycie „DbContextOptionsBuilder.EnableSensitiveDataLogging”, aby wyświetlić sprzeczne wartości klucza.

Aby uniknąć wyjątku, zaktualizowałem kod:

Customer customer = context.Customers.Local.First(c => c.Id == id);
if (customer == null) {
    customer = new Customer () { Id = id };
    context.Customers.Attach(customer);
}
context.Customers.Remove(customer);
context.SaveChanges();

2

Mniejsza wersja (w porównaniu do poprzednich):

var customer = context.Find(id);
context.Delete(customer);
context.SaveChanges();

Proszę podać kontekst tego fragmentu kodu i być może wyjaśnienie, co robi lepiej niż inne odpowiedzi pozostawione w ostatniej dekadzie.
miken32

1

Ta odpowiedź jest faktycznie zaczerpnięta z kursu Scotta Allena zatytułowanego ASP.NET MVC 5 Fundamentals. Pomyślałem, że podzielę się tym, ponieważ uważam, że jest to nieco prostsze i bardziej intuicyjne niż jakakolwiek z odpowiedzi już tutaj. Należy również zauważyć, że według Scotta Allena i innych przeprowadzonych przeze mnie szkoleń metoda znajdowania jest zoptymalizowanym sposobem pobierania zasobu z bazy danych, który może korzystać z buforowania, jeśli został już pobrany. W tym kodzie kolekcja odnosi się do DBSet obiektów. Obiekt może być dowolnym ogólnym typem obiektu.

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.