我有两个表:Word
和Adjective
,两者都有一些属性。这两个表的主键是ID
,Adjective.ID
也引用Word.ID
作为外键,因此存在1-1关系。
我还有一个包含Update功能的表的存储库。
public void Update(T entity) {
var entry = DatabaseContext.Entry(entity);
DatabaseSet.Attach(entity);
entry.State = EntityState.Modified;
}
我从数据库中获取一个值,将其转换为一个看起来像这样的ViewModel(当然它实际上有点复杂):
public class WordModel {
public int ID { get; set; }
public string OriginalWord { get; set; }
}
public class AdjectiveModel : WordModel {
public string Translation { get; set; }
}
然后我改变属性Word和翻译的值,转换并写回。转换后我有一个像这样的对象:
Word = {
ID = 1
OriginalWord = y
Adjective = {
ID = 1
Translation = z
}
}
然而,在更新时,只有一个表得到更新。
Database.Words.Update(Word)
仅更新Word表格中的OriginalWord值,
Database.Adjectives.Update(Word.Adjective)
仅更新“形容词”表中的“翻译”值。
当顺序运行两个表的更新时,我得到一个InvalidOperationException: ObjectStateManager中已存在具有相同键的对象。 ObjectStateManager无法使用相同的键跟踪多个对象。
创建新的数据库条目非常有效。
我无法相信我必须自己更新两个表,然后为每个表保存上下文。我通过教程创建了数据库存储库,显然没有很好地解释DbSet和DbContext的情况,这让我有点无奈。 可悲的是,我没有链接(很久以前我创建了数据库项目)
那么,我在这里做错了什么?
答案 0 :(得分:2)
你实体Word包含一个实体形容词,它就是对象图的根。现在,在下列情况下,您应该记住以下内容:
使用myDbContext.Words.Add(myNewWordObjectGraph);
来获得所需的正确状态。
使用myDbContext.Entry(myNewWord).state = EntityState.Added;
来获得所需的正确状态。
使用myDbContext.Entry(myWord).State = EntityState.Modified;
和 myDbContext.Entry(myAdjective).State = EntityState.Modified;
来获得您想要的正确状态。即为图中的每个修改对象调用myDbContext.Entry(myObject).State = EntityState.Modified;
,无论它是根还是其他节点。
使用myDbContext.MyRootObjectDbSet.Add(myRootObject);
;这会将图表中的所有对象标记为EntityState.Added
,包括未更改和/或修改的对象 。所以下一个调用应该是每个未更改和/或修改的对象,以便更正其状态:myDbContext.Entry(myObject).State = ThisObjectSCorrectState;
。
我希望有所帮助
调用DbSet.Attach(...)
只是将对象添加到EF的跟踪对象中。如果在调用DbSet.Attach(...)
之前修改对象,则在调用SaveChages()
时修改将不会持久保存到DB,因此在修改之前附加对象 ,调用{{ 1}}然后修改对象是让EF意识到修改的方法。
根据你的更新方法定义的方式,我认为你的存储库看起来像这样吗?
//不是线程安全的,因为它包含一个瞬态对象'DbContext'。
DbSet.Attach(...)
我建议将更新方法更改为以下内容:
public class Repository<T> : IRespository<T> where T : class
{
private readonly MyDbContext context;
public Repository(MtDbContext context)
{
this.context = context
}
//...
public void Update(T entity) {... }
public void Commit() { context.SaveChanges(); }
}
使用包含DbContext的存储库的相同实例,将为您在图中更新的每个对象调用此更新方法。