简体   繁体   中英

Identifying and Deleting Entity Framework child records

I have the following objects defined in EF;

public class ItemA()
{
        public virtual ICollection<ItemB> Items{ get; set; }
}

public class ItemB()
{
        public virtual ICollection<ItemC> Items{ get; set; }
}

In my code, I am doing the following;

myItemA.Items.Remove(myItemA.Items.FirstOrDefault(x => (int)x.Type == model.Type));

myItemA.Items.Add(new ItemB());

When the instance of ItemA is populated, it contains a single ItemB and I simply want to replace this with the new instance of ItemB. When I get into my Service to update the message, I noticed that simply calling the following code resulted in the new ItemB and the existing ItemB becomes orphaned with the parent ID being null. The links between ItemB and ItemC are intact.

_dbContext.Entry(entity).State = EntityState.Modified;
_dbContext.SaveChanges();

So, I know that I need to tell EF that the child ItemB is to be deleted and the constraints setup in the model will hopefully cascade delete the child ItemC records and then the orphaned ItemB. However, I am struggling to find a way of doing so.

I have tried re-getting the Parent ItemA from the context to compare the List and mark them as deleted, but as I am getting the proxy back, both objects are essentially the same and only have the updated ItemB and not the original.

var existingItem = GetItem(entity.Id);

or

var existing Items = GetItem(entity.Id).Items.ToList();

So what I need is the original ItemA.Items to be able to tell EF they are to be deleted. Please note that I know how to tell EF that something should be deleted, I am only interested in getting a reference to the entity that should be deleted.

EDIT

Adding this code makes it work and the orphaned ItemB (with child ItemC) are now removed, however, as far as I understand it, this will now be done within 2 transactions.

    //Update Message
    _dbContext.Entry(entity).State = EntityState.Modified;
    _dbContext.SaveChanges();

    //Remove any orphaned records
    var itemsToRemove = _dbContext.Set<ItemB>().Where(x => x.ItemA == null).ToList();
    _dbContext.Set<ItemB>().RemoveRange(itemsToRemove );
    _dbContext.SaveChanges();

Ideally, looking for a way to do this a single SaveChanges()

Umm.. did i understand something wrong or do you only want to implement a cascade delete like this:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<ItemB>().HasRequired(b => b.Parent).WithMany(a => a.Items).WillCascadeOnDelete();
}

This should also work:

public class ItemA()
{
    public virtual ICollection<ItemB> Items{ get; set; }
}

public class ItemB()
{
    [Required] // This set's the constraint
    public virtual ItemA Parent { get; set; }
    public virtual ICollection<ItemC> Items{ get; set; }
}

Did't use the second one, yet, but it should have the identical result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM