2009-05-15 14 views
74

¿Hay alguna forma de eliminar de forma masiva un grupo de objetos que coincidan con una consulta determinada en LINQ o LINQ-to-Entities? Las únicas referencias que puedo encontrar están desactualizadas, y parece tonto iterar y eliminar manualmente todos los objetos que deseo eliminar.Supresión masiva en LINQ a entidades

Respuesta

28

La pregunta es anterior (antes de que EF5 existiera). Para cualquiera que esté usando EF5, EntityFramework.Extended hace esto en un instante.

+1

Gracias. He actualizado esta para ser la respuesta aceptada. –

+1

EF 6 'RemoveRange' http://stackoverflow.com/a/21468165/1876572 – Eldho

3

Conozco el método DeleteAllOnSubmit de cualquier contexto de datos que eliminará todos los registros en la consulta. Debe haber cierta optimización subyacente ya que muchos objetos se están eliminando. No estoy seguro sin embargo.

+2

Realmente no se realiza ninguna optimización. El SQL generado enumera todos los objetos que coinciden con su consulta, y luego itera manualmente sobre ellos para eliminarlos. Por supuesto, la iteración ocurre en el DB, en lugar de en tu código, pero aún estás construyendo innecesariamente un conjunto de resultados simplemente para eliminar su contenido, todavía mucho peor que un simple "ELIMINAR DE la tabla DONDE foo = barra", que construye no hay conjunto de resultados y cubre la tabla solo una vez. –

2

no estoy seguro de qué tan eficiente que sería, pero usted podría intentar algo como esto:

// deletes all "People" with the name "Joe" 
var mypeople = from p in myDataContext.People 
       where p.Name == "Joe"; 
       select p; 
myDataContext.People.DeleteAllOnSubmit(mypeople); 
myDataContext.SubmitChanges(); 
+0

Eso aún termina iterando sobre todos los elementos que coinciden con la consulta; simplemente lo hace en la base de datos, en lugar de hacerlo en tu código. Más eficiente, pero aún lejos de ser una solución ideal. –

+2

La única otra manera que podría pensar para hacerlo, entonces, sería hacer myDataContext.ExecuteCommand ("DELETE ...") ;. Lejos de ideal, también, pero funcionaría. –

1

Se puede escribir un procedimiento almacenado que realiza el borrado y llamarlo desde LINQ. En general, una eliminación basada en conjunto es más rápida, pero si afecta a demasiados registros podría causar problemas de bloqueo y es posible que necesite un híbrido de bucles a través de conjuntos de registros (tal vez 2000 a la vez, el tamaño depende del diseño de su base de datos pero 2000 es lugar de inicio si considera que el delte basado en conjunto tarda tanto en afectar el uso de la tabla) para realizar la eliminación.

53

Hace un tiempo escribí una serie de blog de 4 partes (partes 1, 2, 3 y 4) que cubren haciendo actualizaciones masivas (con un comando) en el marco de la entidad.

Si bien el foco de esa serie era la actualización, definitivamente podría usar los principios implicados para hacer la eliminación.

Por lo que debe ser capaz de escribir algo como esto:

var query = from c in ctx.Customers 
      where c.SalesPerson.Email == "..." 
      select c; 

query.Delete(); 

Todo lo que necesita hacer es poner en práctica el método de extensión de eliminación(). Ver la línea de postes en busca de pistas sobre cómo ...

Esperanza esto ayuda

+0

Excelente serie. Escribir un método de extensión Delete() basado en esto será trivial. –

+15

Sería bueno tener una muestra de código aquí si alguien lo tiene. – jocull

+1

Puede encontrar una gran cantidad de métodos de extensión (incluida una eliminación por lotes) aquí: https://github.com/loresoft/EntityFramework.Extended – Soliah

6

Las respuestas que estoy viendo aquí son LINQ to SQL

DeleteAllOnSubmit es parte de System.Data.Linq y que es ITable Linq a Sql

Esto no se puede hacer con Entity Framework.

Habiendo dicho todo eso no tengo una solución, pero todavía volver a publicar cuando lo haga

38
using (var context = new DatabaseEntities()) 
    { 
     // delete existing records 
     context.ExecuteStoreCommand("DELETE FROM YOURTABLE WHERE CustomerID = {0}", customerId); 
    } 
