这个问题与this one非常相似。但是,该问题的解决方案:
基本上,我正在迭代一个通用的对象列表,然后插入它们。使用MVC 2,EF 4和默认代码生成。
foreach(Requirement r in requirements)
{
var car = new CustomerAgreementRequirement();
car.CustomerAgreementId = viewModel.Agreement.CustomerAgreementId;
car.RequirementId = r.RequirementId;
_carRepo.Add(car); //Save new record
}
Repository.Add()方法:
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
private TxRPEntities txDB;
private ObjectSet<TEntity> _objectSet;
public void Add(TEntity entity)
{
SetUpdateParams(entity);
_objectSet.AddObject(entity);
txDB.SaveChanges();
}
我应该注意到,我已经成功地在我的代码中使用Add()方法进行单个插入;这是我第一次尝试使用它迭代插入一组对象。
错误:
System.InvalidOperationException:已成功提交对数据库的更改,但更新对象上下文时发生错误。 ObjectContext可能处于不一致状态。内部异常消息:AcceptChanges无法继续,因为对象的键值与ObjectStateManager中的另一个对象冲突。在调用AcceptChanges之前,请确保键值是唯一的。
如前一个问题所述,EntityKey设置为True,StoreGeneratedPattern = Identity。插入的实际表是关系表,因为它由标识字段和两个外键字段组成。错误总是发生在第二个插入上,无论之前是否插入了特定实体,我可以确认值始终不同,就数据库而言没有关键冲突。我怀疑它与在实际插入之前设置的临时实体键有关,但我不知道如何确认,也不知道如何解决它。
我的直觉是,在上一个问题中,将SaveOptions设置为None的解决方案不是最佳解决方案。 (参见先前的讨论here)
答案 0 :(得分:1)
我在使用循环的存储库中遇到了这个问题,并认为它可能是由一些奇怪的种族情况引起的。我所做的是重构一个UnitOfWork类,以便repository.add()方法严格地添加到数据库,但不存储上下文。因此,存储库仅负责集合本身,并且该集合上的每个操作都发生在工作单元的范围内。
问题在于:在循环中,使用EF4快速耗尽内存。所以你需要定期存储更改,我不会在每次保存后存储。
公共类BaseRepository:IRepository,其中TEntity:class { 私人TxRPEntities txDB; private ObjectSet _objectSet;
public void Add(TEntity entity)
{
SetUpdateParams(entity);
_objectSet.AddObject(entity);
}
public void Save()
{
txDB.SaveChanges();
}
然后你可以做类似
的事情foreach(Requirement r in requirements)
{
var car = new CustomerAgreementRequirement();
car.CustomerAgreementId = viewModel.Agreement.CustomerAgreementId;
car.RequirementId = r.RequirementId;
_carRepo.Add(car); //Save new record
if (some number limiting condition if you have thousands)
_carRepo.Save(); // To save periodically and clear memory
}
_carRepo.Save();
注意:我并不是真的喜欢这个解决方案,但是当我们在其他地方工作时,我试图找到为什么事情会在一个循环中破裂,这就是我想出的最好的结果。< / p>
答案 1 :(得分:0)
如果实体在创建之后没有直接添加到上下文中(在执行任何赋值之前),我们遇到了一些奇怪的碰撞问题。我注意到这个问题的唯一一次是在循环中添加对象。
尝试将新添加的实体添加到上下文中,执行分配,然后保存上下文。此外,除非您绝对需要主键,否则每次添加新实体时都不需要保存上下文。