2011-08-23 91 views
2

我有一個非常簡單的映射,如:NHibernate更新版本選擇?

public abstract class EntityMap<TEnt, TId, TDto> : ClassMap<TEnt> 
    where TEnt: Entity<TId, TDto> 
    where TDto : DataTransferObject<TDto, TId> 
{ 
    protected EntityMap() 
    { 
     Id(x => x.Id).GeneratedBy.GuidComb(); 
     Map(x => x.Name).Not.Nullable().Unique().Length(255); 
     Version(x => x.Version); 
     SelectBeforeUpdate(); 
    } 

我使用該映射執行類似於測試:

[TestMethod] 
    public void ThatVersionDoesNotChangedAfterOnlyAReadAction() 
    { 
     var services = BrandServices.WithDto(BrandTestFixtures.GetDto()).Get(); 
     Assert.AreEqual(1, services.Version); 
     Context.CurrentSession().Transaction.Commit(); 
     Context.CurrentSession().Transaction.Begin(); 
     var brand = BrandServices.Brands.Single(x => x.Name == BrandTestFixtures.GetDto().Name); 
     Assert.AreEqual(1, brand.Version); 
    } 

所以,在此測試中創建映射到實體映射的對象,這對象被插入到數據庫中。在語義上,應該只有1個版本的對象。但是,會發生什麼情況是在提交後插入的對象立即用新版本更新。而且,當我再次檢索對象以檢查版本時,版本再次遞增。預期的版本應該是1,測試品牌的版本是3,但是在數據庫中版本是4!?!?!

我嘗試了各種風格的映射選項。對我來說最令人困惑的部分是,在從數據庫中檢索對象的時候版本會增加。在我的多個雙向關係的完整應用程序中,這會導致嚴重的問題。有沒有辦法修改這種行爲,還是我不得不訴諸自制的版本控制機制?

-- statement #1 
select brand0_.Id  as Id0_, 
     brand0_.Version as Version0_, 
     brand0_.Name as Name0_ 
from [Brand] brand0_ 

-- statement #2 
select brand0_.Id  as Id0_, 
     brand0_.Version as Version0_, 
     brand0_.Name as Name0_ 
from [Brand] brand0_ 

-- statement #3 
INSERT INTO [Brand] 
      (Version, 
      Name, 
      Id) 
VALUES  (1 /* @p0_0 */, 
      'Dynatra' /* @p1_0 */, 
      '8ca15020-2e23-4ace-adff-9f4800b706d5' /* @p2_0 */) 

-- statement #4 
UPDATE [Brand] 
SET Version = 2 /* @p0 */, 
     Name = 'Dynatra' /* @p1 */ 
WHERE Id = '8ca15020-2e23-4ace-adff-9f4800b706d5' /* @p2 */ 
     AND Version = 1 /* @p3 */ 

-- statement #5 
commit transaction 

-- statement #6 
begin transaction with isolation level: Unspecified 

-- statement #7 
UPDATE [Brand] 
SET Version = 3 /* @p0 */, 
     Name = 'Dynatra' /* @p1 */ 
WHERE Id = '8ca15020-2e23-4ace-adff-9f4800b706d5' /* @p2 */ 
     AND Version = 2 /* @p3 */ 

-- statement #8 
select brand0_.Id  as Id0_, 
     brand0_.Version as Version0_, 
     brand0_.Name as Name0_ 
from [Brand] brand0_ 

-- statement #9 
UPDATE [Brand] 
SET Version = 4 /* @p0 */, 
     Name = 'Dynatra' /* @p1 */ 
WHERE Id = '8ca15020-2e23-4ace-adff-9f4800b706d5' /* @p2 */ 
     AND Version = 3 /* @p3 */ 

回答

1

好的,我發現什麼是錯的。在課堂上,我是在試探我已經映射的集合,我用的是該集合的「懶惰實例化」,如:

public virtual ISet<Product> Products 
    { 
     get { return _products ?? (_products = new HashedSet<Product>(); } 
     protected set { _products = value;} 
    } 

事實證明,這是一個沒有去與NH。用NH代替你自己實現的集合實例的這件事引起了我很多頭痛,成爲NH新手。希望其他'新手'可以從中學習到。如果你想知道你在這個問題上可能做錯的一切,請閱讀我的帖子。

+0

我最喜歡的失誤,**自我改變實體** :-) http://programmers.stackexchange.com/問題/ 100534 /什麼,是最最常見的 - 錯誤 - 和反模式,NHibernate的用戶程序員-M/100535#100535 –

-1

我還發現了一個... 的問題是有:

public enum ContractValidationImportance 
{ 
    Low, 
    Neutral, 
    Intermediate, 
    High 
} 

...entity.cs 
..... 

    private ContractValidationImportance _validationImportance; 
    public ContractValidationImportance ValidationImportance 
    { 
     get { return _validationImportance; } 
     set { _validationImportance = value; } 
    } 

... entity.hbm.xml 

<property name="ValidationImportance" column="ValidationImportance" type="Int32" />