Вопрос:

ASP.NET Web API - Потокобезопасная логика для обновления объекта

c# asp.net multithreading entity-framework asp.net-web-api

914 просмотра

4 ответа

33 Репутация автора

У меня есть следующий метод для добавления или обновления сущности типа Itemдля некоторых пользователей. Этот метод является частью класса Service, новый экземпляр которого создается для каждого запроса.

public async Task SaveItem(int userId, string name)
{
    var item = await _context.Items.Where(i => i.UserId == userId).SingleOrDefaultAsync();

    if (item == null)
    {
        item = new Item
        {
            UserId = userId,
            Name = name
        };
        _context.Items.Add(item);
    }
    else
    {
        item.Name = name;
        _context.Entry(item).State = System.Data.Entity.EntityState.Modified;
    }

    await _context.SaveChangesAsync();
}

Проблема состоит в том, что два одновременных запроса могут создать два элемента для одного и того же пользователя, что недопустимо. Для меня это выглядит довольно распространенным фрагментом кода, и мне интересно, что является стандартным способом решения такой проблемы параллелизма.

Автор: Nikita Kisel Источник Размещён: 22.08.2016 09:21

Ответы (4)


1 плюс

19 Репутация автора

Если комбинация UserId и Name для элемента должна быть уникальной, сделайте ее уникальной в базе данных.

Вы можете попытаться решить это с помощью статических объектов блокировки ... но это только сделает его медленным и трудным для понимания / поддержки.

Автор: Fabian Размещён: 22.08.2016 09:39

0 плюса

218 Репутация автора

У вас может быть две отдельные функции: одна создает и обновляет. Или вы можете попытаться обновить, и если это не удастся, создайте его, и не забудьте добавить уникальный индекс в вашу базу данных.

Автор: rlee Размещён: 22.08.2016 10:03

4 плюса

36010 Репутация автора

Решение

Вы должны Concurrency Conflictsправильно обращаться с вашим заявлением.

1. Пессимистичный параллелизм (блокировка)

Если вашему приложению необходимо предотвратить случайную потерю данных в сценариях параллелизма, один из способов сделать это - использовать блокировки базы данных. Это называется пессимистическим параллелизмом. Например, перед чтением строки из базы данных вы запрашиваете блокировку только для чтения или для доступа к обновлению. Если вы заблокируете строку для доступа к обновлению, никакие другие пользователи не смогут заблокировать строку для доступа только для чтения или для доступа к обновлению, поскольку они получат копию данных, которая находится в процессе изменения. Если вы заблокируете строку для доступа только для чтения, другие могут также заблокировать ее для доступа только для чтения, но не для обновления.

2. Оптимистический параллелизм

Альтернативой пессимистическому параллелизму является оптимистичный параллелизм. Оптимистический параллелизм означает, что конфликты параллелизма могут возникать, а затем реагировать соответствующим образом, если они происходят.

Пожалуйста, прочитайте статью Обработка параллелизма со статьей Entity Framework для получения дополнительной информации.

Автор: Sampath Размещён: 22.08.2016 11:52

0 плюса

14984 Репутация автора

Если UserIdполе помечено как уникальное (или идентичность, которая также является уникальной), вы уже в порядке. Всякий раз, когда вы попадаете в этот небольшой промежуток времени, чтобы добавить более одного элемента с одним и тем же одновременно UserId, только первый будет успешным, а все остальные не будут добавлены.

Автор: Sir Rufo Размещён: 23.08.2016 07:33
Вопросы из категории :
32x32