ASP.NET MVC api,Entity Framework和许多客户端

时间:2016-10-12 19:24:44

标签: asp.net-mvc entity-framework

我有一个大问题。

我有一个WebApi服务器和方法SetUserStatus

有两个实体:UserUserStatus。他们有一对多的关系。它们中的每一个都具有用于乐观并发的RowVersion属性。

当两个客户端尝试修改User的同一个实例,抛出User时,乐观并发适用于DbUpdateConcurrencyException。当两个或多个客户端按Id选择一个用户时,问题就开始了,并且添加了新的UserStatus

UserStatus具有EndDate属性。添加新的UserStatus时必须填写。在我的存储库中,我做了类似的事情:

public async Task<bool> SetUserStatus(int userId, bool status)
{
    using(var db = new ApplicationDbContext())
    {
        var user = await db.User.FirstOrDefaultAsync(u => u.Id == id);

        if (user != null)
        {
            var lastStatus = user.Statuses.FirstOrDefault(s => !s.EndDate.HasValue);

            if (lastStatus != null)
            {
                lastStatus.EndDate = DateTime.Now;
            }

            user.Statuses.Add(new UserStatus { Status = status });

            return await db.SaveChangesAsync() > 0;
        }
    }
}

所以......我有几个空EndDate的记录。我理解它是因为这个方法的每次调用都有自己的数据库上下文。但我不知道如何解决这个错误。我只需UserStatusEndDate。我不希望在每次调用此方法时使用锁。

我的错误在哪里?

THX!

1 个答案:

答案 0 :(得分:0)

这样做的原因是你在.Net代码中这样做。并发是你的问题。

采取这种情况:

  1. 有一个状态,没有EndDate
  2. 第一次通话获得此状态
  3. 并发通话获得相同的状态
  4. 他们都更新了第一个状态,并创建了一个没有EndDate的新状态
  5. 他们都提交
  6. 您现在有一个EndDate状态,2个没有。
  7. 下一个电话只会更新最后一个电话,让您的状态没有EndDate。
  8. 如果你想拥有100%一致的东西,那么有很多选项,但最简单的选择可能就是使用数据库触发器或存储过程。