尝试使用EF 4迭代添加对象时System.InvalidOperationException

时间:2011-01-13 00:32:03

标签: entity-framework-4

这个问题与this one非常相似。但是,该问题的解决方案:

  1. 似乎不适用,或
  2. 有点怀疑,似乎不是解决问题的好方法。
  3. 基本上,我正在迭代一个通用的对象列表,然后插入它们。使用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

2 个答案:

答案 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)

如果实体在创建之后没有直接添加到上下文中(在执行任何赋值之前),我们遇到了一些奇怪的碰撞问题。我注意到这个问题的唯一一次是在循环中添加对象。

尝试将新添加的实体添加到上下文中,执行分配,然后保存上下文。此外,除非您绝对需要主键,否则每次添加新实体时都不需要保存上下文。