Dans nos tests unitaires, nous utilisons ADO.NET (DataTable, DataAdapter) pour la préparation de la base de données resp. vérifier les résultats, tandis que les composants testés eux-mêmes s'exécutent sous NHibernate 2.1. La version .NET est 3.5, la version SqlServer est 2005.Colonne d'identité DataTable non définie après DataAdapter.Update/Refresh sur table avec "au lieu de" -trigger (SqlServer 2005)
Les tables de base de données ont des colonnes d'identité en tant que clés primaires. Certaines tables appliquent des déclencheurs à la place de l'insertion/mise à jour (cela est dû à la rétrocompatibilité, je ne peux rien changer). Les déclencheurs fonctionnent généralement comme ceci:
create trigger dbo.emp_insert
on dbo.emp
instead of insert
as
begin
set nocount on
insert into emp ...
select @@identity
end
L'instruction d'insertion émis par le ADO.NET DataAdapter (généré sur la volée par une enveloppe mince ADO.NET) tente de récupérer la valeur d'identité de nouveau dans le DataRow:
exec sp_executesql N'
insert into emp (...) values (...);
select id, ... from emp where id = @@identity
'
Mais id-colonne du DataRow est toujours 0. Lorsque je supprime temporairement le déclencheur, il fonctionne très bien - l'id-colonne contient la valeur d'identité définie par la base de données.
NHibernate d'autre part utilise ce type d'instruction d'insertion:
exec sp_executesql N'
insert into emp (...) values (...);
select scope_identity()
'
Cela fonctionne, le NHibernate POCO a sa propriété id correctement défini juste après le rinçage. Ce qui me semble un peu contre-intuitif, car je m'attendais à ce que le déclencheur fonctionne dans une portée différente, donc @@ identity devrait être mieux adapté que scope_identity().
Donc, je pensais pas de problème, je vais appliquer scope_identity() au lieu de @@ identity sous ADO.NET ainsi. Mais cela n'a aucun effet, la valeur DataRow n'est toujours pas mise à jour en conséquence. Et maintenant pour le mieux: lorsque je copie et collez ces deux instructions de profileur SqlServer dans une requête Management Studio (y compris "exec sp_executesql"), et les exécutez là, les résultats semblent être inverses! Là, la version ADO.NET fonctionne, et la version NHibernate ne fonctionne pas (sélectionnez scope_identity() renvoie null). J'ai essayé plusieurs fois de vérifier, mais en vain. Eh bien, en fait c'était ce que j'aurais attendu - @@ identity pour être OK, et scope_identity() pour échouer.
Bien sûr, l'invoquer dans Management Studio montre simplement le jeu de résultats provenant de la base de données, quoi qu'il arrive dans NHibernate et ADO.NET est un autre sujet. En outre, plusieurs propriétés de session définies par T-SQL SET sont différentes dans les deux scénarios (requête Management Studio vs application au moment de l'exécution)
Ceci est un vrai casse-tête pour moi. Je serais heureux de toute idée à ce sujet. Je vous remercie!