INSTEAD OF INSERT disparador provoca un error en SaveChanges of Entity Framework

Esta es mi primera publicación, pero vengo mucho aquí para encontrar las soluciones adecuadas para mis problemas.

Tengo una base de datos (SQL Server 2008 R2) con una tabla que tiene un INSTEAD OF INSERT disparador para verificar los datos insertados.

Si es una fila duplicada, actualice esa fila; de lo contrario, inserte esa fila.

Trigger:

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

Como se puede ver, SET NOCOUNT OFF y hago la consulta de selección al final del disparador. Información extra sobre la mesa:

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
)

He probado el gatillo antes de usarlo. funciona muy bien!

Código de prueba:

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')

AHORA, el problema es que el EF (Entity Framework) no funciona.

Creo que es irrelevante que esto funcione en un servicio web (.asmx), porque probé EF con una tabla de prueba (sin el activador) y todo funciona bien.

En este código, agrego algunos objetos a EF y guardo los cambios.

Ya intenté guardar los cambios en el bucle, pero esto no tiene efecto...

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

Siempre termino con este error:

La declaración de actualización, inserción o eliminación de la tienda afectó a un número inesperado de filas (0). Es posible que se hayan modificado o eliminado entidades desde que se cargaron las entidades. Actualice las entradas de ObjectStateManager.

También he intentado Attach el objeto y cambie el modo de concurrencia a fijo, todo esto no funciona ...

Incluso probé un AFTER INSERT disparador, pero esa no es la solución que quería y tengo que codificar mucho más ya que ya está insertado en la tabla.

¿Alguien ahora una solución a mi problema?

preguntado el 03 de mayo de 12 a las 14:05

Creo que puedes obtener la respuesta de este hilo: stackoverflow.com/questions/5820992/… -

1 Respuestas

Creo que debe configurar @@identity en la parte ACTUALIZAR del disparador. Para hacerlo, cree una consulta de inserción simple y ejecútela. Suponiendo que hay una columna de identidad id en 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)

Si usa Sql Server 2005 o más reciente, hay una cláusula de salida en ACTUALIZAR que puede usar para recuperar la lista de registros modificados.

Por cierto, puede eliminar la parte existente y verificar si UPDATE establece @@rowcount en cero; si lo hizo, debe insertar filas.

contestado el 03 de mayo de 12 a las 16:05

No entiendo cómo esto es una solución al problema. ¿Cómo podrías resolver el problema? - tilito

@Tillito Si OP inserta o actualiza una fila a la vez, este código establece el último valor de identidad del sistema en el valor más alto de la ID de autonumeración de la tabla, por lo que cuando EF lo solicita, como lo hace después de la consulta, devuelve el número correcto. Pero fue hace mucho tiempo. Probablemente haya una mejor solución ahora. - Nikola Markovinovic

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.