0

単体テストでは、データベース応答を準備するためにプレーンな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クエリと実行時のアプリケーション)で異なります。

これは私にとって本当のパズルです。それについての洞察があれば嬉しいです。ありがとうございました!

4

1 に答える 1

1

それを見つけた。ID 値は実際には DataTable に送信されましたが、期待した列には送信されませんでした。既存の列「id」を使用する代わりに、ADO.NET は新しい列「Column1」を作成しました。

理由は、代わりのトリガーの最後にある次の行です。

select @@identity 

残念ながら、NHibernate では、代わりのトリガーの最後に "select @@identity" が必要なようです (これは Hibernate フォーラムの投稿で言及されており、今もう一度確認しましたが、実際に必要です)。しかし、私はここから行くことができます (NHibernate の方言を適応させることは 1 つの可能性です)...

于 2010-03-31T14:06:53.117 に答える