我有一个包含撰写主键的表(3列):
UTP_ID (ITEMId)
UTS_ID (CategoryID)
USS_ID (SubCategoryID)
当我尝试更改SubCategory时,例如,使用EF 4,我得到以下错误:
utl.USS_ID = Convert.ToInt32(ddlSubSetor.SelectedItem.Value);
the property is part of the object's key information and cannot be modified
任何想法?为什么我不能改变它?
答案 0 :(得分:7)
EF在主键属性值和对象引用之间实现Identity Map。它不允许更改同一对象实例的密钥。
我会用直接SQL执行此操作:
objectContext.ExecuteStoreCommand(
"UPDATE MyTable SET USS_ID = {0} WHERE UTP_ID = {1} AND UTS_ID = {2} AND USS_ID = {3}",
Convert.ToInt32(ddlSubSetor.SelectedItem.Value),
utl.UTP_ID, utl.UTS_ID, utl.USS_ID);
确保您的实体utl
与上下文分离,因为此代码直接写入数据库表,并且实体未获取有关此更改的任何信息。但这避免了必须删除并重新创建实体(由于数据库中旧行的现有外键约束,这可能是不可能的。)
答案 1 :(得分:1)
作为实体密钥的一部分,需要从上下文中删除对象并使用新的主键值重新附加。
实体框架通过具有管理实体状态的上下文,实体集合(基本上是表)和实体本身(一行数据)来工作。当数据从数据库中读取时,它将被添加到实体的集合中,而集合又由上下文管理以更改状态。更改实体的密钥实际上是从数据库中删除条目并插入新条目。作为更改实体密钥的结果,首先从其集合中删除实体,分离实体对象以允许密钥修改,更改主键值并将实体重新附加到集合。最后,在上下文中调用save更改以将更改应用于数据库。
以下代码应产生所需的结果:
Context.UTLs.DeleteObject(utl);
Context.UTLs.Detach(utl);
Context.SaveChanges();
utl.USS_ID = Convert.ToInt32(ddlSubSetor.SelectedItem.Value);
Context.UTLs.AddObject(utl).
Context.SaveChanges();