c# - mvc - entity framework model first
¿Cómo eliminar el niño uno a muchos registros relacionados en la primera base de datos del código EF? (4)
Bueno, tengo un modelo relacionado de uno a muchos:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public string ChildName { get; set; }
}
Lo que quiero hacer es borrar Parent.Children
y eliminar las entidades secundarias relacionadas de la base de datos. Ya lo intenté:
Clase de contexto de base de datos:
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithOptional()
.WillCascadeOnDelete(true);
esto funciona bien, pero todavía tengo registros redundantes en la base de datos con Parent_Id = null
campos Parent_Id = null
cuando lo hago
parent.Children.Clear();
repository.InsertOrUpdate(parent);
en mi clase de repositorio. También el mismo comportamiento es cuando lo hago:
modelBuilder.Entity<Parent>()
.HasMany(pr => pr.Children)
.WithOptional(ri => ri.Parent)
.WillCascadeOnDelete(true);
con propiedad adicional para Parent
en Child
clase Child
public class Child
{
...
public Parent Parent { get; set; }
...
}
o cuando lo hago
modelBuilder.Entity<Child>()
.HasOptional(p => p.Parent)
.WithMany(p => p.Children)
.HasForeignKey(p => p.Parent_Id)
.WillCascadeOnDelete(true);
con propiedad Parent_Id adicional en Child
clase Child
public class Child
{
...
public int Parent_Id { get; set; }
...
}
Entonces, ¿cómo puedo configurar la eliminación de cascada correctamente? ¿O cómo debería suponer eliminar esas entidades secundarias? Supongo que es una tarea casual, pero me falta algo.
En EF6 una forma más rápida de hacer la operación es ...
context.Children.RemoveRange(parent.Children)
Intenta cambiar a
public virtual ICollection<Child> Children { get; set; }
porque virtual es necesario para obtener la carga diferida. como se explica here
Creo que tu padre.Children.clear no está funcionando porque los niños no se han cargado
La eliminación en cascada no tiene ningún efecto aquí porque no elimina el elemento parent
simplemente llama a InsertOrUpdate
. El procedimiento correcto es eliminar a los niños uno por uno, como por ejemplo:
using (var context = new MyContext())
{
var parent = context.Parents.Include(p => p.Children)
.SingleOrDefault(p => p.Id == parentId);
foreach (var child in parent.Children.ToList())
context.Children.Remove(child);
context.SaveChanges();
}
Si su objeto se autorreferencia, puede eliminar hijos de muchos a muchos y de uno a muchos utilizando el siguiente método. Solo recuerde llamar a db.SaveChanges () después :)
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Object obj = this.db.Objects.Find(id);
this.DeleteObjectAndChildren(obj);
this.db.Objects.Remove(obj);
this.db.SaveChanges();
return this.Json(new { success = true });
}
/// <summary>
/// This deletes an object and all children, but does not commit changes to the db.
/// - MH @ 2016/08/15 14:42
/// </summary>
/// <param name="parent">
/// The object.
/// </param>
private void DeleteObjectAndChildren(Object parent)
{
// Deletes One-to-Many Children
if (parent.Things != null && parent.Things.Count > 0)
{
this.db.Things.RemoveRange(parent.Things);
}
// Deletes Self Referenced Children
if (parent.Children != null && parent.Children.Count > 0)
{
foreach (var child in parent.Children)
{
this.DeleteObjectAndChildren(child);
}
this.db.Objects.RemoveRange(parent.Children);
}
}