如何使用 Entity Framework 在一笔交易中更新选定的记录?

How to update selected records in one transaction with Entity Framework?

我正在使用 SQL 服务器。我的情况如下所示:

  1. 我有一个tableMessages。 table 有一列 MessageStatusId
  2. 我有几个可以访问这个数据库的服务
  3. 每个服务 select 定期发送状态为 New 的消息并以某种方式处理这些消息
  4. 服务 select 消息如下:
    await DbContext.Set<Message>()
                   .Where(m => m.MessageStatusId == MessageStatusEnum.New)
                  .ToListAsync();
    
  5. 处理后,服务更新消息状态

我不希望服务 select 同一组记录。所以我需要将消息状态更新为 InProcess。如何通过 Entity Framework?

在一笔交易中实现这一点

您可以实施悲观锁定以确保一次只有一个工作人员访问 table,但是保持 table 访问尽可能短以避免之间的死锁非常重要客户。我建议每个请求获取有限数量的行:

var options = new TransactionOptions
{
   IsolationLevel = System.Transactions.IsolationLevel.Serializable,
   Timeout = new TimeSpan(0, 0, 0, 10)
};

var messageIds = new List<int>();

using(var scope = new TransactionScope(TransactionScopeOption.RequiresNew, options))
{
    using (var context = new MessageDbContext())
    {
        var messages = context.Messages
            .Where(x => x.MessageStatusId == MessageStatusEnum.New)
            .OrderBy(x => x.MessageDate)
            .Take(100)
            .ToList();

       foreach(var message in messages)
           message.MessageStatusId = MessageStatusEnum.InProgress;

       context.SaveChanges();
       messageIds = messages.Select(x => x.MessageId).ToList();
    }
    scope.Commit();
}

我的建议是:

  • 将此 Message 实体分离到一个有界 DbContext 中,该 DbContext 仅服务于消息 checking/status 更新,没有其他。此消息实体可以只是此操作的 MessageId 和 MessageStatusId,以及其他检查消息状态/w 悲观锁定的实体。
  • 使用同步调用,比异步调用更快。
  • 获取行,将它们标记为正在进行并获取它们的 ID,然后提交状态更改。之后你可以用乐观锁阅读它们,在你有空的时候处理,避免死锁。
  • 限制查询的行数以避免在碰巧有大量积压时出现意外。 (10, 100, 取其合理)