我想在应用程序运行之前将虚拟数据初始化到数据库。我有一个SQL脚本,可以直接将数据插入表中。
问题是当我想更新一个元素时,我得到了这个例外:
'System.InvalidOperationException' en EntityFramework.dll: Attaching an entity of type 'Es.Udc.DotNet.MiniPortal.Model.Book' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
这是我的更新方法:
public void Update(E entity)
{
dbContext.Entry<E>(entity).State = EntityState.Modified;
dbContext.SaveChanges();
}
我认为这种情况正在发生,因为EF不跟踪这些项目,但我不知道我能做些什么。什么是初始化虚拟数据并被EF跟踪的最佳方法?感谢。
答案 0 :(得分:1)
我认为这是因为EF没有跟踪项目
这种情况正在发生,因为 EF是跟踪实体。使用相同的DbContext实例,您尝试通过该实体的不同实例读取和更新实体。通过引用跟踪实体。
这意味着您传递给此Update()
方法的实体与您首先从数据库中读取的实体不同。
如果您没有在代码中明确地执行此操作,则可能是代码经历了映射阶段,其中实体更新为new
(显式或通过反射)并从另一个实体填充,例如通过AutoMapper映射的视图模型。
另一种情况是上下文的生命周期太长,例如因为它是从静态变量和/或单例或错误配置的依赖注入容器中使用的。
所以:
AsNoTracking()
。多次查询同一实体可能有意义,在这种情况下,在某些位置使用非跟踪实体可能是解决方案。无论您选择哪种方法,都需要处理并发性,而您并不想自己处理这种并发性。 Optimistic concurrency support is present by default in Entity Framework
答案 1 :(得分:0)
我建议您在将实体发送到Update方法之前执行select(使用EF),然后在将其设置为已修改后尝试将实体附加到上下文(这取决于您是否使用changetraking选项)
dbContext.Set<TEntity>().Attach(entity);
例如,这是我的Repository Update方法(仅用于示例):
public void Update(TEntity updated, Tkey key)
{
updated.ObjectState = ObjectState.Modified;
var existing = _dbSet.Find(key);
if (existing == null) return;
existing.ObjectState = ObjectState.Modified;
dbContext.Entry(existing).CurrentValues.SetValues(updated);
dbContext.Set<TEntity>().Attach(existing);
}