C# 具有实体框架和并发性的Azure函数

C# 具有实体框架和并发性的Azure函数,c#,entity-framework,azure,azure-functions,azure-iot-hub,C#,Entity Framework,Azure,Azure Functions,Azure Iot Hub,我有一个IotHub触发器,它基本上使用实体框架将传入的id保存到数据库中,如果这样的id不存在的话 [FunctionName("MainFunc")] public static async Task Run( [IoTHubTrigger("messages/events", Connection = "IotHubCompatibleEndpointConnectionString", ConsumerG

我有一个IotHub触发器,它基本上使用实体框架将传入的id保存到数据库中,如果这样的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();
}
问题是,当有大量消息发送到iot集线器时,多个触发器调用开始并行工作(至少在我调试触发器时),这导致
InsertIfNotExists()
方法出现问题,当数据库中不存在多个具有相同id的记录时,会导致重复密钥异常,正在处理中


最合适的修复方法是什么?只需吞下异常,因为该记录仍将出现在数据库中?

您没有提供太多代码在InsertIfNotExists中执行的操作,但我认为您的问题是您有上下文。SaveChanges();最后,这意味着首先在内存中修改,然后保存,这意味着同时可以有多个实例执行相同的操作。这里最重要的是快速插入数据库,但即使这样也不能保证一次插入一个

所以我看这里没有什么选择

备选案文1。您还可以使用try-catch,在出现错误时,只需执行第二次trip以获取id,因为您知道已插入该记录

备选案文2。Transact-sql具有实际执行upsert的merge语句。如果您使用的是实体框架核心(您没有提供是否为其核心,但我假设为其核心),那么您可以使用

备选案文3。将是使用事务

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();