.Net mvc EF代码首先如何处理对数据库的并发更新请求

.Net mvc EF codefirst how to hanle concurrent update requests to database

我在数据库中有一个 table:

USERID   MONEY
______________
  1       500

货币价值只能由拥有帐户的登录用户更改。我有一个像这样的函数:

bool buy(int moneyToSpend)
{
    var moneyRow = db.UserMoney.Find(loggedinUserID);
    if(moneyRow.MONEY < moneyToSpend)
        return false;
    //code for placing order
    moneyRow.MONEY -= moneyToSpend;
    return true;
}

我知道 mvc 会话总是同步的,所以在一个用户会话中永远不会有 2 个对此函数的同步调用。但是,如果用户从不同的浏览器登录站点 2 次怎么办?它仍然是单线程会话还是我可以获得 2 个对此函数的并发请求? 如果会有并发,那么我应该如何使用 EF 处理它?通常在 ADO 中,我会使用 MSSQL 的 "BEGIN WORK" 来处理这种情况,但我不知道如何使用 EF 来实现。

感谢您的宝贵时间!

我不认为这对你来说是个大问题,因为据我所知,MSSQL 不允许 asyncroneus 数据从同一个线程提交给同一个用户,它必须在移动之前完成一个进程到下一个,但你可以尝试这样的事情

using (var db = new YourContext()) 
{ 
    var moneyRow = db.UserMoney.Find(loggedinUserID);
    moneyRow.MONEY -= moneyToSpend; 

    bool saveFailed; 
    do 
    { 
        saveFailed = false; 
        try 
        { 
            db.SaveChanges(); 
        } 
        catch (DbUpdateConcurrencyException ex) 
        { 
            saveFailed = true; 

            // Update original values from the database 
            var entry = ex.Entries.Single(); 
            entry.OriginalValues.SetValues(entry.GetDatabaseValues()); 
        } 

    } while (saveFailed); 
}

可以在这里找到更多内容 Optimistic Concurrency Patterns

我建议您使用 RowVersion 来处理并发请求。

这里有很好的参考:http://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

// in UserMoney.cs
[Timestamp]
public byte[] RowVersion { get; set; }

// in model builder
modelBuilder.Entity<UserMoney>().Property(p => p.RowVersion).IsConcurrencyToken();

// The update logic
public bool Buy(int moneyToSpend, byte[] rowVersion)
{
    try
    {
        var moneyRow = db.UserMoney.Find(loggedinUserID);
        if(moneyRow.MONEY < moneyToSpend)
        {            
            return false;
        }

        //code for placing order
        moneyRow.MONEY -= moneyToSpend;
        return true;
    }
    catch (DbUpdateConcurrencyException ex)
    {
        var entry = ex.Entries.Single();
        var submittedUserMoney = (UserMoney) entry.Entity;
        var databaseValue = entry.GetDatabaseValues();

        if (databaseValue == null)
        {
            // this entry is no longer existed in db
        }
        else
        {
            // this entry is existed and have newer version in db
            var userMoneyInDb = (UserMoney) databaseValue.ToObject();
        }
    }
    catch (RetryLimitExceededException)
    {
        // probably put some logs here
    }
}