2012-10-18 36 views
2

我有一個集成測試,嘗試插入一行的行與另一行所具有的唯一列的副本相同。要插入該行,我把這個代碼,在我的實體庫中找到:使用NHibernate插入失敗後SQL不可用

using (var transaction = rb.unitOfWork.Session.BeginTransaction()) 
     { 
      try 
      { 
       ret = (Key)rb.unitOfWork.Session.Save(entity); 
       transaction.Commit(); 
       rb.unitOfWork.Session.Clear(); 
      } 
      catch 
      { 
       transaction.Rollback(); 
       rb.unitOfWork.Session.Clear(); 
       throw; 
      } 
     } 

當這個代碼與重複的實體運行,我可以看到插入NHibernate的探查才能通過。這句話後,我看到這些警告和錯誤:

-- statement #1 WARN: System.Data.SqlClient.SqlException (0x80131904): Violation of UNIQUE KEY constraint 'UQ_Contract_C51D43DA5070F446'. Cannot insert duplicate key in object 'dbo.Contracts'. The duplicate key value is (1005171). The statement has been terminated. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at System.Data.SqlClient.SqlCommand.ExecuteBatchRPCCommand() at System.Data.SqlClient.SqlCommandSet.ExecuteNonQuery() at NHibernate.AdoNet.SqlClientSqlCommandSet.ExecuteNonQuery() at NHibernate.AdoNet.SqlClientBatchingBatcher.DoExecuteBatch(IDbCommand ps)

-- statement #2 ERROR: Violation of UNIQUE KEY constraint 'UQ_Contract_C51D43DA5070F446'. Cannot insert duplicate key in object 'dbo.Contracts'. The duplicate key value is (1005171). The statement has been terminated.

-- statement #3 ERROR: could not execute batch command.[SQL: SQL not available]Could not synchronize database state with session

-- statement #4 rollback transaction

此測試後,我做了很多查詢的測試,一切似乎是工作的罰款,直到我打了同一個版本庫的更新語句。下面是被調用的代碼:

using (var transaction = rb.unitOfWork.Session.BeginTransaction()) 
     { 
      rb.unitOfWork.Session.SaveOrUpdate(entity); 
      transaction.Commit(); 
      rb.unitOfWork.Session.Clear(); 
     } 
     rb.unitOfWork.Session.Evict(entity); 

檢查探查表明,該更新被調用,鑽之後,我得到這些語句:

-- statement #1 WARN: System.Data.SqlClient.SqlException (0x80131904): Violation of UNIQUE KEY constraint 'UQ_Contract_C51D43DA5070F446'. Cannot insert duplicate key in object 'dbo.Contracts'. The duplicate key value is (1005171). The statement has been terminated. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at System.Data.SqlClient.SqlCommand.ExecuteBatchRPCCommand() at System.Data.SqlClient.SqlCommandSet.ExecuteNonQuery() at NHibernate.AdoNet.SqlClientSqlCommandSet.ExecuteNonQuery() at NHibernate.AdoNet.SqlClientBatchingBatcher.DoExecuteBatch(IDbCommand ps)

-- statement #2 ERROR: Violation of UNIQUE KEY constraint 'UQ_Contract_C51D43DA5070F446'. Cannot insert duplicate key in object 'dbo.Contracts'. The duplicate key value is (1005171). The statement has been terminated.

-- statement #3 ERROR: could not execute batch command.[SQL: SQL not available]Could not synchronize database state with session

從我所看到的,似乎像插入語句將NHibernate置於失敗狀態。上面的更新代碼拋出一個聲明SQL不可用的GenericADOException。我一定在這裏做錯了事。我應該以不同的方式處理異常嗎?

回答

2

假設您使用Identity或任何其他PostInsert Id生成器,如果插入錯誤,它仍然沒有設置id,並且下一個SaveOrUpdate將嘗試再次插入它,因爲它認爲它是未保存的實例,導致再次出現錯誤。

try { 
    session.Save(entity); // has duplicate key 
} catch {} 

Assert(entity.Id, Key.Unsaved); 

session.SaveOrUpdate(entity2); // will issue INSERT and throws again