7

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

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 я receieve следующее исключение:

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. 

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

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

Спасибо! -Paul

ответ

7

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

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

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

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

И если вы делаете INSTEAD OF UPDATE, просто убедитесь, что вы «УСТАНАВЛИВАЙТЕ NOCOUNT OFF» прямо перед оператором INSERT и после этого не выполняете никаких действий. –

+0

Должен быть помечен как ответ –

3

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

SELECT SCOPE_IDENTITY() AS CentrePersonID; 

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

+0

Я только что узнал, что даже если имена полей не являются чувствительными к регистру стороне БД, имя поля как кодированное выше _is_ чувствительно к регистру и должно соответствовать точно эквивалентной кодовой стороне ключа , –

Смежные вопросы