+3

+1 - Es bueno ver un ejemplo de código de cómo ejecutar el código SQL usando EF –

+1

Me doy cuenta de que esta es probablemente la única forma de hacer esto, salvo crear un procedimiento almacenado, pero parece una trampa =). Ahora que estoy usando esto, me siento tentado de usarlo en varios otros lugares para cicumvent la extravagancia de EF, como las complejas combinaciones de la izquierda y bys del grupo ... :) – Losbear

+0

+! ... cuando se usa una base de datos , encontrarás que la herramienta que deseas es un destornillador. EF es solo otro martillo. – gbjbaanb

1

Eliminación de datos a través del marco de la entidad se basa en el uso del método DeleteObject. Puede invocar este método en EntityCollection para la clase de entidad que desea eliminar o en ObjectContext derivado. Aquí hay un ejemplo simple:

NorthwindEntities db = new NorthwindEntities(); 

IEnumerable<Order_Detail> ods = from o in db.Order_Details 
           where o.OrderID == 12345          
           select o; 

foreach (Order_Detail od in ods) 
    db.Order_Details.DeleteObject(od); 

db.SaveChanges(); 
+0

Sin embargo, eso no es "Bulk Delete". – Nuzzolilo

4

Para aquellos que utilizan EF6 y quieren ejecutar fila consulta SQL para su eliminación:

using (var context = new DatabaseEntities()) 
{ 
    // delete existing records 
    context.Database.ExecuteSqlCommand("DELETE FROM YOURTABLE WHERE CustomerID = @id", idParameter); 
} 
+1

Esto funcionó para mí en EF 5 pero tuve que usar @ p0 para el parámetro.Lo bueno es que proporciona param type seguro de comprobar en el SQL generado: por lo que en EF5, esto funcionaría: context.Database.ExecuteSqlCommand ("BORRADO DE YourTable DONDE CustomerID = @ P0", idParameter); \ @ P1 para el próximo parámetro, etc ... –

1

me gustaría hacer algo como:

var recordsToDelete = (from c in db.Candidates_T where c.MyField == null select c).ToList<Candidates_T>(); 
if(recordsToDelete.Count > 0) 
{ 
    foreach(var record in recordsToDelete) 
    { 
     db.Candidate_T.DeleteObject(record); 
     db.SaveChanges(); 
    } 
} 

No creo que hay una manera de hazlo sin un bucle ya que Entity Framework funciona con Entidades y la mayoría de las veces, esto significa colección de objetos.

+1

Algo como esto trabajó para mí. – Demodave

+0

Puedes compartir lo que hiciste también. Gracias. –

+0

@G Jeny Ramirez Agregué mi solución. – Demodave

1

En este ejemplo, obtengo los registros para eliminar, y uno a uno los adjunta al conjunto de resultados y luego solicito que se eliminen. Entonces tengo 1 guardar cambios.

using (BillingDB db = new BillingDB()) 
    { 
     var recordsToDelete = (from i in db.sales_order_item 
        where i.sales_order_id == shoppingCartId 
        select i).ToList<sales_order_item>(); 

     if(recordsToDelete.Count > 0) 
     { 
     foreach (var deleteSalesOrderItem in recordsToDelete) 
     {     
      db.sales_order_item.Attach(deleteSalesOrderItem); 
      db.sales_order_item.Remove(deleteSalesOrderItem);     
     } 
     db.SaveChanges(); 
     } 
    } 
1
context.Entity.Where(p => p.col== id) 
       .ToList().ForEach(p => db.Entity.DeleteObject(p)); 

ellos es el método más rápido para eliminar el registro de la base de datos usando EF

0

removeRange se introdujo en EF6, se puede eliminar una lista de objetos. Muy facil.

var origins= (from po in db.PermitOrigins where po.PermitID == thisPermit.PermitID select po).ToList(); 
db.PermitOrigins.RemoveRange(origins); 
db.SaveChanges(); 
+1

Mientras que este fragmento de código puede resolver la cuestión, [incluyendo una explicación] (http: //meta.stackexchange .com/questions/114762/explaining-entirely-code-based-answers) realmente ayuda a mejorar la calidad de su publicación. Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. – DimaSan