代码首先没有更新子对象

本文关键字:更新 对象 代码 | 更新日期: 2023-09-27 17:49:37

我在用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是一个下拉列表。

当用户单击保存按钮时,视图返回所有填充的Place属性,除了State,它只填充ID,因为它的值来自下拉列表,Name为空。

在Edit Post Method中,我有以下代码:

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首先没有检测到用户的状态变化。

你知道为什么代码首先不能从Place检测状态更改值吗?

谢谢。

代码首先没有更新子对象

您的Update方法更新了Address的(标量属性),并更新了State的(标量属性),但它不更新placeAddress之间的关系(这不是问题,因为您显然只在视图中编辑Address属性,而不将另一个Address实体分配给place),它不更新place.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)。当您将视图发布到服务器时,FK属性StateID将使用从下拉列表中选择的新ID填充。在你的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();
    }
    

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

您还需要附加实体。下面是你需要做的一个简单版本。

var updated = _dbSet.Attach(item);
_dataContext.Entry(item).State = EntityState.Modified;
return updated;