Pregunta

When deleting a parent record I would like EF to delete the child records and not have to do the following:

public Foo
{
    [Key]
    public int FooID { get; set; }
    public string Foo_Name { get; set; }
    //One to many with bar
    public virtual  List<Bar> Bar_List { get; set; }
}

public Bar
{
    [Key]
    public int BarID { get; set; }
    public string Bar_Name { get; set; }
    //One to Many with baz
    public virtual List<Baz> Baz_List { get; set; }
}

public Baz
{
    [Key]
    public int BazID { get; set; }
    public string Baz_Name { get; set; }
}

This is what I am doing to remove the Child Records

using(var context = new FooBarBazContext())
{
    var Foo_List = context.Foos.Where(w => w.Foo_Name == "FooName1234").ToList();

    foreach(var foo in Foo_List)
    {
         foreach(var bar in foo.Bar_List)
         {
              bar.Baz_List.ToList().ForEach(i => context.Bazs.Remove(i));
         }
         foo.Bar_List.ToList().ForEach(i => context.Bars.Remove(i));
         context.Foos.Remove(foo);
         context.Entry<Foo>(foo).State = EntityState.Deleted;
         context.SaveChanges();
    }
}

EDIT - Solution

Ok, I needed to add a Parent navigation property to each of the child objects

public Foo
{
    [Key]
    public int FooID { get; set; }
    public string Foo_Name { get; set; }
    //One to many with bar
    public virtual  List<Bar> Bar_List { get; set; }
}

public Bar
{
    [Key]
    public int BarID { get; set; }
    public string Bar_Name { get; set; }
    //One to Many with baz
    public virtual List<Baz> Baz_List { get; set; }
    public virtual Foo FooObject [ get; set; } //<-- Navigation property for Foo
}

public Baz
{
    [Key]
    public int BazID { get; set; }
    public string Baz_Name { get; set; }
    public virtual Bar BarObject { get; set; } //<-- Navigation property for Bar
}

and then I needed to add the following to the OnModelCreating event:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     modelBuilder.Entity<Foo>().HasKey(x => x.FooID)
                               .HasMany(x => x.Bar_List)
                               .WithOptional(x => x.FooObject)
                               .WillCascadeOnDelete(true);

     modelBuilder.Entity<Bar>().HasKey(x => x.BarID)
                               .HasMany(x => x.Baz_List)
                               .WithOptional(x => x.BarObject)
                               .WillCascadeOnDelete(true);

     base.OnModelCreating(modelBuilder);
}

and now EF does all of the heavy lifting for me:

var foosToRemove = context.Foos.Where(w => w.Foo_Name == "FooName1234").ToList();

foreach (var fooToRemove in foosToRemove)
{
      context.Entry<Foo>(fooToRemove).State = EntityState.Deleted;
}
int results = context.SaveChanges();
¿Fue útil?

Solución

You need to set up Cascade Deletion on your entities.

See Entity Framework 4.3 delete cascade with code first (Poco)

{
//...
modelBuilder.Entity<Parent>()
    .HasMany(e => e.ParentDetails)
    .WithOptional(s => s.Parent)
    .WillCascadeOnDelete(true);
//...

One thing to note, when you delete the parent the related child entities in the context will issue a delete statement as well. For example, a parent with 1000 children will issue 1001 statements (1 delete for the parent and 1000 for the children). This is done to keep the entities in the context up to date.

To avoid extra child deletes, detach the children before SaveChanges and allow the foreign key in the database to do the delete. If you are doing code first, you'll need to add that foreign key relation.

See How Cascade Delete Really Works in EF for more info.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top