Столбец идентификаторов DataTable не устанавливается после DataAdapter.Update / Refresh для таблицы с «вместо» -trigger (SqlServer 2005) - PullRequest
0 голосов
/ 31 марта 2010

В наших модульных тестах мы используем простой ADO.NET (DataTable, DataAdapter) для подготовки базы данных, соответственно. проверка результатов, в то время как сами протестированные компоненты работают под NHibernate 2.1. Версия .NET - 3.5, версия SqlServer - 2005.

Таблицы базы данных имеют идентичные столбцы в качестве первичных ключей. Некоторые таблицы применяют триггеры вместо вставки / обновления (это связано с обратной совместимостью, я ничего не могу изменить). Триггеры обычно работают так:

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), пытается извлечь значение идентификатора обратно в DataRow:

exec sp_executesql N'
insert into emp (...) values (...);
select id, ... from emp where id = @@identity
'

Но id-столбец DataRow по-прежнему равен 0. Когда я временно удаляю триггер, он работает нормально - тогда столбец id хранит значение идентификатора, установленное базой данных.

С другой стороны, NHibernate использует такой оператор вставки:

exec sp_executesql N'
insert into emp (...) values (...);
select scope_identity()
'

Это работает, у свойства NHibernate POCO свойство id установлено правильно сразу после сброса. Это кажется мне немного нелогичным, так как я ожидал, что триггер будет работать в другой области видимости, поэтому @@ identity должно подходить лучше, чем scope_identity ().

Так что я подумал, что нет проблем, я буду применять scope_identity () вместо @@ identity в ADO.NET. Но это не имеет никакого эффекта, значение DataRow по-прежнему не обновляется соответствующим образом.

А теперь самое главное: когда я копирую и вставляю эти два оператора из профилировщика SqlServer в запрос Management Studio (включая exec sp_executesql) и запускаю их там, результаты кажутся обратными! Там работает версия ADO.NET, а версия NHibernate - нет (select scope_identity () возвращает null). Я несколько раз пытался проверить, но безрезультатно. Ну, на самом деле это было то, чего я ожидал - @@ identity будет в порядке, а scope_identity () завершится ошибкой.

Конечно, его вызов в Management Studio просто показывает набор результатов, поступающий из базы данных, что бы ни происходило внутри NHibernate, а ADO.NET - другая тема. Кроме того, некоторые свойства сеанса, определенные в T-SQL SET, отличаются в двух сценариях (запрос Management Studio и приложение во время выполнения)

Это настоящая головоломка для меня. Я был бы рад любому пониманию этого. Спасибо!

1 Ответ

1 голос
/ 31 марта 2010

Нашел это. Фактически значение идентификатора было передано в DataTable, но не в ожидаемом столбце. Вместо использования существующего столбца «id» ADO.NET создал новый столбец «Column1».

Причина в том, что эта строка в конце триггера взамен:

select @@identity 

К сожалению, NHibernate, похоже, требует "select @@ identity" в конце вместо триггеров (это упоминалось в публикации на форуме Hibernate, и я подтвердил это сейчас - это действительно необходимо). Но я могу пойти отсюда (адаптация NHibernate диалекта одна возможность) ...

...