1

向我的数据库添加帖子时遇到问题,这个“添加”函数是从多个线程调用的。而且通常在彼此之后很快,我不知道这是否重要,但这就是它的工作方式。

代码:

private object dbLock = new object();

public void Add(string fileName, DateTime collectionTime)
    {
        try
        {
            lock (dbLock)
            {
                var collection = new Collection
                {
                    Filename = fileName,
                    Datetime = collectionTime,
                };
                _entities.AddToCollection(collection);
                _entities.SaveChanges();
                CollectionChanged(collection, null);
            }
        }
        catch (Exception ex)
        {
        }
        finally
        {

        }
    }

我的问题是,当 SaveChanges 被调用时,我得到了这个异常:

对数据库的更改已成功提交,但在更新对象上下文时出错。ObjectContext 可能处于不一致的状态。内部异常消息:AcceptChanges 无法继续,因为对象的键值与 ObjectStateManager 中的另一个对象冲突。在调用 AcceptChanges 之前确保键值是唯一的。

我设法找到的所有答案都与您必须添加的有关StoreGeneratedPattern="Identity",我已经这样做了,但这无济于事

<Property Name="ID" Type="integer" Nullable="false" StoreGeneratedPattern="Identity" />

那么还有其他方法可以解决这个问题吗?

4

1 回答 1

3

最终,在线程之间共享对象上下文是一个非常糟糕的主意。对象上下文旨在用作工作单元- 即短暂的;典型用法:

using(var ctx = new SomeObjectContextType()) // assuming IDisposable
{
    // not shown: get some records, if needed
    ...
    // not shown: update, add, remove some records, if needed

    ctx.SaveChanges();
} // and now it is gone, never to be used again

在某些情况下,它可能会这更复杂一些,例如在页面/请求期间保留一个对象上下文,但它应该在调用者之间共享。造成这种情况的原因很多,但基本上所有竞争更新都需要锁定,这里的“更新”包括从数据库读取任何记录或延迟加载属性的简单行为。一个对象上下文在被多个线程访问时会变得脾气暴躁,这不足为奇:(通常)不支持这种情况

此外,拥有长寿命对象上下文还有其他问题:

  • 有时,事情会变糟(例如超时、死锁、回滚或只是一个简单的连接错误);在这里,适当的响应方式就是简单地丢弃你现在损坏的对象上下文(Dispose()如果合适的话)——然后忘记它;如果你想重新应用你的改变,你从一个的对象上下文开始
  • 对象上下文包括身份映射和变更管理系统;如果您将其保存的时间超过一次操作,那么您正在慢慢地将越来越多的对象累积到其中;除了导致内存问题之外,这还会逐渐降低性能 - 因为现在每个读取/更新操作都有越来越多的数据需要拖网

基本上,这里的“修复”是:不要那样做。这不是对象上下文的正确用法。没有应用程序范围的共享对象上下文。

于 2013-06-18T08:39:42.813 回答