具有 Entity Framework 和并发性的 Azure 函数

Azure function with Entity Framework and concurrency

我有一个 IotHub 触发器,如果​​不存在这样的 ID,它基本上使用 Entity Framework 将传入的 ID 保存到数据库中。

[FunctionName("MainFunc")]
public static async Task Run(
    [IoTHubTrigger("messages/events",
                   Connection = "IotHubCompatibleEndpointConnectionString",
                   ConsumerGroup = "ttx_iothub_trigger_sqldb_cg")]
    EventData eventData, ILogger log)
{
    string id = GetIdFromMessage(eventData);
    var context = new MyEfDbContext();
    InsertIfNotExists(id);
    DoSomethingElse(context);
    context.SaveChanges();
}

问题是,当有大量消息发送到物联网集线器时,多个触发器调用开始并行工作(至少在我调试触发器时),这导致 InsertIfNotExists() 方法领先的问题正在处理超过 1 个具有相同 ID 且不存在于数据库中的记录时出现重复键异常。

最合适的修复方法是什么?只是吞下异常,因为记录无论如何都会出现在数据库中?

您没有提供太多您在 InsertIfNotExists 中所做的代码,但我看到您的问题是您有 context.SaveChanges();最后这意味着首先你在内存中修改然后你保存,这意味着你可以同时让多个实例做同样的事情。这里最重要的是快速插入数据库,但即使这样也不能保证一次插入一个。

所以我在这里看到的选项很少

选项 1。您也可以使用 try catch,出错时只需进行第二次访问以通过 id 获取,因为您知道记录已插入。

选项 2. Transact sql 具有实际上执行更新插入的合并语句。如果你正在使用 entity framework 核心(你没有提供它是否是核心,但我假设它是核心)你可以使用 extension

DataContext.DailyVisits
    .Upsert(new DailyVisit
    {
        UserID = userID,
        Date = DateTime.UtcNow.Date,
        Visits = 1,
    })
    .On(v => new { v.UserID, v.Date })
    .WhenMatched(v => new DailyVisit
    {
        Visits = v.Visits + 1,
    })
    .RunAsync();

选项 3。将使用事务。