Триггер INSTEAD OF INSERT вызывает ошибку в SaveChanges Entity Framework

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

У меня есть база данных (SQL Server 2008 R2) с таблицей, которая имеет INSTEAD OF INSERT триггер для проверки вставленных данных.

Если это дублированная строка, обновите эту строку; в противном случае вставьте этот ряд.

Спусковой крючок:

ALTER TRIGGER [dbo].[CheckDataTrigger]
    ON [dbo].[MonitorSummary]
    INSTEAD OF INSERT
AS 
BEGIN
    SET NOCOUNT OFF

    IF exists( select * from inserted i, MonitorSummary ms
            where ms.ServiceUrl = i.ServiceUrl
                AND ms.AppName = i.AppName
                AND ms.BuildVersion = i.BuildVersion
                AND ms.FunctionName = i.FunctionName
                AND ms.Company = i.Company
                AND ms.UserName = i.UserName
                AND ms.ServerName = i.ServerName)
    BEGIN
       UPDATE MonitorSummary  
       SET MonitorSummary.Function_Count = inserted.Function_Count,
           MonitorSummary.Execution_Time_Sum = inserted.Execution_Time_Sum,
           MonitorSummary.LogLevel = inserted.LogLevel
       FROM inserted
       WHERE MonitorSummary.ServiceUrl = inserted.ServiceUrl
       AND MonitorSummary.AppName = inserted.AppName
       AND MonitorSummary.BuildVersion = inserted.BuildVersion
       AND MonitorSummary.FunctionName = inserted.FunctionName
       AND MonitorSummary.Company = inserted.Company
       AND MonitorSummary.UserName = inserted.UserName
       AND MonitorSummary.ServerName = inserted.ServerName
    END
    ELSE
    BEGIN
      INSERT INTO MonitorSummary
         SELECT 
             i.ServiceUrl, i.EmailAdress, i.EmailSent, i.AppName, i.BuildVersion, 
             i.FunctionName, i.Company, i.UserName, i.ServerName, i.Function_Count, 
             i.Execution_Time_Sum, i.LogLevel
         FROM inserted i
    END

    SELECT Monitor_Id 
    FROM MonitorSummary 
    WHERE @@ROWCOUNT > 0 AND Monitor_Id = SCOPE_IDENTITY()
END

Как вы видете, SET NOCOUNT OFF и я делаю запрос выбора в конце триггера. Дополнительная информация о столе:

CREATE TABLE [dbo].[MonitorSummary](
    [Monitor_Id] [int] IDENTITY(1,1) NOT NULL,
    [ServiceUrl] [nvarchar](100) NULL,
    [EmailAdress] [nvarchar](100) NULL,
    [EmailSent] [bit] NOT NULL default 0,
    [AppName] [nvarchar](100) NULL,
    [BuildVersion] [nvarchar](100) NULL,
    [FunctionName] [nvarchar](100) NULL,
    [Company] [nvarchar](100) NULL,
    [UserName] [nvarchar](100) NULL,
    [ServerName] [nvarchar](100) NULL,
    [Function_Count] [int] NOT NULL default 0,
    [Execution_Time_Sum] [numeric](18, 8) NOT NULL default 0,
    [LogLevel] [nvarchar](50) NULL,
PRIMARY KEY CLUSTERED 
(
    [Monitor_Id] ASC
)

Я проверил триггер, прежде чем использовать его. это прекрасно работает!

Тестовый код:

INSERT INTO MonitorSummary VALUES
    ('ServiceUrl2', 'EmailAdress2', 0, 'AppName2', 'BuildVersion2', 'FunctionName2',
        'Company2', 'UserName2', 'ServerName2', 1, 1, 'LogLevel2'),
    ('ServiceUrl2', 'EmailAdress2', 0, 'AppName2', 'BuildVersion2', 'FunctionName2',
        'Company3', 'UserName2', 'ServerName2', 1, 1, 'LogLevel2'),                 
    ('ServiceUrl3', 'EmailAdress3', 0, 'AppName2', 'BuildVersion2', 'FunctionName2',
        'Company2', 'UserName2', 'ServerName2', 1, 1, 'LogLevel2'),
    ('ServiceUrl3', 'EmailAdress3', 0, 'AppName2', 'BuildVersion2', 'FunctionName2',
        'Company2', 'UserName2', 'ServerName2', 2, 2, 'LogLevel2')

СЕЙЧАС проблема в том, что EF (Entity Framework) не работает.

Я думаю, что не имеет значения, что это работает в веб-сервисе (.asmx), потому что я тестировал EF с тестовой таблицей (без триггера), и все просто отлично работает.

В этом коде я добавляю некоторые объекты в EF и сохраняю изменения.

Уже пытались сохранить изменения в цикле, но на это это никак не влияет...

private void StoreData(MonitorSummary[] data)
{
    foreach (MonitorSummary item in data)
    {
        MonitorEntity.MonitorSummary.AddObject(item);
        //MonitorEntity.SaveChanges();
    }
    MonitorEntity.SaveChanges();
}

Я всегда заканчиваю эту ошибку:

Оператор хранения, обновления или удаления затронул неожиданное количество строк (0). Объекты могут быть изменены или удалены с момента загрузки объектов. Обновите записи ObjectStateManager.

Я также пытался Attach объект и изменить режим параллелизма на фиксированный, все это не работает..

Я даже попробовал AFTER INSERT триггер, но это не то решение, которое я хотел, и я должен кодировать намного больше, так как он уже вставлен в таблицу..

У кого-нибудь сейчас есть решение моей проблемы?

1 ответ

Решение

Я считаю, что вам нужно установить @@identity в части UPDATE триггера. Для этого создайте простой запрос вставки и выполните его. Предполагая, что есть столбец идентичности id в MonitorSummary:

declare @strSql varchar(1000)
declare @id int

select @id = max (id) 
  from MonitorSummary
 where -- whole join condition to identify changed record(s)

set @strSql = 'SELECT Identity (Int, ' + Cast(@id As Varchar(10)) + ',1) AS id 
                     INTO #Tmp'
EXECUTE (@strSql)

Если вы используете Sql Server 2005 или новее, в UPDATE есть предложение вывода, которое вы можете использовать для получения списка измененных записей.

Кстати, вы можете удалить существующую часть и проверить, если UPDATE устанавливает @@rowcount в ноль; если это так, вам нужно вставить строки.

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