Question

I'm posting the exact entity:

    public class Person : ContactableEntity
{

    public Plan Plan { get; set; }

    public int Record { get; set; }

    public int PersonTypeValue { get; set; }

}

I'm using the following code to update in a disconected context fashion:

        public void Update(DbSet MySet, object Obj)
    {
        MySet.Attach(Obj);
        var Entry = this.Entry(Obj);
        Entry.State = EntityState.Modified;
        this.SaveChanges();
    }

This is a method exposed by my dbContext Called this way:

PersistentManager.Update(PersistentManager.Personas,UpdatedPersona);

The problem is, EF will update any property but the referenced Plan object. Can someone tell me where is the mistake? In advance : the entity reaches the point of update with all the properties correctly set. EF just fails to update the FK in the Database (no exception though) Update: tried solving the problem like this but it didn't work:

            PersistentMgr.Contacts.Attach(Obj);
            PersistentMgr.Entry(Obj).State = EntityState.Modified;
            PersistentMgr.Entry(Obj.Plan).State = EntityState.Modified;
            PersistentMgr.SaveChanges();
Was it helpful?

Solution

You need...

this.Entry(person).State = EntityState.Modified;
this.Entry(person.Plan).State = EntityState.Modified;

...because when you set the state of the person to Modified the person gets attached to the context in state Modified but related entities like person.Plan are attached in state Unchanged.

If the relationship between Person and Plan has been changed while the entities were detached it is more difficult (especially, like in your model, when no foreign key is exposed as property ("independent association")) to update the entities correctly. You basically need to load the original object graph from the database, compare it with detached graph if relationships have been changed and merge the changes into the loaded graph. An example is here (see the second code snippet in that answer).

Edit

Example to show that it works (with EF 5.0):

using System.Data;
using System.Data.Entity;
using System.Linq;

namespace EFModifyTest
{
    public class Person
    {
        public int Id { get; set; }
        public Plan Plan { get; set; }
        public int Record { get; set; }
        public int PersonTypeValue { get; set; }
    }

    public class Plan
    {
        public int Id { get; set; }
        public string SomeText { get; set; }
    }

    public class MyContext : DbContext
    {
        public DbSet<Person> Contacts { get; set; }
        public DbSet<Plan> Plans { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());

            // Create a person with plan
            using (var ctx = new MyContext())
            {
                ctx.Database.Initialize(true);

                var plan = new Plan { SomeText = "Old Text" };
                var person = new Person { Plan = plan, Record = 1, PersonTypeValue = 11 };

                ctx.Contacts.Add(person);

                ctx.SaveChanges();
            }
            // see screenshot 1 from SQL Server Management Studio

            Person detachedPerson = null;
            // Load the person with plan
            using (var ctx = new MyContext())
            {
                detachedPerson = ctx.Contacts.Include(c => c.Plan).First();
            }

            // Modify person and plan while they are detached
            detachedPerson.Record = 2;
            detachedPerson.PersonTypeValue = 12;
            detachedPerson.Plan.SomeText = "New Text";

            // Attach person and plan to new context and set their states to Modified
            using (var ctx = new MyContext())
            {
                ctx.Entry(detachedPerson).State = EntityState.Modified;
                ctx.Entry(detachedPerson.Plan).State = EntityState.Modified;

                ctx.SaveChanges();
            }
            // see screenshot 2 from SQL Server Management Studio
        }
    }
}

Screenshot 1 from SQL Server Management Studio (before the modification, Person table is left, Plan table is right):

Before modification

Screenshot 2 from SQL Server Management Studio (after the modification, Person table is left, Plan table is right):

After modification

If it doesn't work for you there must be an important difference to my test model and code. I don't know which one, you must provide more details.

Edit 2

If you change the relationship from Person to another (existing) Plan you must load the original and then update the relationship. With independent associations (no FK property in model) you can update relationships only by using change tracking (aside from more advanced modifications of relationship entries in the ObjectContext change tracker):

var originalPerson = this.Contacts.Include(c => c.Plan)
    .Single(c => c.Id == person.Id);
this.Plans.Attach(person.Plan);

this.Entry(originalPerson).CurrentValues.SetValues(person);
originalPerson.Plan = person.Plan;

this.SaveChanges();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top