1

我在使用 CodeFirst 更新 POCO 的子对象时遇到问题。我的 POCO 如下

public class Place
{
    public int ID { get; set; 
    public string Name { get; set; }

    public virtual Address Address { get; set; }
}

public class Address
{
    public int ID { get; set; 
    public string AddressLine { get; set; }
    public string City { get; set; }

    public virtual State State { get; set; }
}

public class State
{
    public int ID { get; set; 
    public string Name { get; set; }
}

我有一个视图来编辑所有地方及其子字段。除了 State 是 DropDownList 之外,所有属性都是文本框。

当用户单击“保存”按钮时,视图会返回所有已填充的 Place 属性,但仅使用 ID 填充的 State 除外,因为它的值来自 DropDownList 并且 Name 为空。

在编辑发布方法中,我有以下代码:

if (ModelState.IsValid)
{
    bool isNewPlace = place.ID == -1;
    //Hack, State name is empty from View, we reload
    place.Address.State = new StateBLL().GetByID(place.Address.State.ID);
    new PlaceBLL().Update(place);

    return RedirectToAction("Index");
}

PlaceBLL 类的更新代码如下

protected override void Update(Place place)
{
    MyDbContext.Instance().Set<Address>().Attach(place.Address);
    MyDbContext.Instance().Entry(place.Address).State = System.Data.EntityState.Modified;
    MyDbContext.Instance().Set<State>().Attach(place.Address.State);
    MyDbContext.Instance().Entry(place.Address.State) = System.Data.EntityState.Modified;
    MyDbContext.Instance().SaveChanges();
    }

当用户编辑 Place 对象时,除了状态之外的所有字段都正确更新,当用户更改某个地方的状态时,此更改不会持久保存到数据库,如果代码似乎首先没有检测到用户的状态更改。

你知道为什么 code first 没有检测到 Place 的 State 变化值吗?

谢谢。

4

2 回答 2

1

您的Update方法更新 (scalar properties of)Address并更新 (scalar properties of)State但它不会更新 and 之间的关系(不是问题,因为您显然只在视图中编辑属性而没有将另一个实体分配给)和它不会更新 和之间的关系。但在你看来,这实际上是你改变的。placeAddressAddressAddressplaceplace.Addressplace.Address.State

要更新和之间的关系place.Addressplace.Address.State有两种选择:

  • 在您的类中引入一个外键属性,该属性Address代表状态的 FK(这种类型的关联称为外键关联):

    public class Address
    {
        public int ID { get; set; 
        public string AddressLine { get; set; }
        public string City { get; set; }
    
        public int StateID { get; set; }
        public virtual State State { get; set; }
    }
    

    然后确保将下拉列表绑定到place.Address.StateID(而不是place.Address.State.ID)。StateID当您将视图发布到服务器时,将使用下拉列表中新选择的 ID 填充FK 属性。在您的Update方法中,您可以删除第三和第四行。单独更新Address也会更新StateID外键。State您还可以删除在您的编辑帖子操作中加载的代码。

  • 如果您想保留当前的独立关联(= 在模型类中没有暴露外键属性的关联),您必须从数据库加载原始状态并使用新状态更新它:

    protected override void Update(Place place)
    {
        var dbPlace = MyDbContext.Instance().Places.Include(p => p.Address.State)
            .Single(p => p.ID == place.ID);
    
        // Update scalar properties of place
        MyDbContext.Instance().Entry(dbPlace)
            .CurrentValues.SetValues(place);
    
        // Update scalar properties of Address
        MyDbContext.Instance().Entry(dbPlace.Address)
            .CurrentValues.SetValues(place.Address);
    
        // Change relationship between Adress and State
        if (dbPlace.Address.State.ID != place.Address.State.ID)
        {
            MyDbContext.Instance().States.Attach(place.Address.State);
            dbPlace.Address.State = place.Address.State;
        }
    
        MyDbContext.Instance().SaveChanges();
    }
    

    同样,您可以删除State在 Edit Post 操作中加载的代码,因为正确的键属性 ( State.ID) 足以更改关系。

于 2012-12-29T16:04:07.267 回答
0

您还需要附加实体。以下是您需要做的简单版本。

var updated = _dbSet.Attach(item);
_dataContext.Entry(item).State = EntityState.Modified;
return updated;
于 2012-12-27T20:54:27.863 回答