2013-07-02 112 views
2

我想配置使用流利nhibernate操作鎖。流利NHibernate樂觀鎖

有很多的信息在那裏,但沒有看起來很適合我在類圖是場景如下(編輯爲簡潔起見):

實體:

public class EmailGroup : CRUDDomainObject<EmailGroup> 
{   
    public virtual string Id { get; set; } 
    public virtual MailServer Server { get; set;} 
    public virtual string FromAddress { get; set;} 
    public virtual string ToAddress { get; set;} 
    public virtual long Version { get; set; }  
} 

地圖:

public class EmailGroupMap : ClassMap<EmailGroup> 
{ 
    public const string TABLE_ID = "EMAILGROUP"; 

    public const string FIELD_ID = "EMAILID"; 
    public const string FIELD_MAIL_SERVER = "MAILSERVID"; 
    public const string FIELD_FROM_ADDRESS = "EMLFROM"; 
    public const string FIELD_TO_ADDRESS = "EMLTO"; 
    public const string FIELD_VERSION = "VERSION"; 

    public EmailGroupMap() 
    { 
     Table(TABLE_ID); 

     Id(x => x.Id) 
      .Column(FIELD_ID) 
      .Not.Nullable() 
      .GeneratedBy.Assigned() 
      .Length(12); 

     References(x => x.Server) 
      .Column(FIELD_MAIL_SERVER) 
      .NotFound.Ignore(); 

     Map(x => x.FromAddress) 
      .Column(FIELD_FROM_ADDRESS) 
      .Not.Nullable() 
      .Length(120); 

     Map(x => x.ToAddress) 
      .Column(FIELD_TO_ADDRESS) 
      .Not.Nullable() 
      .Length(1000); 

     Version(X => X.Version) 
      .Column(FIELD_VERSION) 
      .Generated.Always() 
      .UnsavedValue("0") 
      .Access.Property(); 

     DynamicUpdate(); 

     OptimisticLock.Version(); 
    } 
} 

在這裏我看起來很好,但是當我加載實體並修改它時,版本號不會遞增。同樣,如果我手動增加版本,而一個會話打開,我沒有得到StaleObjectException。

此配置看起來對更有經驗的眼睛有效嗎?如果有的話,我還能找到什麼?

UPDATE:

執行(當然)的數據庫管理時間戳版本的列之後被遞增。然而,NHibernate不會將該行視爲樂觀鎖定。我捕獲從SQL Server的更新查詢,以檢查在where子句(截斷簡潔):

exec sp_executesql N'UPDATE [EMAILGROUP] 
SET [EMLDESC] = @EMLDESC, [MAILSERVID] = @MAILSERVID, [EMLFROM] = @EMLFROM, [EMLTO] = @EMLTO, [EMLCC] = @EMLCC, [EMLBCC] = @EMLBCC 
WHERE [EMAILID] = @EMAILID' 
+1

您確定沒有重寫該映射的一部分的約定嗎?也可以在代碼中搜索對輔助約定的調用,例如'OptimisticLock.Is()'。 – cremor

+0

感謝cremor,雖然它不是映射被忽略,但它似乎是在對錯誤的對象進行測試,而映射存在時它並沒有被hibernate管理。更改生成後從不鎖定工作就好了。 –

回答

2

你爲什麼要指定Generated.Always()?這告訴NHibernate,這不是一個真正的列,而是由數據庫計算。文檔:http://nhibernate.info/doc/nh/en/index.html#mapping-generated

刪除,它應該工作。

+0

嗨,cremor,我修改了行,因爲你是正確的,它被設置不正確。但它沒有效果。 –

+0

這實際上是問題,它發生了我正在測試一個非託管對象。 –

2

Version和SQL Server最典型的scneario(不知道這是你的情況)是SQL類型timestamp (過時)或更好rowversion。這應該映射到C#byte[]。所以這些更改應該解決它:

1)服務器上的版本列必須是rowversion(或timestamp)類型。這樣的列會自動更新與當前行相關的任何更改。僅一個這樣的塔可以每個表

2存在)實體應該是這樣

public class EmailGroup : CRUDDomainObject<EmailGroup> 
{   
    ... 
    public virtual byte[] Version { get; set; } 

3)流利映射代碼應該保持原樣。這應該是一個流利的映射工作來做背後的技巧。我們需要實現的是這樣的:在這裏

<version name="Version" generated="always" unsaved-value="null" type="BinaryBlob"> 
    <column name="Version" not-null="false" sql-type="timestamp"/> 
</version> 

請參見更多:http://ayende.com/blog/3946/nhibernate-mapping-concurrency

+0

感謝Radim,雖然數據庫在每次更新時增加了列,但NHibernate仍然沒有生成正確的where子句進行樂觀鎖定,並且沒有生成過時的對象異常,導致我相信問題在別處。我用生成的SQL更新了這個問題。 –

+0

我看不到更新。但是我肯定會建議你在服務器上保留版本的更新。這可以保證,即使其他一些進程(批處理,管理...)也會改變數據,版本將會不同。 –

+0

我現在看到更新。我在映射中唯一的區別是Unsaved值,對於二進制blob是NULL。你能檢查一下嗎?其他設置對我來說也是一樣的(我確實希望你使用'rowversion'而不是'long') –