単体テストでは、データベース応答を準備するためにプレーンなADO.NET(DataTable、DataAdapter)を使用します。テストされたコンポーネント自体はNHibernate2.1で実行されますが、結果を確認します。.NETバージョンは3.5、SqlServerバージョンは2005です。
データベーステーブルには、主キーとしてID列があります。一部のテーブルは、挿入/更新の代わりにトリガーを適用します(これは下位互換性のためであり、変更することはできません)。トリガーは通常、次のように機能します。
create trigger dbo.emp_insert
on dbo.emp
instead of insert
as
begin
set nocount on
insert into emp ...
select @@identity
end
ADO.NET DataAdapter(シンADO.NETラッパーによってオンザフライで生成される)によって発行された挿入ステートメントは、ID値をDataRowに取得しようとします。
exec sp_executesql N'
insert into emp (...) values (...);
select id, ... from emp where id = @@identity
'
ただし、DataRowのid-Columnはまだ0です。トリガーを一時的に削除すると、正常に機能します。id-Columnは、データベースによって設定されたID値を保持します。
一方、NHibernateはこの種の挿入ステートメントを使用します。
exec sp_executesql N'
insert into emp (...) values (...);
select scope_identity()
'
これは機能し、NHibernatePOCOのidプロパティはフラッシュ直後に正しく設定されます。トリガーが別のスコープで実行されることを期待していたので、これは少し直感に反しているように見えます。したがって、@@identityはscope_identity()よりも適しているはずです。
したがって、問題はないと思いました。ADO.NETでも@@identityの代わりにscope_identity()を適用します。ただし、これによる影響はなく、DataRow値はそれに応じて更新されません。
そして今、最良の部分は、これら2つのステートメントをSqlServerプロファイラーからManagement Studioクエリ( "exec sp_executesql"を含む)にコピーして貼り付け、そこで実行すると、結果が逆になっているように見えることです。そこでは、ADO.NETバージョンは機能しますが、NHibernateバージョンは機能しません(select scope_identity()はnullを返します)。確認を数回試みましたが、役に立ちませんでした。まあ、実際にはそれは私が期待していたことでした-@@ identityはOKであり、scope_identity()は失敗します。
もちろん、Management Studioで呼び出すと、データベースからの結果セットが表示されるだけです。NHibernateとADO.NET内で発生することはすべて別のトピックです。また、T-SQL SETによって定義されたいくつかのセッションプロパティは、2つのシナリオ(Management Studioクエリと実行時のアプリケーション)で異なります。
これは私にとって本当のパズルです。それについての洞察があれば嬉しいです。ありがとうございました!