¿Eliminar un solo registro de Entity Framework?

195

Tengo una tabla de SQL Server en Entity Framework employcon una sola columna de clave llamada ID.

¿Cómo elimino un solo registro de la tabla con Entity Framework?

usuario2497476
fuente
2
db.employ.Remove (db.employ.Find (ID1))
Carter Medlin
2
@CarterMedlin: si bien eso funcionará, son dos visitas a la base de datos: una SELECCIONAR y una ELIMINAR. La mayoría de las personas considera que es un gran desperdicio, especialmente porque seleccionar probablemente tomará mucho más tiempo que una eliminación.
Davor
No sugeriría usar el marco de entidades Remove o RemoveRange debido a los problemas de rendimiento. Prefiero usar algo súper simple como sigue: var sql = "ELIMINAR DE TU_TABLE DONDE YOUR_FIELD = @your_parameter"; this.your_context.Database.ExecuteSqlCommand (sql, new SqlParameter ("@ your_parameter", yourParameter));
curiousBoy
2
@curiousBoy Creo que cuando ejecutas declaraciones como sugeriste, el caché EF6 no refleja el cambio.
Itzjak

Respuestas:

362

No es necesario consultar primero el objeto, puede adjuntarlo al contexto por su id. Me gusta esto:

var employer = new Employ { Id = 1 };
ctx.Employ.Attach(employer);
ctx.Employ.Remove(employer);
ctx.SaveChanges();

Alternativamente, puede establecer el estado de la entrada adjunta en eliminado:

var employer = new Employ { Id = 1 };
ctx.Entry(employer).State = EntityState.Deleted;
ctx.SaveChanges();
mt_serg
fuente
87
Alternativamente,ctx.Entry(employer).State = EntityState.Deleted
Simon Belanger
12
esto solo funcionará si las relaciones se definen como borrar cascada. de lo contrario, el código anterior fallará en una excepción FK.
baruchl
66
@mt_serg, estoy mirando 3 pasos adelante. ¿Cuándo fue la última vez que realmente tuvo que eliminar un registro tan simple de la base de datos? generalmente se trata de registros más complejos que incluyen relaciones FK. De ahí mi comentario.
baruchl
2
@IanWarburton La segunda y tercera línea (Adjuntar y quitar)
Simon Belanger
44
@PaulZahra: a veces tiene una lista de ID de alguna otra consulta o fuente, y necesita eliminar una. En lugar de cargar los objetos solo para eliminarlos, de esta manera puede eliminarlos por ID. Ya sabes, así es como funciona normalmente la instrucción DELETE en SQL.
siride
82

Puede usar SingleOrDefaultpara obtener un solo objeto que coincida con sus criterios, y luego pasarlo al Removemétodo de su tabla EF.

var itemToRemove = Context.Employ.SingleOrDefault(x => x.id == 1); //returns a single item.

if (itemToRemove != null) {
    Context.Employ.Remove(itemToRemove);
    Context.SaveChanges();
}
Mansfield
fuente
55
¡Esta no es una buena manera, porque está seleccionando todos los campos de la base de datos!
Ali Yousefi
2
Así es como lo hago.
Jack Fairfield
44
@ Ali, Jack - Pero creo que esto es preferible porque primero verifica si los datos que está tratando de eliminar realmente existen, lo que puede evitar problemas. La respuesta aceptada no tiene verificación como tal.
Michael Philips
44
Esta es la mejor manera. Piénsalo. ¿Qué sucede si John Smith está tratando de eliminar un elemento con un id = 1 que Susie Smith eliminó hace 30 segundos pero John no lo sabe? Necesita golpear la base de datos en ese caso.
Yusha
44
@Yusha ¿Por qué? En ambos escenarios, el resultado es que el registro se ha ido. ¿Realmente nos importa si eso sucedió ahora o hace 30 segundos? Algunas condiciones de carrera simplemente no son tan interesantes de seguir.
9Runa5
13
  var stud = (from s1 in entities.Students
            where s1.ID== student.ID
            select s1).SingleOrDefault();

  //Delete it from memory
  entities.DeleteObject(stud);
  //Save to database
  entities.SaveChanges();
Alex G
fuente
2
FirstOrDefaultes peligroso. O sabe que solo hay uno (así que use SingleOrDefault), o hay más de uno, y debe hacerse en un bucle.
Mark Sowul
8
Employer employer = context.Employers.First(x => x.EmployerId == 1);

context.Customers.DeleteObject(employer);
context.SaveChanges();
Sam Leach
fuente
¿Esto protege si no hay ningún objeto con Id 1? ¿No arrojaría una excepción?
Jack Fairfield
@JackFairfield, creo que deberías comprobar si hay objetos nulos. y de acuerdo a esto realizar eliminar.
Jawand Singh
Firstes peligroso. O sabe que solo hay uno (así que use Single), o hay más de uno, y debe hacerse en un bucle.
Mark Sowul
5

