Come eliminare un oggetto per id con entity framework


105

Mi sembra di dover recuperare un oggetto prima di eliminarlo con Entity Framework come di seguito

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

context.DeleteObject(customer);

context.Savechanges();

Quindi devo premere il database due volte. C'è un modo più semplice?


j.mp/f0x0Bh è la tua risposta. Questo è un modo carino e generico per farlo
BritishDeveloper

Risposte:


93

In Entity Framework 6 l'azione di eliminazione è Remove. Ecco un esempio

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

16
Perché Attach? Perché non solo Removee SaveChanges?
runek

3
Devi allegare la tua entità nel contesto perché se non lo fai, riceverai un errore durante la rimozione. EF può rimuovere entità solo in questo contesto
Pierre-Luc

3
@runeks secondo il manuale l'entità deve esistere nel contesto prima di poter eseguire l'operazione di rimozione. Vedere qui docs.microsoft.com/en-us/dotnet/api/…
dwkd

1
Non ho usato l'allegato e funziona bene
ILIAS M. DOLAPO il

58

Lo stesso di @Nix con una piccola modifica da digitare in modo forte:

Se non si desidera eseguire una query, creare un'entità e quindi eliminarla.

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

7
Non perfetto in quanto genera un'eccezione se l'oggetto è mancante: "DbUpdateConcurrencyException: l'istruzione di aggiornamento, inserimento o eliminazione dell'archivio ha interessato un numero imprevisto di righe (0)." Mi piacerebbe che lo ignorasse, come farebbe un'istruzione DELETE.
Dunc

scusa, questo causa una convalida che non è necessaria e prevista sempre!
Hamed Zakery Miab

32

Domanda simile qui .

Con Entity Framework c'è EntityFramework-Plus (libreria di estensioni).
Disponibile su NuGet. Quindi puoi scrivere qualcosa come:

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

È utile anche per le eliminazioni in blocco.


36
Sfida la ragione per cui questo non fa parte della libreria EF di base ormai.
nathanchere

1
@FerretallicA - d'accordo.
acarlon

2
questo metodo è un uso obsoleto: context.Users.Where (user => user.Id == id) .Delete ();
Manuel

Non funziona con Azure SQL DataWarehouse a causa dell'errore "Una clausola FROM non è attualmente supportata in un'istruzione DELETE". Ma l'SQL grezzo come nella risposta di Jonik funziona.
Michael Freidgeim,

1
È necessario context.SaveChanges ()?
Tomas Kubes

23

Se non si desidera eseguire una query, creare un'entità e quindi eliminarla.

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

6

Sto usando il seguente codice in uno dei miei progetti:

    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;
            }
        }
    }

In questo modo, interrogherà il database due volte solo se si verifica un'eccezione durante il tentativo di rimuovere l'elemento con l'ID specificato. Quindi, se l'elemento non viene trovato, restituisce un messaggio significativo; altrimenti, restituisce semplicemente l'eccezione (puoi gestirla in un modo più adatto al tuo caso utilizzando diversi blocchi catch per diversi tipi di eccezione, aggiungere più controlli personalizzati utilizzando i blocchi if ecc.).

[Sto usando questo codice in un progetto MVC .Net Core / .Net Core con Entity Framework Core.]


2

La query sql grezza è il modo più veloce suppongo

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
Ciò vanifica lo scopo dell'uso della funzionalità di oggetti fortemente tipizzati in EF.
LawMan

4
Ciò compromette i contanti di identità EF. Dopo questo EF ti restituirà ancora l'entità eliminata.
epossidica

1
Funziona con Azure SQL DataWarehouse, quando altre soluzioni non lo fanno.
Michael Freidgeim,

1
Se lo fai, potresti anche non utilizzare un ORM. Immagino che ciò comprometterebbe la cache EF.
Storm Muller

Questo stile è vulnerabile agli attacchi SQL Injection. In questo esempio specifico sei protetto perché la variabile è un numero intero, ma non utilizzare mai questo modello con una variabile stringa.
thelem

2

La risposta di dwkd ha funzionato principalmente per me nel core di Entity Framework, tranne quando ho visto questa eccezione:

InvalidOperationException: impossibile tenere traccia dell'istanza del tipo di entità "Customer" perché è già stata tracciata un'altra istanza con lo stesso valore di chiave per {"Id"}. Quando si collegano entità esistenti, assicurarsi che sia allegata solo un'istanza di entità con un determinato valore chiave. Prendi in considerazione l'utilizzo di "DbContextOptionsBuilder.EnableSensitiveDataLogging" per visualizzare i valori delle chiavi in ​​conflitto.

Per evitare l'eccezione, ho aggiornato il codice:

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

Una versione più piccola (rispetto alle precedenti):

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

Fornisci un contesto a questo frammento di codice e forse una spiegazione di ciò che fa meglio delle altre risposte rimaste negli ultimi dieci anni.
miken32

1

Questa risposta è in realtà presa dal corso di Scott Allen intitolato ASP.NET MVC 5 Fundamentals. Ho pensato di condividerlo perché penso che sia leggermente più semplice e più intuitivo di tutte le risposte già qui. Nota anche, secondo Scott Allen e altri corsi di formazione che ho fatto, il metodo find è un modo ottimizzato per recuperare una risorsa dal database che può utilizzare la memorizzazione nella cache se è già stata recuperata. In questo codice, la raccolta fa riferimento a un DBSet di oggetti. L'oggetto può essere qualsiasi tipo di oggetto generico.

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.