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.