我在使用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; }
}
我可以编辑地点及其子项的所有字段。除了作为DropDownList的State之外,所有属性都是文本框。
当用户单击“保存”按钮时,视图将返回所有已填充的“地方”属性,但只有ID填充的状态除外,因为它的值来自DropDownList且名称为空。
在编辑帖子方法中,我有以下代码:
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对象时,除状态外所有字段都正确更新,当用户更改某个地方的状态时,此更改不会持久保存到数据库,如果看起来代码首先未检测到用户的状态更改。
你知道为什么代码首先没有检测到Place的状态变化值吗?
感谢。
答案 0 :(得分:1)
您的Update
方法更新了Address
的(标量属性)并更新了State
的(标量属性),但它没有更新关系 place
和Address
之间(这不是问题,因为您显然只在视图中编辑Address
属性而未将另一个Address
实体分配给place
)和它不会更新place.Address
和place.Address.State
之间的关系。但这是你在视野中实际改变的。
要更新place.Address
和place.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
)。将视图发布到服务器时,将从下拉列表中使用新选择的ID填充FK属性StateID
。在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
的代码,因为正确的键属性(State.ID
)足以改变关系。
答案 1 :(得分:0)
您还需要附加实体。以下是您需要做的简单版本。
var updated = _dbSet.Attach(item);
_dataContext.Entry(item).State = EntityState.Modified;
return updated;