Entity 4.1 Updating an existing parent entity with new child Entities

元气小坏坏 提交于 2019-11-27 06:49:32

I first clear the existing ingredients collection in the product entity and than add the updated list of ingredients again.

Well, this is kind of brute-force-attack to update the child collection. EF doesn't have any magic to update the children - which means: adding new children, deleting removed children, updating existing children - by only setting the state of the parent to Modified. Basically this procedure forces you to delete the old children also from the database and insert the new one, like so:

// product is the detached product with the detached new children collection
using (var context = new MyContext())
{
    var productInDb = context.Products.Include(p => p.Ingredients)
        .Single(p => p.Id == product.Id);

    // Update scalar/complex properties of parent
    context.Entry(productInDb).CurrentValues.SetValues(product);

    foreach (var ingredient in productInDb.Ingredients.ToList())
        context.Ingredients.Remove(ingredient);

    productInDb.Ingredients.Clear(); // not necessary probably

    foreach (var ingredient in product.Ingredients)
        productInDb.Ingredients.Add(ingredient);

    context.SaveChanges();
}

The better procedure is to update the children collection in memory without deleting all children in the database:

// product is the detached product with the detached new children collection
using (var context = new MyContext())
{
    var productInDb = context.Products.Include(p => p.Ingredients)
        .Single(p => p.Id == product.Id);

    // Update scalar/complex properties of parent
    context.Entry(productInDb).CurrentValues.SetValues(product);

    var ingredientsInDb = productInDb.Ingredients.ToList();
    foreach (var ingredientInDb in ingredientsInDb)
    {
        // Is the ingredient still there?
        var ingredient = product.Ingredients
            .SingleOrDefault(i => i.Id == ingredientInDb.Id);

        if (ingredient != null)
            // Yes: Update scalar/complex properties of child
            context.Entry(ingredientInDb).CurrentValues.SetValues(ingredient);
        else
            // No: Delete it
            context.Ingredients.Remove(ingredientInDb);
    }

    foreach (var ingredient in product.Ingredients)
    {
        // Is the child NOT in DB?
        if (!ingredientsInDb.Any(i => i.Id == ingredient.Id))
            // Yes: Add it as a new child
            productInDb.Ingredients.Add(ingredient);
    }

    context.SaveChanges();
}
angularsen

I found this recent article on the GraphDiff extension for DbContext.

Apparently it is a generic, reusable variant of Slauma's solution.

Example code:

using (var context = new TestDbContext())
{
    // Update DBcompany and the collection the company and state that the company 'owns' the collection Contacts.
    context.UpdateGraph(company, map => map.OwnedCollection(p => p.Contacts));     
    context.SaveChanges();
}

On a side note; I see the author has proposed to the EF team to use his code in issue #864 Provide better support for working with disconnected entities.

I reckon, This is more simpler solution.

public Individual
{
.....

public List<Address> Addresses{get;set;}


}

//where base.Update from Generic Repository
public virtual void Update(T entity)
        {
            _dbset.Attach(entity);
            _dataContext.Entry(entity).State = EntityState.Modified;
        }

//overridden update
 public override void Update(Individual entity)
        {


            var entry = this.DataContext.Entry(entity);
            var key = Helper.GetPrimaryKey(entry);
            var dbEntry = this.DataContext.Set<Individual>().Find(key);

            if (entry.State == EntityState.Detached)
            {
                if (dbEntry != null)
                {
                    var attachedEntry = this.DataContext.Entry(dbEntry);
                    attachedEntry.CurrentValues.SetValues(entity);
                }
                else
                {
                    base.Update(entity);
                }
            }
            else
            {
                base.Update(entity);
            }
            if (entity.Addresses.Count > 0)
            {
                foreach (var address in entity.Addresses)
                {
                    if (address != null)
                    {
                        this.DataContext.Set<Address>().Attach(address);
                        DataContext.Entry(address).State = EntityState.Modified;
                    }
                }
            }
        }

after many many months struggling with understanding this entire crappy Entity Framework I hope this can help someone and not go through any of the frustration I have endured.

public void SaveOrder(SaleOrder order)
        {
            using (var ctx = new CompanyContext())
            {
                foreach (var orderDetail in order.SaleOrderDetails)
                {
                    if(orderDetail.SaleOrderDetailId == default(int))
                    {
                        orderDetail.SaleOrderId = order.SaleOrderId;
                        ctx.SaleOrderDetails.Add(orderDetail);
                    }else
                    {
                        ctx.Entry(orderDetail).State = EntityState.Modified;
                    }
                }

                ctx.Entry(order).State = order.SaleOrderId == default(int) ? EntityState.Added : EntityState.Modified;
                ctx.SaveChanges();                

            }

        }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!