ошибка при вставке в таблицу, имеющую вместо триггера из entity data framework

#sql-server #sql-server-2008 #entity-framework-4 #triggers

#sql-сервер #sql-server-2008 #entity-framework-4 #триггеры

Вопрос:

Я использую entity framework 4, при вставке новой записи с использованием entity framework в таблицу, которая имеет вместо триггера insert в то время как в таблице есть столбец identity, триггер вместо используется для изменения одного из вставленных значений в соответствии с определенной логикой, Entity framework вызывает исключение «Оператор обновления хранилища, вставки или удаления повлиял на неожиданное количество строк (0). Объекты, возможно, были изменены или удалены с момента загрузки объектов. Обновить записи ObjectStateManager».

Кто-нибудь может помочь, как обойти это исключение?

Комментарии:

1. есть ли причина, по которой вы не отметили правильный ответ? Приведенный ниже ответ Райана Гросса исправил эту точно такую же проблему для меня.

Ответ №1:

Используя Entity Framework 4.1, решение, опубликованное Ладиславом, чтобы добавить выбор Scope_Identity() в конец тела триггера, решило проблему для меня. Я скопировал сюда все создание триггера для полноты картины. С помощью этого определения триггера я смог добавлять строки в таблицу, используя context.SaveChanges().

 ALTER TRIGGER [dbo].[CalcGeoLoc]
   ON  [dbo].[Address]
   INSTEAD OF INSERT
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT OFF;

-- Insert statements for trigger here
INSERT INTO Address (Street, Street2, City, StateProvince, PostalCode, Latitude, Longitude, GeoLoc, Name)
SELECT Street, Street2, City, StateProvince, PostalCode, Latitude, Longitude, geography::Point(Latitude, Longitude, 4326), Name 
FROM Inserted;

select AddressId from [dbo].Address where @@ROWCOUNT > 0 and AddressId = scope_identity();
END
  

Редактировать для обработки вычисленных значений (Спасибо Крису Моргану в комментариях):

Если у вас есть какие-либо другие вычисленные значения в таблице, вам также придется включить их в SELECT. Например, если бы у вас был CreatedDate столбец, который использует GETDATE() , вы бы сделали выбор следующим образом:

 SELECT [AddressId], [CreatedDate] from [dbo].Addresses where @@ROWCOUNT > 0 and AddressId = scope_identity();
  

Комментарии:

1. Я добавил «ВЫБРАТЬ <имя_столбца> ИЗ ВСТАВЛЕННОГО;» в конец тела триггера, и это сделало свое дело.

2. Ты потрясающий. Я бы проголосовал за это 150 000 раз, если бы мог.

3. Если у вас есть какие-либо другие вычисленные значения в таблице, вам также придется включить их в SELECT. Например, если бы у вас был столбец CreatedDate, который использует GETDATE(), вы бы сделали выбор следующим образом: SELECT [AddressId], [CreatedDate] from [dbo].Addresses where @@ROWCOUNT > 0 and AddressId = scope_identity();

4. Этот ответ решил мою проблему, и он должен быть отмечен как правильный.

5. Очень полезно, но следует отметить, что это решение может не работать в будущих версиях SQL Server. Из документации по СОЗДАНИЮ ТРИГГЕРА : Возможность возвращать результаты из триггеров будет удалена в будущей версии SQL Server . Триггеры, возвращающие результирующие наборы, могут вызвать неожиданное поведение в приложениях, которые не предназначены для работы с ними. Избегайте возврата наборов результатов из триггеров в новой работе по разработке и планируйте модифицировать приложения, которые в настоящее время это делают.

Ответ №2:

Вместо триггера выполняется операция вставки, созданная Entity framework. Это может быть потенциальной проблемой, потому что после использования столбца identity за каждой вставкой следует:

 select [Id]
from [dbo].[TableXXX]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
  

Итак, вопрос в том, что происходит с этим запросом после замены insert. Если он выполняется и возвращает null, вы получаете исключение. Вы можете добавить его после вставки записи в свой триггер, но это не поможет, если исходный запрос также будет выполнен.

Вы можете изменить свой триггер, чтобы он был либо до, либо после вставки и изменения данных.

Комментарии:

1. Можете ли вы уточнить «но это не поможет, если также будет выполнен исходный запрос».

2. добавление информации к этому ответу, до того, как вставка не существует в sql server, после вставки происходит намного медленнее, чем вместо вставки.

Ответ №3:

Вам также необходимо вернуть любые свойства, помеченные как вычисляемые

 select [Id], [YourComputedColumn]
from [dbo].[TableXXX]
where @@ROWCOUNT > 0 and [Id] = scope_identity()
  

Ответ №4:

Я также обнаружил, что для параметра StoreGeneratedPattern необходимо установить значение Identity, чтобы заставить его работать со столбцом nvarchar, который я использовал в качестве первичного ключа, но который не генерировал значение identity. Это было для ситуаций с триггером after insert, который вычислял уникальное значение для сохранения в ключевом столбце. В других ситуациях (добавление и обновление) может потребоваться установить значение Вычислено.