Entity framework, problems updating related objects

前端 未结 3 1158
野性不改
野性不改 2020-11-30 18:23

I am currently working on a project using the latest version of Entity Framework and I have come across an issue which I can not seem to solve.

When it comes to up

相关标签:
3条回答
  • 2020-11-30 18:32

    You can also call the tables independently

    MyContext db = new MyContext
    // I like using asynchronous calls in my API methods 
    var OldFoo = await db.Foo.FindAsync(id);
    var OldAssociateFoo = db.AssociatedFoo;  
    var NewFoo = OldFoo;
    var NewAssociatedFoo = OldAssociatedFoo;
    
    NewFoo.SomeValue = "The Value";
    NewAssociatedFoo.OtherValue = 20;
    
    db.Entry(OldFoo).CurrentValues.SetValues(NewFoo);
    db.Entry(OldAssociatedFoo).CurrentValues.SetValues(NewAssociatedFoo);
    
    await db.SaveChangesAsync();
    
    0 讨论(0)
  • 2020-11-30 18:35

    CurrentValues.SetValues only updates scalar properties but no related entities, so you must do the same for each related entity:

    public Foo Edit(Foo newFoo)
    {
        var dbFoo = context.Foo
                           .Include(x => x.SubFoo)
                           .Include(x => x.AnotherSubFoo)
                           .Single(c => c.Id == newFoo.Id);
    
        context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
        context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);
        context.Entry(dbFoo.AnotherSubFoo).CurrentValues.SetValues(newFoo.AnotherSubFoo);
    
        context.SaveChanges();
    
        return newFoo;
    }
    

    If the relationship could have been removed altogether or have been created you also need to handle those cases explicitly:

    public Foo Edit(Foo newFoo)
    {
        var dbFoo = context.Foo
                           .Include(x => x.SubFoo)
                           .Include(x => x.AnotherSubFoo)
                           .Single(c => c.Id == newFoo.Id);
    
        context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
        if (dbFoo.SubFoo != null)
        {
            if (newFoo.SubFoo != null)
            {
                if (dbFoo.SubFoo.Id == newFoo.SubFoo.Id)
                    // no relationship change, only scalar prop.
                    context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo);
                else
                {
                    // Relationship change
                    // Attach assumes that newFoo.SubFoo is an existing entity
                    context.SubFoos.Attach(newFoo.SubFoo);
                    dbFoo.SubFoo = newFoo.SubFoo;
                }
            }
            else // relationship has been removed
                dbFoo.SubFoo = null;
        }
        else
        {
            if (newFoo.SubFoo != null) // relationship has been added
            {
                // Attach assumes that newFoo.SubFoo is an existing entity
                context.SubFoos.Attach(newFoo.SubFoo);
                dbFoo.SubFoo = newFoo.SubFoo;
            }
            // else -> old and new SubFoo is null -> nothing to do
        }
    
        // the same logic for AnotherSubFoo ...
    
        context.SaveChanges();
    
        return newFoo;
    }
    

    You eventually also need to set the state of the attached entities to Modified if the relationship has been changed and the scalar properties as well.

    Edit

    If - according to your comment - Foo.SubFoo is actually a collection and not only a reference you will need something like this to update the related entities:

    public Foo Edit(Foo newFoo)
    {
        var dbFoo = context.Foo
                           .Include(x => x.SubFoo)
                           .Include(x => x.AnotherSubFoo)
                           .Single(c => c.Id == newFoo.Id);
    
        // Update foo (works only for scalar properties)
        context.Entry(dbFoo).CurrentValues.SetValues(newFoo);
    
        // Delete subFoos from database that are not in the newFoo.SubFoo collection
        foreach (var dbSubFoo in dbFoo.SubFoo.ToList())
            if (!newFoo.SubFoo.Any(s => s.Id == dbSubFoo.Id))
                context.SubFoos.Remove(dbSubFoo);
    
        foreach (var newSubFoo in newFoo.SubFoo)
        {
            var dbSubFoo = dbFoo.SubFoo.SingleOrDefault(s => s.Id == newSubFoo.Id);
            if (dbSubFoo != null)
                // Update subFoos that are in the newFoo.SubFoo collection
                context.Entry(dbSubFoo).CurrentValues.SetValues(newSubFoo);
            else
                // Insert subFoos into the database that are not
                // in the dbFoo.subFoo collection
                dbFoo.SubFoo.Add(newSubFoo);
        }
    
        // and the same for AnotherSubFoo...
    
        db.SaveChanges();
    
        return newFoo;
    }
    
    0 讨论(0)
  • 2020-11-30 18:45

    Just thought I would post the link below as it really helped me understand how to update related entities.

    Updating related data with the entity framework in an asp net mvc application

    NOTE: I did change the logic slightly that is shown in the UpdateInstructorCourses function to suit my needs.

    0 讨论(0)
提交回复
热议问题