2012-11-16 52 views
1

我有一個問題,我試圖重新插入一個實體到我的數據庫。它說明與下面的單元測試:NHibernate的插入與identity_insert ON

 // entity mapped to dbo.IdentityInsertTest table 
     // dbo.IdentityInsertTest has an IDENTITY Primary Key, Id 
     var id = (long)NHibernateSession1.Save(new IdentityInsertTest()); 
     NHibernateSession1.Flush(); 

     // delete previously created row 
     ExecuteNonQuery("DELETE FROM dbo.IdentityInsertTest"); 

     try 
     { 
      // set entity insert off so that I can re-insert 
      NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult(); 

      // re-create deleted row with explicit Id 
      NHibernateSession2.Save(new IdentityInsertTest { Id = id }); 
      NHibernateSession2.Flush(); 

      Assert.AreEqual(1, ExecuteScalar("SELECT COUNT(1) FROM dbo.IdentityInsertTest")); 

      // this assert fails: expected 1, actual 2 
      Assert.AreEqual(id, ExecuteScalar("SELECT TOP 1 [Id] FROM dbo.IdentityInsertTest")); 
     } 
     finally 
     { 
      NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest OFF").UniqueResult(); 
     } 

我的映射很簡單:

<class name="IdentityInsertTest" table="IdentityInsertTest"> 
    <id name="Id" type="long"> 
     <generator class="native" /> 
    </id> 

    <property name="Data" type="int" not-null="false" /> 
</class> 

的問題,據我可以看到它是NHibernate的發電機仍然以某種方式調用身份生成從SQL,即使我已經關閉它。有沒有辦法解決?

編輯:我原本忘記在設置IDENTITY_INSERT時執行「UniqueResult()」,但這似乎不是錯誤的根源。仍然得到同樣的結果

+0

你想在表格中間的某處添加一個實體嗎?或者想在最後添加一個實體?我真的不明白你的邏輯,你爲什麼需要這樣做? – Rippo

+0

如另一條評論所述,這是在雲應用程序中實現撤銷/重做邏輯,缺少自然鍵 – Shane

+0

如果所有表都是標識列,並且您擁有數據庫完整性,那麼爲什麼密鑰必須返回原始位置州?我的評論也在你澄清之前......對不起,但我仍然不知道;得到你的邏輯 – Rippo

回答

2

注:我已經打上這個作爲回答,因爲它直接回答了這個問題,但是,在我與去年底如上述評論

軟刪除選項的問題是,

  1. 我沒有明確的保存方法指定編號
  2. 我就算了,設置IDENTITY_INSERT禾已經在另一個查詢中執行了。那一個是通過使用交易

    // entity mapped to dbo.IdentityInsertTest table 
    // dbo.IdentityInsertTest has an IDENTITY Primary Key, Id 
    var id = (long)NHibernateSession1.Save(new IdentityInsertTest()); 
    NHibernateSession1.Flush(); 
    
    // delete previously created row 
    ExecuteNonQuery("DELETE FROM dbo.IdentityInsertTest"); 
    
    try 
    { 
        NHibernate.ITransaction txn; 
        using (txn = SelectSession1.BeginTransaction()) 
        { 
         // set entity insert off so that I can re-insert 
         NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult(); 
    
         // re-create deleted row with explicit Id 
         NHibernateSession2.Save(new IdentityInsertTest(), id); 
         NHibernateSession2.Flush(); 
    
         txn.Commit(); 
        } 
    
        Assert.AreEqual(1, ExecuteScalar("SELECT COUNT(1) FROM dbo.IdentityInsertTest")); 
    
        // this assert fails: expected 1, actual 2 
        Assert.AreEqual(id, ExecuteScalar("SELECT TOP 1 [Id] FROM dbo.IdentityInsertTest")); 
    } 
    finally 
    { 
        NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest OFF").UniqueResult(); 
    } 
    
4

你是不是真正執行你的SQLQuery,這應該做的伎倆

IQuery sqlQry = NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON"); 
object ret = sqlQry.UniqueResult(); 
+0

我已更改我的代碼以包含此內容,但未改變結果。感謝您指出它,它將在稍後成爲問題。 – Shane

1

選擇另一個鍵生成策略,你正在試圖做的是一個非常糟糕的主意。標識列是人爲的主鍵,它不應該有任何意義。

+0

在這個階段,這是一個非常大的步驟,我不完全理解你的觀點「身份列是人爲主鍵」。你知道任何我可以閱讀的文章來澄清? – Shane

+0

Google代理與自然主鍵。自然主鍵(如社會安全號碼)在現代系統中很少使用。 SQL標識列是代理鍵;除了唯一標識記錄之外,這種類型的鍵沒有意義。設計良好的系統不需要插入具有特定代理鍵的記錄。你想解決什麼問題? –

+0

我看到你在看什麼,但這些數據沒有自然的關鍵。整個問題源於在雲(基於瀏覽器)應用程序中實現備忘錄撤消模式。 我使用的身份作爲一個自然的關鍵,因爲我沒有其他 – Shane

3

只是想知道你的邏輯在這裏就刪除/重新添加相對於不刪除,但只是更新....

但是,如果NHibernate的是在你的方式,你不能改變刪除標識列則有如果你想添加一條記錄somewhe

var sql = "DECLARE @id long = 0; 
    SELECT @id = MAX(Id) + 1 FROM IdentityInsertTest; 
    DBCC CHECKIDENT(IdentityInsertTest, RESEED, @id);"; 

    NHibernateSession2.CreateSqlQuery(sql).ExecuteUpdate(); 

    ... now save the entity normally 

OR - :一些難看的變通......

如果你想在bottom添加一條記錄,那麼你可以試試這個再在表的middle,那麼你將要興建手工SQL: -

var sql = "SET IDENTITY_INSERT dbo.IdentityInsertTest ON; 
    INSERT INTO IdentityInsertTest(Id, Data) Values (:id, :data) 
    VALUES (:id, :data); 
    SET IDENTITY_INSERT dbo.IdentityInsertTest OFF;"; 

    NHibernateSession2.CreateSqlQuery(sql) 
     .SetInt64("id", id) 
     .SetInt32("data", data) 
     .ExecuteUpdate(); 
+0

這個答案指出了我的正確方向。這個問題(或其中之一)是,NHibernate並沒有在像上面這樣的併發語句中執行整個事情 – Shane

+0

很高興你到了那裏,也許你至少可以投我:) – Rippo

+0

+1「可怕的工作周圍」。 –

0

我不得不說固定的,這個問題我堵塞時間長。即使通過我執行SQL「SET IDENTITY_INSERT dbo.IdentityInsertTest ON」之前,然後運行Nihbernate代碼,它stil不起作用。有2點需要更多attation。

首先,您必須在您的代碼中使用Transaction。

NHibernate.ITransaction txn; 
using (txn = SelectSession1.BeginTransaction()) 
{ 
    NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult(); 

    ... 

    NHibernateSession2.Flush(); 
    txn.Commit(); 
} 

其次,必須使用 「ID(X => x.Id).GeneratedBy 分配().COLUMN。(」 ID 「);」在你的映射部分。