Estoy usando el marco de la entidad con LINQ. El siguiente código fue útil para mí;

1- Para registros múltiples

 using (var dbContext = new Chat_ServerEntities())
 {
     var allRec= dbContext.myEntities;
     dbContext.myEntities.RemoveRange(allRec);
     dbContext.SaveChanges();
 }

2- Para registro único

 using (var dbContext = new Chat_ServerEntities())
 {
     var singleRec = dbContext.ChatUserConnections.FirstOrDefault( x => x.ID ==1);// object your want to delete
     dbContext.ChatUserConnections.Remove(singleRec);
     dbContext.SaveChanges();
 }
Baqer Naqvi
fuente
Para Single record, ¿por qué no usar en SingleOrDefaultlugar de FirstOrDefault?
Mark Sowul
Cada vez que utiliza SingleOrDefault, declara claramente que la consulta debe dar como resultado un único resultado. Por otro lado, cuando se usa FirstOrDefault, la consulta puede devolver cualquier cantidad de resultados, pero usted declara que solo desea el primero stackoverflow.com/a/1745716/3131402
Baqer Naqvi
1
Sí, entonces, ¿por qué sería correcto eliminar un registro arbitrario, si hay más de uno? Particularmente en este caso, la identificación es la clave, por lo que debería haber una: si hay más de una, es un error (que Single detectaría)
Mark Sowul
@ MarkSowul tienes razón. He editado la respuesta para usar FirstOrDefault.
Baqer Naqvi
@BaqerNaqvi RemoveRange es una forma terrible de eliminar la entidad desde la perspectiva del rendimiento ... Especialmente cuando su entidad está llena de todas las propiedades de navegación por claves externas. Prefiero usar var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = @your_parameter"; this.your_context.Database.ExecuteSqlCommand (sql, new SqlParameter ("@ your_parameter", yourParameter));
curiousBoy
2

Approuch más genérico

public virtual void Delete<T>(int id) where T : BaseEntity, new()
{
    T instance = Activator.CreateInstance<T>();
    instance.Id = id;
    if (dbContext.Entry<T>(entity).State == EntityState.Detached)
    {
        dbContext.Set<T>().Attach(entity);
    }

    dbContext.Set<T>().Remove(entity);
}
valentasm
fuente
2

Con Entity Framework 6, puede usar Remove. También es una buena táctica usingpara asegurarse de que su conexión esté cerrada.

using (var context = new EmployDbContext())
{
    Employ emp = context.Employ.Where(x => x.Id == id).Single<Employ>();
    context.Employ.Remove(emp);
    context.SaveChanges();
}
Gizmo
fuente
1

Solo quería contribuir con los tres métodos con los que he rebotado.

Método 1:

var record = ctx.Records.FirstOrDefault();
ctx.Records.Remove(record);
ctx.SaveChanges();

Método 2:

var record = ctx.Records.FirstOfDefault();
ctx.Entry(record).State = EntityState.Deleted;
ctx.SaveChanges();
ctx.Entry(record).State = EntityState.Detached;

Una de las razones por las que prefiero seguir con el Método 2 es porque en el caso de configurar EF o EFCore QueryTrackingBehavior.NoTracking, es más seguro hacerlo.

Luego está el Método 3:

var record = ctx.Records.FirstOrDefault();
var entry = ctx.Entry(record);
record.DeletedOn = DateTimeOffset.Now;
entry.State = EntityState.Modified;
ctx.SaveChanges();
entry.State = EntityState.Detached;

Esto utiliza un enfoque de eliminación suave al establecer la DeletedOnpropiedad del registro y aún así poder mantener el registro para uso futuro, sea lo que sea. Básicamente, ponerlo en la Papelera de reciclaje .


Además, con respecto al Método 3 , en lugar de configurar todo el registro para que se modifique:

entry.State = EntityState.Modified;

También simplemente establecería solo la columna DeletedOncomo modificada:

entry.Property(x => x.DeletedOn).IsModified = true;
LatenteDenis
fuente
0
    [HttpPost]
    public JsonResult DeleteCotnact(int id)
    {
        using (MycasedbEntities dbde = new MycasedbEntities())
        {
            Contact rowcontact = (from c in dbde.Contact
                                     where c.Id == id
                                     select c).FirstOrDefault();

            dbde.Contact.Remove(rowcontact);
            dbde.SaveChanges();

            return Json(id);
        }
    }

¿Qué opinas de esto, simple o no? También puedes probar esto:

        var productrow = cnn.Product.Find(id);
        cnn.Product.Remove(productrow);
        cnn.SaveChanges();
Namroy
fuente
0

Para DAO genérico, mi trabajo finalmente es esto:

    public void Detele(T entity)
    {
        db.Entry(entity).State = EntityState.Deleted;
        db.SaveChanges();
    }
