在 EF Core 5 中插入之前锁定 table

Lock table before inserting in EF Core 5

我有以下场景:

目前,在创建新订单时,该需求实现如下:

var newOrder = /* logic for creating the new order */;

var orders = _ordersRepository.GetAllBy(userId, date); // get the orders from the db
var totalAmount = orders.Sum(o => o.Amount); 
if(totalAmount < MaximumAmount) {
  newOrder.IsApproved = true;
}
else {
  newOrder.IsApproved = false;
}

_ordersRepository.Add(newOrder);
_ordersRepository.SaveChanges(); // insert into the db

这种方法的问题在于它无法在以下场景中正确处理并发插入:

请求是并发处理的,由于时间短,当前实施的检查是在新订单保存到数据库之前执行的,因此允许创建所有这些请求。最终用户超过最大限制结束。

我怎样才能解决这个问题,最好是不必多次调用 SaveChanges?我正在使用 Entity Framework Core 5 和 SQL 服务器。

感谢评论中的建议!

我试过使用 IsolationLevel 设置为 Serializable 的事务,但后来我意识到这会锁定太多 table(问题中的示例是一个虚拟的,实际实现更复杂)。

我同意有时在数据库中使用这种逻辑可能更容易,但是为此添加存储过程会破坏当前的一致性,并且很可能为其他存储过程敞开大门。我并不是说存储过程不好,只是在我目前的情况下,即使没有它们实现这个有点 harder/more 复杂,但出于一致性原因,我相信这是值得的。

我以

结束的解决方案

我已将流程分为 2 个步骤,如下所示:

// step 1
var newOrder = /* logic for creating the new order */;
_ordersRepository.Add(newOrder);
_ordersRepository.SaveChanges(); // insert into the db

// step 2
var orders = _ordersRepository.GetAllBy(userId, date); // get the orders from the db
var totalAmount = orders.Sum(o => o.Amount); 
if(totalAmount < MaximumAmount) {
  newOrder.IsApproved = true;
}
_ordersRepository.Update(newOrder); 
_ordersRepository.SaveChanges(); // update the new order
  • 第 1 步只是创建新订单并将其插入数据库,IsApproved 标志保留为默认值,即 false
  • 第 2 步执行每日限额验证,如果检查通过,IsApproved 标记为 true

我知道这不是真正的解决方案,而是一种解决方法。锁定 table 可能会对性能产生太大影响,尤其是当给定的 table 被多个应用程序功能使用时。使用此解决方案,即使在第 2 步中出现问题,订单将保留 IsApproved=false,因此不会产生任何影响,用户可以稍后重试,或者支持人员可以处理.