如何限制多对一关系中允许的子实体的数量?

时间:2019-03-02 17:40:28

标签: c# concurrency entity-framework-core

网络游戏...玩家需要建立团队,稍后再与之作战。我想在玩家的帐户下将建立的团队保留在数据库中。

但是,我想限制一个球员可以存储多少支球队。如何实现呢?

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的{​​{1}};它等于JohnDoe,因此线程1进入最外面的9的主体。线程2计数同一用户的if;由于T1尚未添加新团队,因此T2仍然看到previousTeamsNo等于previousTeamsNo并进入最外面的9的正文。两个线程完成后,if保存了JohnDoe个团队,这是我要禁止的。

那该如何解决?

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

好吧,尽管我不确定,但我有一个主意。我了解事物的方式-如果我错了,请纠正我-我需要启动提供最高隔离级别-Serializable的事务,以确保既不会使用11也不插入或删除行指向playerId的ID,而另一个线程处于其事务中间。实体框架核心seems to allow this。但是,我不确定我是否理解上一句话中链接到的文档内容:

  

可序列化。在数据集上放置了范围锁,以防止其他用户在事务完成之前更新或向数据集中插入行。

这意味着在执行JohnDoe查询时锁定了什么?仅这些行(当前行和将来行)的CountAsync外键指向playerId的ID?还是整个JohnDoe表都被锁定,有效地禁用了并发性?这是很难接受的,不是吗?

最后,在SavedTeams方法中使用Serializable隔离级别是否有效?还是在async事务中使用CountAsyncSaveChangesAsync是否有效?我的意思是,可序列化本质上是充当锁-和isn't mixing async and locks a recipe for deadlocks

我如何正确实现所需的条件?

0 个答案:

没有答案