在 WinForms 中使用 EF6 更新导航 属性 的非 ID 字段

Update navigation property's non-id field using EF6 in WinForms

当用户在表单上修改对象时,我想更新对象导航的非 ID 字段 属性。我的"Department"table的一些字段是这样的...

Id
DirectorId (object of Employee table)
NoOfEmployees
Location

和员工table的字段如下:

Id
Name
Post

现在,当向用户显示部门 table 的修改时,我还会显示有关员工的核心信息(post,共 "Director"),并在其中选择了当前主管ComboBox和相应TextBoxes等中的所有相关信息。只要用户选择不同的Director,相关字段也会相应改变。

现在我想要的是,如果此时用户更改了主管的某些信息(例如姓名或年龄),更改应反映在数据库中,而不是强制用户转到员工修改表并在那里进行更改.

我尝试了修改数据库对象的几个字段的简单方法,但是当要修改的对象是导航时,该方法不起作用 属性(如上所述)。这是代码...

using (CompanyDBContext db = new CompanyDBContext() {
    int id = ((Department)cbDept.SelectedItem).Id;
    Department currentDept = db.Departments.Where(x => x.Id == id).First();

    Department newDept = new Department();
    newDept.Id = currentDept.Id;
    newDept.Employee.Id = (int)cbDir.SelectedValue; // --> has no effect;
    // raises NullRefException "Obj. ref. not set to an instance of an obj."
    .....;
    .....;
    db.Entry(currentDept).CurrentValues.SetValues(newDept);

    if (dirNameChanged) {
        var director = new Employee() {
            Id = currentDept.DirectorId,
            Name = tbDirName.Text.Trim()
        };
        db.Employees.Attach(director); // --> raises exception
        db.Entry(director).Property(x => x.Name).IsModified = true;
    }

    db.SaveChanges();
}

.Attach() 方法抛出 InvalidOperationException 异常说

Attaching an entity of type 'CompanyDatabase.Employee' failed because
another entity of the same type already has the same primary key value.
This can happen when using the 'Attach' method or setting the state of
an entity to 'Unchanged' or 'Modified' if any entities in the graph have
conflicting key values. This may be because some entities are new and have
not yet received database-generated key values. In this case use the 'Add'
method or the 'Added' entity state to track the graph and then set the state
of non-new entities to 'Unchanged' or 'Modified' as appropriate.

但是使用 Add() 方法也会引发类似的异常... 有解决办法吗?

P.S。部门对象正在改变。更改 Director 对象也很好,即如果用户为部门选择新的 Director。仅更改 Director(Employee)的非 id 字段会出现问题。

db.Employees.Attach(director); // --> raises exception

异常消息表明上下文已经包含(正在跟踪)具有相同 PK (Id == director.Id) 的 Employee 个对象。因此,与其创建新对象 (new Employee()),不如使用现有对象(EF 使用 reference identity,即不允许两个不同的实体 instances 具有相同的 PK)。

这样做的标准方法是使用Find 方法,该方法将return 当前跟踪的对象与该PK 或将从数据库加载它。因此代码应该是这样的:

if (dirNameChanged)
{
    var director = db.Employess.Find(currentDept.DirectorId);
    director.Name = tbDirName.Text.Trim();
}

请注意,无需 Attach 它或操纵 entity/property 状态 - returned 对象由上下文附加和跟踪,因此任何 属性 值变化是自动确定的。