asp.net - INSTEAD OF INSERT 触发器导致 Entity Framework 的 SaveChanges 中出现错误

标签 asp.net sql-server web-services entity-framework-4 savechanges

这是我的第一篇文章,但我经常来这里寻找解决问题的正确解决方案。

我有一个数据库 (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 )不起作用。

我认为这在 Web 服务 (.asmx) 中工作是无关紧要的,因为我使用测试表(没有触发器)测试了 EF,并且一切正常。

在此代码中,我向 EF 添加一些对象并保存更改。

已经尝试保存循环中的更改,但这没有效果...

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

我总是以这个错误结束:

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.

我还尝试附加对象并将并发模式更改为固定, 所有这一切都不起作用..

我什至尝试了 AFTER INSERT 触发器,但这不是我想要的解决方案,我必须编写更多代码,因为它已经插入到表中。

现在有人可以解决我的问题吗?

最佳答案

我相信您需要在触发器的 UPDATE 部分设置@@identity。为此,创建一个简单的插入查询并执行它。假设MonitorSummary中有身份列id:

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 设置为零;如果是这样,您需要插入行。

关于asp.net - INSTEAD OF INSERT 触发器导致 Entity Framework 的 SaveChanges 中出现错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10432415/

相关文章:

asp.net - 如何在 Razor View 中绑定(bind) bropdown 列表(如果 View 未与任何模型绑定(bind))

c# - 使用 asp.net 网站使用序列化 json 的代码隐藏

php - PDO 不读取 MSSQL Server 的 nvarchar 数据类型

c# - WCF 服务调用失败...我的配置文件有什么问题?

c# - 从 ASP.NET Core Web 方法提供 SOAP

asp.net - 如何强制从代码隐藏进行完整回发?

c# - 想从asp.net网站发送自动邮件

c# - OR LIKE sql查询 bool 错误

java - Visualvm 中的自拍时间比其他时间长

java - 如何从 Android 应用程序调用 Java Web 服务?