竞争条件使nHibernate创建重复条目

时间:2013-07-09 08:56:11

标签: c# multithreading sql-server-2008 nhibernate race-condition

我在nHibernate上有一个竞争条件,它在我的数据库上创建了重复的条目。不幸的是,我无法在数据库上创建UNIQUE索引,因此我想仅使用nHibernate方法来解决此错误。它是一个可能在Web场上运行的Web应用程序(因此我猜系统锁不应该解决问题)。简化的情况如下:

var current = UnitOfWorkManager.Instance.Current;
current.BeginTransaction(IsolationLevel.Serializable);
try {

    var myEntity = MyFactory.MyEntityRepository.GetBy(product, company);
    // race condition happens between the previous statement and Save() method.

    if (myEntity == null)
    {
      myEntity = new MyEntity();
      myEntity.Product     = product;
      myEntity.Company     = company;
      myEntity.Date        = date;
      myEntity.CurrentUser = currentUser;
      myEntity.IsManual    = true;
      myEntity.Save();
    }
    else
    {
      myEntity.IsManual    = false;
      myEntity.Save();
    }
    current.CommitTransaction();
}
catch {
    current.RollbackTransaction();
    throw;
}

我是nHibernate的新手,所以也许我在这里缺少一些基础知识。我很感激任何反馈。 :)

3 个答案:

答案 0 :(得分:1)

阅读nHibernate手册后,我认为如果subProjectToSupplier不为null,您的问题可能是第二次保存。因为nHibernate手册说“保存”会插入。

尝试SaveOrUpdate

答案 1 :(得分:0)

您应该将Save()包装在一个交易中,理想情况下,您可以实施IUnitOfWork等模式或使用SessionFactory,例如:

using (var transaction = session.BeginTransaction()) {
  myEntity = new MyEntity();
  myEntity.Product = product;
  myEntity.Company = company;
  myEntity.Date = date;
  myEntity.CurrentUser = currentUser;
  myEntity.IsManual = true;
  myEntity.Save();
  transaction.Commit();
}

答案 2 :(得分:0)

好的,所以你在这里要求NHibernate解决方案。我不确定这是否可以100%解决你的问题,但试试这个。

  1. 使用ReadCommitted隔离级别。
  2. 根据您的需要实施拦截器http://nhibernate.info/doc/nh/en/#manipulatingdata-interceptors
  3. 在拦截器中你可以做到:

    1. 如果您的唯一列上有记录,请查询数据库。然后你可以应用某种合并机制
    2. 检查当前会话是否还有其他像您要继续存在的对象。
    3. =====

      其他解决方案是在服务器场(memcache)和跟踪您不希望重复的对象之间保持共享缓存。

      PS:我可以多谈谈每一点。只要告诉我一些事情听起来像是你的解决方案