Alex Rivera | Logout

Entity Framework Code First - Why can't I update complex properties this way?

Asked 2011-03-31T20:46:46.777
29

I'm working on a small sample project using Entity Framework 4.1 (code first). My classes look like this:

public class Context : DbContext
{
    public IDbSet<Person> People { get; set; }
    public IDbSet<EmployeeType> EmployeeTypes { get; set; }
}

public class Person
{
    [Key]
    public int Key { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    virtual public EmployeeType EmployeeType { get; set; }
}

public class EmployeeType
{
    [Key]
    public int Key { get; set; }
    public string Text { get; set; }

    virtual public ICollection<Person> People { get; set; }
}

I've saved a couple EmployeeTypes ("first", "second") to the database, and I've saved a Person who has the first type. Now I want to modify the Person. I know I can do this by loading the Person, changing properties, and then saving. But what I want to do instead, which seems to me like it ought to work, is this:

var c = new Context();
var e = c.EmployeeTypes.Single(x => x.Text.Equals("second"));
var p = new Person { 
            Key = originalKey,       // same key
            FirstName = "NewFirst",  // new first name
            LastName = "NewLast",    // new last name
            EmployeeType = e };      // new employee type
c.Entry(p).State = EntityState.Modified;
c.SaveChanges();

Oddly, this changes FirstName and LastName but not EmployeeType. If I get a new Context and request this Person, the EmployeeType remains set to "first" as it was before this code ran.

What do I need to do to get the navigation properties to update, and not just the scalar properties? (This is especially puzzling because for EmployeeType, the only thing that actually needs to change is the foreign key in the Person table, and that key is a scalar property.)

(By the way, I know I can do this by retrieving the Person first, then changin

Edit
Report

1 Answer

1

This works for collections, although i feel like there's got to be a better way.


var properties = typeof(TEntity).GetProperties();
foreach (var property in properties)
{
    if (property.GetCustomAttributes(typeof(OneToManyAttribute), false).Length > 0)
    {
        dynamic collection = db.Entry(e).Collection(property.Name).CurrentValue;
        foreach (var item in collection)
        {
            if(item.GetType().IsSubclassOf(typeof(Entity))) 
            {
                if (item.Id == 0)
                {
                    db.Entry(item).State = EntityState.Added;
                }
                else
                {
                    db.Entry(item).State = EntityState.Modified;
                }
             }
        }
    }
}
db.Entry(e).State = EntityState.Modified;            
db.SaveChanges();

answered 2011-04-12T23:58:02.727

Your Answer