3

我有一個nHibernate競爭條件,這是在我的數據庫上創建重複條目。不幸的是,我不能在數據庫上創建一個UNIQUE索引,因此我只想用nHibernate方法來解決這個錯誤。這是一個Web應用程序,可能運行在網上農場(因此我猜系統鎖也不應該解決問題)。簡化情況如下:競爭條件使nHibernate創建重複條目

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的新手,所以也許我缺少一些基礎知識。我會很感激任何反饋。 :)

+0

myEntity.Save();應該在交易中。 –

+2

你的競賽狀況的性質不是很清楚。 –

+0

您正在查找的數據庫概念是一項交易。您需要創建一個鎖定事務,以便從GetBy開始更新並在保存結束。然而,我可以告訴你如何在Hibernate中做到這一點。 –

回答

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(); 
} 
+0

謝謝@Darren Davies,但我已經使用UnitOfWork實現來創建一個事務(我更新了問題以顯示它)。我得到的一點是,似乎沒有什麼可以鎖定,因爲沒有從存儲庫中獲取記錄,所以兩個線程都可以創建它們的實例......任何想法? –

+0

@GerardoLima - 可能有一個布爾值,指示它正在創建一個新類型的'MyEntity',因此另一個事務必須等到它完成。 –

+0

@達倫戴維斯 - 這個建議看起來像創造一個'鎖'。然後我遇到問題:我應該在哪裏鎖定?由於系統運行在Web場中,創建應用程序(或機器)智能鎖是不可行的,我不知道任何告訴nHibernate將這樣的鎖放在數據庫上的方法...... –

0

好了,你所要求的NHibernate的解決方案在這裏。我不確定這是否可以100%解決您的問題,但試試這個。

  1. 使用ReadCommitted隔離級別。
  2. 您的需求http://nhibernate.info/doc/nh/en/#manipulatingdata-interceptors

在你能做的攔截器實現一個攔截器:

  1. 查詢數據庫,如果有你的唯一列的記錄。然後,您可以應用某種合併機制
  2. 檢查當前會話是否還有其他對象,例如未決的持久保留。

================

其他解決辦法是保持的共享緩存農場(內存緩存)之間並跟蹤對象,你不想被複制。 PS:我可以更多地談論每一點。只要告訴我是否聽起來像是一種解決方案

+0

其實我沒有經歷過在nHibernate上 - 我不知道Interceptor是什麼 - 所以如果你詳細解釋了這個建議,我會很感激。 –

1

閱讀nHibernate手冊後,我認爲你的問題可能是你的第二次調用來保存subProjectToSupplier是否爲空。因爲nHibernate手冊說「保存」插入。

嘗試SaveOrUpdate

+0

在這種特殊情況下,我需要將新行插入到數據庫中或失敗。 –

+0

但是'SaveOrUpdate'不應該解決問題,因爲它是基於ID的,並且會爲每個實體實例創建一個新的不同ID ... –

+0

如果您的數據已過時,您的一個保存調用必須是你的問題。如果不是第二個,那麼它必須是第一個。您的新實體獲得您之前搜索過的同一產品和公司。 – user743414