#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, который вычислял уникальное значение для сохранения в ключевом столбце. В других ситуациях (добавление и обновление) может потребоваться установить значение Вычислено.