Страницы

Поиск по вопросам

среда, 22 января 2020 г.

MSSQL инкремент значения

#c_sharp #sql_server #entity_framework


Как инкрементировать значение поля в БД MSSQL с использованием Linq. Вариант с прочитать-прибавить-записать
не подходит ввиду одновременного инкремента разными клиентами и потоками.

По ответам из комментов, попробовал сделать вот так:

public static async Task IncrementDownloadCounterAsync(Int32 id)
{
    using (LICENSE_RO3Entities db = new LICENSE_RO3Entities())
    {
        using (DbContextTransaction transaction = db.Database.BeginTransaction())
        {
            DB.Update update = await db.Updates.FindAsync(id);
            if (update != null)
            {
                update.download_counter++;
            }

            await db.SaveChangesAsync();
            transaction.Commit();
        }
    }
}

    


Ответы

Ответ 1



Для обновления одной записи никакая транзакция не нужна: EF умеет использовать оптимистическую блокировку для той же цели. Если вы используете Code First - можно отметить свойство атрибутом [ConcurrencyCheck]. В таком случае EF при каждом обновлении записи будет дополнительно проверять что значение соответствующего атрибута в базе не изменилось. Также можно добавить в модель свойство отмеченное атрибутом [Timestamp] типа byte[] если база данных поддерживает тип данных rowversion или его аналог. Отличие Timestamp от ConcurrencyCheck - в том, что ConcurrencyCheck только проверяется, а Timestamp еще и автоматически обновляется при любом изменении записи. [Timestamp] public byte[] RowVersion { get; set; } В любом случае, какой бы из двух способов вы не выбрали - вы получите DbUpdateConcurrencyException если кто-то поменяет значение в базе пока вы собирались его сохранять. После этого можно будет попытаться увеличить счетчик еще раз. Но самый нормальный способ - конечно же делать это средствами базы. EF не предоставляет способа делать это через Linq - поэтому надо использовать SQL-запрос: db.Database.ExecuteSqlCommand("UPDATE Updates SET download_counter = download_counter + 1 WHERE Id = @p0", id); Если есть желание изолировать вышележащие слои от SQL-кода - можно добавить этот запрос как метод контексту: public void IncrementDownloadCounter(int id) { if (Database.ExecuteSqlCommand("UPDATE Updates SET download_counter = download_counter + 1 WHERE Id = @p0", id) == 0) { throw что-нибудь; } }

Комментариев нет:

Отправить комментарий