Функция Azure с Entity Framework и параллелизмом - PullRequest
0 голосов
/ 29 апреля 2019

У меня есть триггер IotHub, который в основном сохраняет входящий идентификатор в базу данных, используя Entity Framework, если такой идентификатор не существует.

[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(), приводящую к исключению дублирующегося ключа. когда обрабатывается более 1 записи с одинаковым идентификатором, отсутствующей в базе данных.

Какой самый подходящий способ исправить это? Просто проглотите исключение, потому что запись все равно появится в базе данных?

1 Ответ

1 голос
/ 30 апреля 2019

Вы не предоставили много кода, что вы делаете в InsertIfNotExists, но, как я вижу, ваша проблема в том, что у вас есть context.SaveChanges ();в конце концов, это означает, что сначала вы изменяете в памяти, затем сохраняете, что означает, что одновременно вы можете иметь несколько экземпляров, делающих одно и то же.Здесь наиболее важно быстро вставить в базу данных, но даже это не гарантирует одну вставку за раз.

Так что я вижу несколько вариантов здесь

Вариант 1. Вы также можете попробовать перехватить, и в случае ошибки просто совершите вторую поездку, чтобы получить по id, так как вы знаете, что запись вставлена.

Вариант 2. В Transact SQL есть оператор слияния, который на самом деле выполняет команду upsert.Если вы используете ядро ​​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. Будет использовать транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...