asp.net-mvc-4 - EF 并发导致触发器出现问题

标签 asp.net-mvc-4 entity-framework-4.1

在我的 SQL 表 (2008) 中,我有一个名为 Timestamp 的时间戳列。

在我的 .Net 项目中,我有一个带有属性的 POCO 类

public byte[] Timestamp {get; set;}

在我的配置代码中,我有以下内容:

Property(p => p.Timestamp).IsRowVersion();

现在,如果我打开两个编辑屏幕,在其中一个编辑屏幕中进行更改并保存(接受保存),然后在第二个编辑屏幕中进行更改并保存(保存被 DbUpdateConcurrencyException 拒绝)。

我觉得奇怪的一件事是,即使我收到并发异常,SQL Profiler 也会显示更新请求正在发送到 SQL 数据库。更新未在数据库上提交,但已发送。这正常吗?我有点希望 EF 提前检查这一点,甚至不发送请求。

最后,如果我在此表上启用触发器:

ALTER TRIGGER [dbo].[trg_person_log_changes]
   ON  [dbo].[Person]
   AFTER INSERT,DELETE,UPDATE
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @auditBody XML
DECLARE @actionType char(1)
DECLARE @username nvarchar(100)

if not exists(select * from deleted)
    Begin
        SET @actionType = 'I'
        SET @username = (select Case 
                                    When lastchangedby is null or lastchangedby = '' then Suser_name()
                                    Else lastchangedby
                                End  
                         from inserted)
    End
else if not exists(select * from inserted)
    Begin
        SET @actionType = 'D'
        SET @username = Suser_name()
    End
else
    Begin
        SET @actionType = 'U'
        SET @username = (select distinct Case 
                                    When lastchangedby is null or lastchangedby = '' then Suser_name()
                                    Else lastchangedby
                                End  
                         from inserted)
    End

If @actionType = 'I'
    Set @auditBody = (select 'Person' as "@tableName",  'True' as "@synch",
      (select * from inserted for xml path('DataItem'), type, binary base64)
      for xml path('Root'))
Else
    SET @auditBody = (select 'Person' as "@tableName", 'True' as "@synch",
      (select * from deleted for xml path('DataItem'), type, binary base64)
      for xml path('Root'))

insert into [dbo].[AuditLog]
           ([Action]
           ,[ActionDate]
           ,[ActionUser]
           ,[AuditData]
           )
    values (
           @actionType
           ,getdate()
           ,@username
           ,@auditBody)
END

现在,当我尝试保存第二次编辑时,我不再收到 DbUpdateConcurrencyException,而是收到一条错误,指出 ActionUser 不能为空。我再次认为我的触发器正在执行,因为即使存在冲突,EF 也允许更新进行。

关于我可能做错了什么有什么想法吗?

注意

这是一个 MVC 项目。在我的编辑 POST Controller 中,我收到一个包含所有表单属性的 DTO 对象(其中之一是时间戳 - 我的编辑表单上的隐藏字段)。我从数据上下文中加载已编辑的人员,并将已编辑的属性从 DTO 对象映射到从数据上下文返回的域对象中。

最佳答案

正确执行乐观并发的唯一方法是进行版本检查,并 100% 确定在实际更新完成之前不会发生任何变化。最方便的方法是将版本检查合并到 UPDATE 语句中,这就是 EF 所做的。所以它确实发送了一条更新语句,看起来像

UPDATE table SET columnA = value
WHERE rowversion = xxxx

但是,当该语句在内存中找不到具有 rowversion 的行时,它会返回与预期不同数量的受影响行,并引发异常。 并且事务被回滚。所以,是的,您在 SQL Profiler 中看到一条语句,但它从未提交。

触发器作为更新语句的一部分运行,即在 EF 报告更新命令之前。显然,@username 在此过程中没有获取值,因此这会引发 SQL 异常,从而在注意到任何并发冲突之前破坏更新方。

关于asp.net-mvc-4 - EF 并发导致触发器出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15930353/

相关文章:

mysql - 与 EF6、MySQL、MVC 错误的一对零/一关系

mysql - 对 Int 字段使用 Contains 时动态 Linq 失败

entity-framework-4 - 不使用 Entity Framework 的 WCF 数据服务

asp.net-mvc-3 - DropDownList 结果未返回

entity-framework - 我应该使用 Entity Framework 4.1 和 MVC3 启用或禁用动态代理吗?

c# - 使用存储库模式获取相关表 Entity Framework

jquery - MVC4 侧边栏事件元素?

razor - ViewModel 中的 StringLength 未在文本框上设置 maxlength

asp.net - Aspnet MVC 中的相对路径和绝对路径有什么区别?

asp.net-mvc-4 - .NET MVC 4 强类型 ViewModel 包含强类型模型,且 EditorFor 和 EditorTemplate 部分 View 未绑定(bind)