Cómo eliminar un objeto por id con el marco de la entidad

105

Me parece que tengo que recuperar un objeto antes de eliminarlo con el marco de la entidad como se muestra a continuación

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

context.DeleteObject(customer);

context.Savechanges();

Entonces necesito ingresar a la base de datos dos veces. ¿Existe una forma más sencilla?

Jeff
fuente
j.mp/f0x0Bh es tu respuesta. Esta es una forma agradable y genérica de hacerlo
Desarrollador británico

Respuestas:

93

En Entity Framework 6, la acción de eliminación es Remove. Aquí hay un ejemplo

Customer customer = new Customer () { Id = id };
context.Customers.Attach(customer);
context.Customers.Remove(customer);
context.SaveChanges();
dwkd
fuente
16
¿Por qué Attach? ¿Por qué no solo Removey SaveChanges?
runas
3
Debe adjuntar su entidad en el contexto porque si no lo hace, recibirá un error al eliminar. EF puede eliminar entidades solo en este contexto
Pierre-Luc
3
@runeks según el manual, la entidad debe existir en el contexto antes de que se pueda realizar la operación Eliminar. Vea aquí docs.microsoft.com/en-us/dotnet/api/…
dwkd
1
No
usé
58

Lo mismo que @Nix con un pequeño cambio para ser fuertemente tipado:

Si no desea consultarlo, simplemente cree una entidad y luego elimínela.

                Customer customer = new Customer () { Id = id };
                context.Customers.Attach(customer);
                context.Customers.DeleteObject(customer);
                context.SaveChanges();
Sawan
fuente
7
No es perfecto, ya que genera una excepción si falta el objeto: "DbUpdateConcurrencyException: la declaración de actualización, inserción o eliminación de la tienda afectó a un número inesperado de filas (0)". Me gustaría que ignorara esto, como lo haría una declaración DELETE.
Dunc
lo siento, esto provoca una validación que no es necesaria y que siempre se espera.
Hamed Zakery Miab
32

Pregunta similar aquí .

Con Entity Framework existe EntityFramework-Plus (biblioteca de extensiones).
Disponible en NuGet. Entonces puedes escribir algo como:

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

También es útil para eliminaciones masivas.

acarlon
fuente
36
Desafía la razón por la que esto no es parte de la biblioteca principal de EF por ahora.
nathanchere
1
@FerretallicA - estuvo de acuerdo.
acarlon
2
este método es obsoleto uso: context.Users.Where (user => user.Id == id) .Delete ();
Manuel
No funciona con Azure SQL DataWarehouse debido al error "Actualmente no se admite una cláusula FROM en una instrucción DELETE". Pero el SQL en bruto como en la respuesta de Jonik funciona.
Michael Freidgeim
1
¿Es necesario context.SaveChanges ()?
Tomas Kubes
23

Si no desea consultarlo, simplemente cree una entidad y luego elimínela.

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

Estoy usando el siguiente código en uno de mis proyectos:

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

De esta manera, consultará la base de datos dos veces solo si ocurre una excepción al intentar eliminar el elemento con el ID especificado. Luego, si no se encuentra el elemento, devuelve un mensaje significativo; de lo contrario, simplemente devuelve la excepción (puede manejar esto de una manera más adecuada a su caso usando diferentes bloques de captura para diferentes tipos de excepciones, agregue más verificaciones personalizadas usando bloques if, etc.).

[Estoy usando este código en un proyecto MVC .Net Core / .Net Core con Entity Framework Core.]

demoníaco
fuente
2

La consulta sql sin procesar es la forma más rápida, supongo

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.
   }
}
Jonik
fuente
19
Esto frustra el propósito de usar la funcionalidad de objetos fuertemente tipados en EF.
LawMan
4
Esto compromete el efectivo de identidad de EF. Después de esto, EF todavía le devolverá su entidad eliminada.
epox
1
Funciona con Azure SQL DataWarehouse, cuando otras soluciones no lo hacen.
Michael Freidgeim
1
Si está haciendo esto, es mejor que no use un ORM. Imagino que esto comprometería el caché EF.
Storm Muller
Este estilo es vulnerable a los ataques de inyección SQL. En este ejemplo específico, está protegido porque la variable es un número entero, pero nunca use este patrón con una variable de cadena.
thelem
2

La respuesta de dwkd funcionó principalmente para mí en el núcleo de Entity Framework, excepto cuando vi esta excepción:

InvalidOperationException: la instancia del tipo de entidad 'Cliente' no se puede rastrear porque ya se está rastreando otra instancia con el mismo valor de clave para {'Id'}. Al adjuntar entidades existentes, asegúrese de que solo se adjunte una instancia de entidad con un valor clave determinado. Considere usar 'DbContextOptionsBuilder.EnableSensitiveDataLogging' para ver los valores clave en conflicto.

Para evitar la excepción, actualicé el código:

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();
Jeffrey Rennie
fuente
1

Una versión más pequeña (en comparación con las anteriores):

var customer = context.Find(id);
context.Delete(customer);
context.SaveChanges();
Luis Gouveia
fuente
Proporcione algo de contexto a este fragmento de código y quizás alguna explicación de lo que hace mejor que las otras respuestas que se dejaron en la última década.
miken32
1

Esta respuesta en realidad se tomó del curso de Scott Allen titulado ASP.NET MVC 5 Fundamentals. Pensé en compartirlo porque creo que es un poco más simple e intuitivo que cualquiera de las respuestas aquí. También tenga en cuenta que según Scott Allen y otros entrenamientos que he realizado, el método de búsqueda es una forma optimizada de recuperar un recurso de la base de datos que puede usar el almacenamiento en caché si ya se ha recuperado. En este código, colección se refiere a un DBSet de objetos. El objeto puede ser cualquier tipo de objeto genérico.

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();
andy_coder
fuente