2

別の行にある一意の列の複製である列を持つ行を挿入しようとする統合テストがあります。行を挿入するには、エンティティ リポジトリにある次のコードを呼び出します。

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 Profiler に表示されることがわかります。そのステートメントの直後に、次の警告とエラーが表示されます。

-- ステートメント #1 警告: System.Data.SqlClient.SqlException (0x80131904): UNIQUE KEY 制約の違反 'UQ_ Contract_C51D43DA5070F446'. オブジェクト 'dbo.Contracts' に重複するキーを挿入できません。重複キーの値は (1005171) です。ステートメントは終了されました。System.Data.SqlClient.SqlConnection.OnError (SqlException 例外、ブール型 breakConnection) で System.Data.SqlClient.SqlInternalConnection.OnError (SqlException 例外、ブール型 breakConnection) で System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() で System.Data .SqlClient.TdsParser.Run(RunBehavior runBehavior、SqlCommand cmdHandler、SqlDataReader dataStream、BulkCopySimpleResultSet bulkCopyHandler、TdsParserStateObject stateObj) System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds、RunBehavior run、文字列 resetOptionsString) で System.Data.SqlClient.SqlBehaviorCommand .RunExecuteReaderTds(CommandBehavior cmdBehavior,

-- ステートメント #2 エラー: UNIQUE KEY 制約 'UQ_ Contract _C51D43DA5070F446' の違反。オブジェクト 'dbo.Contracts' に重複するキーを挿入できません。重複キーの値は (1005171) です。ステートメントは終了されました。

-- ステートメント #3 エラー: バッチ コマンドを実行できませんでした。[SQL: SQL を使用できません]データベースの状態をセッションと同期できませんでした

-- ステートメント #4 ロールバック トランザクション

このテストの後、多くのクエリ テストを行ったところ、同じリポジトリの更新ステートメントに到達するまで、すべてが正常に機能しているように見えます。呼び出されるコードは次のとおりです。

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

プロファイラーを確認すると、更新が呼び出されたことが示され、その直後に次のステートメントが表示されます。

-- ステートメント #1 警告: System.Data.SqlClient.SqlException (0x80131904): UNIQUE KEY 制約の違反 'UQ_ Contract_C51D43DA5070F446'. オブジェクト 'dbo.Contracts' に重複するキーを挿入できません。重複キーの値は (1005171) です。ステートメントは終了されました。System.Data.SqlClient.SqlConnection.OnError (SqlException 例外、ブール型 breakConnection) で System.Data.SqlClient.SqlInternalConnection.OnError (SqlException 例外、ブール型 breakConnection) で System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() で System.Data .SqlClient.TdsParser.Run(RunBehavior runBehavior、SqlCommand cmdHandler、SqlDataReader dataStream、BulkCopySimpleResultSet bulkCopyHandler、TdsParserStateObject stateObj) System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds、RunBehavior run、文字列 resetOptionsString) で System.Data.SqlClient.SqlBehaviorCommand .RunExecuteReaderTds(CommandBehavior cmdBehavior,

-- ステートメント #2 エラー: UNIQUE KEY 制約 'UQ_ Contract _C51D43DA5070F446' の違反。オブジェクト 'dbo.Contracts' に重複するキーを挿入できません。重複キーの値は (1005171) です。ステートメントは終了されました。

-- ステートメント #3 エラー: バッチ コマンドを実行できませんでした。[SQL: SQL を使用できません]データベースの状態をセッションと同期できませんでした

私が見る限り、insert ステートメントが NHibernate を失敗状態にしたようです。上記の更新コードは、SQL Not Available という GenericADOException をスローします。私はここで何か間違ったことをしているに違いありません。例外を別の方法で処理する必要がありますか?

4

1 に答える 1

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
于 2012-10-19T08:40:16.803 に答える