Как ограничить количество разрешенных дочерних объектов в отношениях «многие к одному»? - PullRequest
0 голосов
/ 02 марта 2019

Веб-игра ... Игроки должны создавать команды, с которыми они позже вступят в битвы.Я хочу сохранить созданные команды в базе данных под учетной записью игрока.

Однако я хочу установить ограничение на количество команд, которое игрок может хранить.Как это реализовать?

public const MaxTeams = 10;

[Authorize] public async Task AddTeam(string teamSerialized)
{
    var previousTeamsNo = await dbContext.SavedTeams.CountAsync(
        t => t.playerId == Context.UserIndentifier
    );
    if (previousTeamsNo < MaxTeams) {
        var team = new SavedTeam(teamSerialized);
        if (team.isValid) {
            dbContext.Add(team);
            await dbContext.SaveChangesAsync();
        }
    }
}

Хотя приведенный выше код может быть простым, я боюсь, что он также недействителен.Поток 1 имеет значение previousTeamsNo пользователя JohnDoe;он равен 9, поэтому нить 1 переходит к телу самого внешнего if.Поток 2 считает previousTeamsNo того же пользователя;поскольку T1 еще не добавил новую команду, T2 по-прежнему видит previousTeamsNo, равный 9, и переходит к телу самого внешнего if.После завершения обоих потоков JohnDoe имеет 11 сохраненных команд, что я и хотел запретить.

Как это исправить?

================

Хорошо, у меня есть одна идея, хотя я не уверен в этом.Как я понимаю вещи - пожалуйста, исправьте меня, если я ошибаюсь - мне нужно запустить транзакцию, обеспечивающую самый высокий уровень изоляции - Сериализуемый - чтобы гарантировать, что ни один поток не будет вставлять или удалять строки с playerIdуказывая на идентификатор JohnDoe, в то время как другой поток находится в середине своей транзакции.Entity Framework Core , кажется, позволяет это .Однако я не уверен, что понимаю часть документации, на которую я ссылался в предыдущем предложении:

Сериализуемый.В DataSet установлена ​​блокировка диапазона, которая не позволяет другим пользователям обновлять или вставлять строки в набор данных до завершения транзакции.

Это означает, что блокируется при выполнении запроса CountAsync?Только эти строки (текущее и потенциальное будущее), чей внешний ключ playerId указывает на идентификатор JohnDoe?Или таблица ВСЕ SavedTeams заблокирована, эффективно отключая параллелизм?Это вряд ли приемлемо, не так ли?

Наконец, допустимо ли использование уровня изоляции Serializable в методе async?Или допустимо использовать CountAsync и SaveChangesAsync в транзакции Serializable?Я имею в виду, Serializable по сути действует как блокировка - и не смешивает async и блокирует рецепт для взаимоблокировок ?

Как правильно реализовать то, что мне нужно?

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