Pet*_*inl 5 .net entity-framework-4
在审批工作流程中,我希望确保提醒电子邮件只发送一次.
使用SqlCommand.ExecuteNonQuery,我可以通过测试返回值来确保这一点.使用EF的推荐解决方案是什么?根据文档ObjectContext.SaveChanges不返回等效值.
SqlCommand示例:(在SendMail失败的情况下,TransactionScope用于回滚数据库更新.)
Dim sql = "UPDATE LeaveApprovalRequests SET State = 'Reminded'" &
" WHERE ID=3 AND State <>'Reminded'"
Using scope As New TransactionScope
Using cnx As New SqlConnection(My.Settings.connectionString)
cnx.Open()
Dim cmd As New SqlCommand(sql, cnx)
If 1 = cmd.ExecuteNonQuery Then
SendMail()
End If
scope.Complete()
End Using
End Using
通过启用乐观并发(在RowVersion属性上使用ConcurrencyMode = Fixed)并捕获OptimisticConcurrencyException,我能够识别对象是否实际在商店中更新.现在,TransactionScope(用于在SendMail失败时回滚数据库更新)会引发死锁错误.为什么?
Using scope As New TransactionScope
Using ctx As New ApprovalEntities
Try
Dim approval = ctx.LeaveApprovalRequests.
Where(Function(r) r.ID = 3 And r.State = "Created"
).FirstOrDefault
If approval Is Nothing Then
Console.WriteLine("not found")
Exit Sub
End If
Threading.Thread.Sleep(4000)
approval.State = "Reminded"
ctx.SaveChanges()
SendMail()
Catch ex As OptimisticConcurrencyException
Exit Try
End Try
End Using
scope.Complete()
End Using
根据与 Morteza 讨论的结果,我回答如下。
SaveChanges 返回它打算更新的对象数量,而不是它在存储中更新的对象数量。因此它必须与 OptimisticConcurrencyException 一起使用来确定更改是否成功。必须考虑到除了要更改的属性之外的其他属性也可能导致 OptimisticConcurrencyException。
读取实体并在同一 TransactionScope 中更新它会导致死锁。
对于我的任务“仅当我能够将状态从创建更改为提醒时才发送电子邮件”,我使用以下解决方案:
通过 1:1 关联将 ApprovalRequest 实体一分为二,在 OptimisticConcurrencyException 上退出,使用 SaveChanges 在 TransactionScope 中发送邮件。
ApprovalRequests
ID (PK)
RequestedBy
...
RowVersion (ConcurrencyMode=Fixed)
ApprovalRequestStates
ApprovalRequest_ID (PK, FK)
State (ConcurrencyMode=Fixed)
Using ctx As New ApprovalEntities
Dim approval = cxt.ApprovalRequests.Where ...
Dim state = ctx.ApprovalRequestStates.
Where(Function(r) r.ApprovalRequest_ID = approval.ID And r.State = "Created"
).FirstOrDefault()
If state Is Nothing Then Exit Sub
state.State = "Reminded"
Threading.Thread.Sleep(3000)
Using scope As New TransactionScope
Try
ctx.SaveChanges()
SendMail()
scope.Complete()
Catch ex As OptimisticConcurrencyException
Exit Try
End Try
End Using
End Using
谨防!通过父实体引用子实体时更新子实体也会导致父实体的数据库更新 - 在这种情况下会抛出不需要的 OptimisticConcurrencyException。因此我没有使用:ApprovalRequests.ApprovalRequestStates.State =“提醒”
| 归档时间: |
|
| 查看次数: |
1693 次 |
| 最近记录: |