c# - 在 Entity Framework 核心中执行业务规则

标签 c# .net .net-core transactions entity-framework-core

假设我有一个执行以下操作的 Controller 操作:

  1. 检查在特定时间是否有日历槽
  2. 检查是否没有与该时间段重叠的已预订约会
  3. 如果两个条件都满足,它会在给定时间创建一个新约会

简单的实现带来了多个问题:

  • 如果在步骤 3 之前删除了在 1 中获取的日历槽怎么办?
  • 如果在第 2 步之后但在第 3 步之前预约了另一个约会怎么办?

这些问题的解决方案似乎是使用 SERIALIZABLE 事务隔离级别。问题是每个人似乎都认为这种事务隔离级别非常危险,因为它可能会导致死锁。

给出以下简单的解决方案:

public class AController
{
    // ...
    public async Task Fn(..., CancellationToken cancellationToken)
    {
        var calendarSlotExists = dbContext.Slots.Where(...).AnyAsync(cancellationToken);
        var appointmentsAreOverlapping = dbContext.Appointments.Where(...).AnyAsync(cancellationToken);
        if (calendarSlotExists && !appointmentsAreOverlapping)
            dbContext.Appointments.Add(...);
        dbContext.SaveChangesAsync(cancellationToken);
    }
}

始终防止并发问题的最佳方法是什么?我应该如何处理最终的死锁?

最佳答案

数据库完整性检查是你最好的 friend

根据您的描述,您的约会是基于时段的。这使问题变得简单得多,因为您可以有效地为 Appointments 表上的 SlotId 定义唯一约束。然后你需要一个用于 Appointments.SlotId 引用的外键 Slot.Id

what if the calendar slot fetched in 1 is removed before step 3?

数据库会抛出外键违规异常

what if another appointment is booked after step 2 but before step 3?

数据库会抛出重复键异常

接下来您需要做的是捕获这两个异常并将用户重定向回预订页面。再次从数据库重新加载数据并检查是否有无效条目,通知用户进行修改并重试。

对于死锁部分,它实际上取决于您的表结构。你访问数据的方式,你索引它们的方式,以及 DB 的查询计划。对此没有明确的答案。

关于c# - 在 Entity Framework 核心中执行业务规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55343663/

相关文章:

c# - Entity Framework 代码优先 CTP5 映射

c# - "(float)integer == integer"在 C# 中是否保证相等?

c# - 有没有一种很好的方法可以将一个 int 分成两个短裤(.NET)?

.net - 模拟框架(在 .Net 中)如何创建模拟对象?

C# 创建一个比较两个成员属性的 LambdaExpression(对于 EF Core HasQueryFilter)

c# - 没有 ASP.NET MVC 的捆绑和缩小

c# - 指定的类型必须是不包含引用的结构

azure - ping 类在已发布的网络核心 Web 应用程序中不起作用

c# - 如何在.NET Core中获取IServiceProvider的实例?

c# - 连接表 MySQL