实体框架代码优先 - 为什么我不能这样更新复杂属性?

Rya*_*ndy 28 c# entity-framework ef-code-first entity-framework-4.1

我正在使用Entity Framework 4.1(代码优先)开展一个小型示例项目.我的课程看起来像这样:

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; }
}
Run Code Online (Sandbox Code Playgroud)

我已经将几个EmployeeTypes("first","second")保存到数据库中,并且我保存了第一个类型的Person.现在我要修改Person.我知道我可以通过加载Person,更改属性,然后保存来完成此操作.但是我想要做的事情,在我看来应该像它应该工作,是这样的:

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();
Run Code Online (Sandbox Code Playgroud)

奇怪的是,这会更改FirstName和LastName,但不会更改EmployeeType.如果我获得一个新的Context并请求此Person,那么EmployeeType将保持设置为"first",就像在此代码运行之前一样.

我需要做什么才能更新导航属性,而不仅仅是标量属性? (这尤其令人费解,因为对于EmployeeType,实际需要更改的唯一内容是Person表中的外键,并且该键是标量属性.)

(顺便说一下,我知道我可以通过首先检索Person,然后逐个更改属性来做到这一点,但是因为我在ASP.NET MVC中使用模型绑定,所以看起来这样会更容易因为我我的POST方法中已经有了更新的人物对象.)

Lad*_*nka 19

你可以尝试不同的方式:

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
c.People.Attach(p); // Attach person first so that changes are tracked 
c.Entry(p).Reference(e => e.EmployeeType).Load();               
p.EmployeeType = e; // Now context should know about the change
c.Entry(p).State = EntityState.Modified;
c.SaveChanges();
Run Code Online (Sandbox Code Playgroud)

其他方法是在您的Person实体中公开外键,如:

public class Person
{
    [Key]
    public int Key { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [ForeignKey("EmployeeType")]
    public int EmployeeTypeKey { get; set; }
    public virtual EmployeeType EmployeeType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这将改变之间的关系的类型Person,并EmployeeType从独立的关联外键关联.而不是分配导航属性分配外键属性.这将允许您通过当前代码修改关系.

问题是独立关联(那些不使用外键属性)在状态管理器/更改跟踪器中作为单独的对象处理.因此,您对此人的修改并未影响现有关系的状态,也未设置新关系.我问在MSDN上如何使用的DbContext API做,但它可能只有当你施放DbContextObjectContext并使用ObjectStateManagerChangeRelationshipState.

  • 但这很疯狂.如果EF足够聪明,可以在数据库中创建外键,那么在不必将其作为属性公开的情况下更新外键是多么不够智能?这是EF的所有风格中的问题,还是只在Code First中? (4认同)