EF4.1 + MARS - UPDATE上不允许新的交易

时间:2011-10-26 21:22:15

标签: c# .net sql entity-framework entity-framework-4

当我更新数据库中的实体时,我收到以下异常:

  

不允许使用新事务,因为会话中还有其他线程在运行。

我使用相同的代码块来处理所有传入的数据(从Excel工作簿中删除)。工作INSERT和不工作UPDATE之间的唯一区别如下:

public void UploadWorkbook(Workbook workbook, string uploadedBy, string comments)
{
    workbook.UploadedBy = uploadedBy;
    workbook.Comments = comments;

    var existing = _repository.Get(x => x.FileName == workbook.FileName);
    if (existing == null)
        _repository.Insert(workbook); // this works on the commit
    else
        _repository.Update(workbook); // this causes commit to fail

    _unitOfWork.Commit(); // fails when repository runs update method
}

此外,这是更新方法:

public override void Update(Workbook entity)
{
    var existing = Get(x => x.FileName == entity.FileName);

    if (existing == null)
    {
        var message = string.Format(@"Error :: Cannot update Workbook '{0}' 
                                    because it does not exist in the database.", 
                                    entity.FileName);

        throw new Exception(message);
    }

    existing.Version = entity.Version;
    existing.DateModified = DateTime.Now;
    existing.Comments = entity.Comments;
    existing.FilePath = entity.FilePath;

    if (existing.Data != null)
        existing.Data.Clear();

    existing.Data = entity.Data;
}

以下是Get方法的实现:

public virtual T Get(Func<T, bool> where)
{
    return _dbSet.Where(where).FirstOrDefault();
}

我在这里看了一些关于类似问题的其他帖子,但没有什么像我所经历的那样。我真的被困在这里,因为我无法理解INSERT是如何工作的,但UPDATE失败了......如果有另一个事务发生不会导致任何一个动作失败?

1 个答案:

答案 0 :(得分:3)

我的第一个怀疑是你的接听电话

Get(x => x.FileName == entity.FileName);

隐式创建一个在提交工作单元之前未关闭的新线程/事务。然后,您的工作单元正在尝试在提交调用中创建一个全新的事务,这与已经打开的Get()事务冲突。

如果是这种情况,那么您可能想知道如何让Get调用在与提交调用相同的事务中运行。

修改

我相信您可以通过简单地更改

来解决问题
public virtual T Get(Func<T, bool> where)
{
    return _dbSet.Where(where).FirstOrDefault();
}

public virtual T Get(Func<T, bool> where)
{
    return _dbSet.Where(where).SingleOrDefault();
}

SingleOrDefault()应该强制序列完成“读取”并释放提交事务的连接。 (开始时也可能更安全,因为如果您的查询返回了多个结果,则从FirstOrDefault()不清楚您实际会得到哪条记录,因为没有指定排序。使用SingleOrDefault()将在返回多行的情况下抛出异常)

或者您可以尝试显式的事务范围:

public void UploadWorkbook(Workbook workbook, string uploadedBy, string comments)
{
    workbook.UploadedBy = uploadedBy;
    workbook.Comments = comments;

    using (var transaction = new TransactionScope())
    {
        var existing = _repository.Get(x => x.FileName == workbook.FileName);
        if (existing == null)
            _repository.Insert(workbook); // this works on the commit
        else
            _repository.Update(workbook); // this causes commit to fail

        _unitOfWork.Commit(); // fails when repository runs update method
        transaction.Complete();
    }
}

(另见Microsoft Connect page on this error message