OptimisticConcurrencyException - SQL 2008 R2 вместо триггера вставки с Entity Framework

Использование базы данных выпуска SQL 2008 R2 за ноябрь и приложения.net 4.0 Beta 2 Azure для рабочих ролей. Рабочая роль собирает данные и вставляет их в одну таблицу SQL с одним столбцом идентификаторов. Поскольку, вероятно, будет запущено несколько экземпляров этой рабочей роли, я создал триггер вставки вместо таблицы SQL. Триггер выполняет функцию Upsert с помощью функции SQL Merge. Используя T-SQL, я смог проверить правильность вставки вместо триггерных функций, новые строки были вставлены, в то время как существующие строки были обновлены. Это код для моего триггера:

Create Trigger [dbo].[trgInsteadOfInsert] on [dbo].[Cars] Instead of Insert
as
begin
set nocount On

merge into Cars as Target
using inserted as Source
on Target.id=Source.id AND target.Manufactureid=source.Manufactureid
when matched then 
update set Target.Model=Source.Model,
Target.NumDoors = Source.NumDoors,
Target.Description = Source.Description,
Target.LastUpdateTime = Source.LastUpdateTime,  
Target.EngineSize = Source.EngineSize
when not matched then
INSERT     ([Manufactureid]
       ,[Model]
       ,[NumDoors]
       ,[Description]
       ,[ID]
       ,[LastUpdateTime]
       ,[EngineSize])
 VALUES
       (Source.Manufactureid,
       Source.Model,
       Source.NumDoors,
       Source.Description,
       Source.ID,
       Source.LastUpdateTime,
       Source.EngineSize);
  End

В рамках рабочей роли я использую Entity Framework для объектной модели. Когда я вызываю метод SaveChanges, я получаю следующее исключение:

OptimisticConcurrencyException
Store update, insert, or delete statement affected an unexpected number of rows (0).    Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.

Я понимаю, что это похоже на то, что SQL не сообщает IdentityScope для каждой новой вставленной / обновленной строки. Затем EF считает, что строки не были вставлены, и транзакция в конечном итоге не зафиксирована.

Как лучше всего справиться с этим исключением? Может быть, используя OUTPUT из функции слияния SQL?

Спасибо! -Павел

2 ответа

Как вы и подозревали, проблема в том, что за любыми вставками в таблицу со столбцом Identity сразу же следует выбор scope_identity() для заполнения соответствующего значения в Entity Framework. Вместо триггера пропускается этот второй шаг, что приводит к ошибке вставки 0 строк.

Я нашел ответ в этом потоке Stackru, в котором предлагалось добавить следующую строку в конце вашего триггера (в случае, когда элемент не соответствует и вставка выполняется).

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

Я протестировал это с Entity Framework 4.1, и это решило проблему для меня. Я скопировал все мое создание триггера здесь для полноты. С помощью этого триггера я смог добавить строки в таблицу, добавив в контекст сущности Address и сохранив их с помощью 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

У меня был почти точно такой же сценарий: вставки на основе Entity Framework в представление с INSTEAD OF INSERT триггер на нем приводил к исключению "... неожиданное количество строк (0)...". Благодаря ответу Райана Гросса я исправил это, добавив

SELECT SCOPE_IDENTITY() AS CentrePersonID;

в конце моего триггера, где CentrePersonID Имя ключевого поля базовой таблицы, имеющей идентификатор автоинструмента. Таким образом, EF может обнаружить идентификатор вновь вставленной записи.

Другие вопросы по тегам