Tom Trnka
fuente
0

Usar EntityFramework.Plus podría ser una opción:

dbContext.Employ.Where(e => e.Id == 1).Delete();

Más ejemplos están disponibles aquí

Mohammad Reza Sadreddini
fuente
0

puedes hacerlo simplemente así

   public ActionResult Delete(int? id)
    {
        using (var db = new RegistrationEntities())
        {
            Models.RegisterTable Obj = new Models.RegisterTable();
            Registration.DAL.RegisterDbTable personalDetail = db.RegisterDbTable.Find(id);
            if (personalDetail == null)
            {
                return HttpNotFound();
            }
            else
            {
                Obj.UserID = personalDetail.UserID;
                Obj.FirstName = personalDetail.FName;
                Obj.LastName = personalDetail.LName;
                Obj.City = personalDetail.City;

            }
            return View(Obj);
        }
    }


    [HttpPost, ActionName("Delete")]

    public ActionResult DeleteConfirmed(int? id)
    {
        using (var db = new RegistrationEntities())
        {
            Registration.DAL.RegisterDbTable personalDetail = db.RegisterDbTable.Find(id);
            db.RegisterDbTable.Remove(personalDetail);
            db.SaveChanges();
            return RedirectToAction("where u want it to redirect");
        }
    }

modelo

 public class RegisterTable
{

    public int UserID
    { get; set; }


    public string FirstName
    { get; set; }


    public string LastName
    { get; set; }


    public string Password
    { get; set; }


    public string City
    { get; set; }

} 

vista desde la cual lo llamarás

 <table class="table">
    <tr>
        <th>
            FirstName
        </th>
        <th>
            LastName
        </th>

        <th>
            City
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td> @item.FirstName </td>
            <td> @item.LastName </td>
            <td> @item.City</td>
            <td>
                <a href="@Url.Action("Edit", "Registeration", new { id = item.UserID })">Edit</a> |
                <a href="@Url.Action("Details", "Registeration", new { id = item.UserID })">Details</a> |
                <a href="@Url.Action("Delete", "Registeration", new { id = item.UserID })">Delete</a>

            </td>
        </tr>

    }

</table>

Espero que esto sea fácil de entender

Sikander Iqbal
fuente
0

Puede hacer algo como esto en su evento click o celldoubleclick de su cuadrícula (si utilizó uno)

if(dgEmp.CurrentRow.Index != -1)
 {
    employ.Id = (Int32)dgEmp.CurrentRow.Cells["Id"].Value;
    //Some other stuff here
 }

Luego haga algo como esto en su botón Eliminar:

using(Context context = new Context())
{
     var entry = context.Entry(employ);
     if(entry.State == EntityState.Detached)
     {
        //Attached it since the record is already being tracked
        context.Employee.Attach(employ);
     }                             
     //Use Remove method to remove it virtually from the memory               
     context.Employee.Remove(employ);
     //Finally, execute SaveChanges method to finalized the delete command 
     //to the actual table
     context.SaveChanges();

     //Some stuff here
}

Alternativamente, puede usar una consulta LINQ en lugar de usar la consulta LINQ To Entities:

var query = (from emp in db.Employee
where emp.Id == employ.Id
select emp).Single();

mploy.Id se utiliza como parámetro de filtrado que ya pasó del evento CellDoubleClick de su DataGridView.

arvin aquio
fuente
La idea detrás del código es que conecta el id (mploy.Id) del registro que desea eliminar al modelo (clase de empleado) y luego lo adjunta a la tabla real desde el contexto, luego ejecuta el método Remove () en memoria y luego finalmente ejecute el guardado real en la base de datos usando el método SaveChanges (). Aunque la consulta LINQ también funciona bien, pero no me gusta la idea de consultar la tabla solo para obtener la identificación del registro.
arvin aquio
0

Aquí hay una manera segura:

using (var transitron = ctx.Database.BeginTransaction())
{
  try
  {
    var employer = new Employ { Id = 1 };
    ctx.Entry(employer).State = EntityState.Deleted;
    ctx.SaveChanges();
    transitron.Commit();
  }
  catch (Exception ex)
  {
    transitron.Rollback();
    //capture exception like: entity does not exist, Id property does not exist, etc...
  }
}

Aquí puede agrupar todos los cambios que desee, para que pueda hacer una serie de borrados antes de SaveChanges y Commit, para que se apliquen solo si todos son exitosos.

Emilio.NT
fuente
0

La mejor manera es verificar y luego eliminar

        if (ctx.Employ.Any(r=>r.Id == entity.Id))
        {
            Employ rec = new Employ() { Id = entity.Id };
            ctx.Entry(rec).State = EntityState.Deleted;
            ctx.SaveChanges();
        }
Fuente dE
fuente