Веб-игра ... Игроки должны создавать команды, с которыми они позже вступят в битвы.Я хочу сохранить созданные команды в базе данных под учетной записью игрока.
Однако я хочу установить ограничение на количество команд, которое игрок может хранить.Как это реализовать?
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
и блокирует рецепт для взаимоблокировок ?
Как правильно реализовать то, что мне нужно?