对控制器函数的多次调用会导致问题(ASP.NET MVC Web 应用程序中的 EF Core)

Posted

技术标签:

【中文标题】对控制器函数的多次调用会导致问题(ASP.NET MVC Web 应用程序中的 EF Core)【英文标题】:Multiple calls to a controller's function causes problems (EF Core in an ASP.NET MVC web app) 【发布时间】:2021-11-03 02:03:26 【问题描述】:

我在 ASP.NET MVC Web 应用程序中使用 EF Core。

这是一家在线餐厅。我想让用户更改购物车项目的数量(仅在这一点添加更多)并通过它来更新他的cartItemPrice 和他的cartTotalPrice(购物车可以包含很少的购物车项目,每个购物车项目都可以包含少量菜肴)。

在测试代码后,它工作正常,只有当我当时调用AddOne 方法一时,cartItemPriceCartTotalPrice 都应该更新。

当我多次调用该方法时问题开始(通过快速单击..双击导致问题的实例)。

该问题导致cartItemPrice 有时会更改,有时不会更改,而CartTotalPrice 总是更改。

我使用这个标签从 View/Carts 调用 AddOne 方法:

 <div class="quantity">
 <a asp-action="AddOne" asp-controller="Carts" asp-route-id="@ci.Id" class="add quantity-btn col-3">+</a>
 </div>

我尝试使用 async 和 await 也没有使用它们,两种方式都给出了同样糟糕的结果。

Controllers/CartsController 中的函数:

异步/等待:

public async Task AddToTotalPrice(double price)

    var user = GetCurrentUserName();
    var cart = await _context.Cart.FirstOrDefaultAsync(s => s.UserName == user);
    cart.CartTotalPrice += price;
    await _context.SaveChangesAsync();


public async Task AddOne(int id)

    var cartitem = await _context.CartItem.Include(d => d.Dish).FirstOrDefaultAsync(s => s.Id == id);
    var u = GetCurrentUserName();
    var c = _context.Cart.FirstOrDefault(p => p.UserName == u);

    if (cartitem != null)
    
        if (cartitem.CartId != c.Id)
        
            return;
        

        cartitem.Quantity += 1;
        cartitem.cartItemPrice = cartitem.Dish.Price * cartitem.Quantity;
        await AddToTotalPrice(cartitem.Dish.Price);
        await _context.SaveChangesAsync();
    

没有异步/等待:

public void AddToTotalPrice(double price)

    var user = GetCurrentUserName();
    var cart = _context.Cart.FirstOrDefault(s => s.UserName == user);
    cart.cartTotalPrice += price;
    _context.SaveChanges();


public void AddOne(int id)

    var cartitem = _context.CartItem.Include(d => d.Dish).FirstOrDefault(s => s.Id == id);
    var u = GetCurrentUserName();
    var c = _context.Cart.FirstOrDefault(p => p.UserName == u);

    if (cartitem != null)
    
        if (cartitem.CartId != c.Id)
        
            return;
        

        cartitem.Quantity += 1;
        cartitem.cartItemPrice = cartitem.Dish.Price * cartitem.Quantity;
        AddToTotalPrice(cartitem.Dish.Price);
        _context.SaveChanges();
    

这里出了什么问题,是否可以修复?

谢谢。

【问题讨论】:

1) 将并发列添加到您的架构中。 2)调用保存更改一次,或在事务中。 3) 捕获并重试请求。和/或通过查询按需计算总价。 似乎 [ConcurrencyCheck] 修复了它。谢谢@JeremyLakeman 【参考方案1】:

当服务器处理一个请求时,另一个请求正在做同样的事情,并且你有数据竞争。

你可以通过两种方式解决这个问题:

交易

public async Task AddToTotalPrice(double price)

    var user = GetCurrentUserName();
    var cart = await _context.Cart.FirstOrDefaultAsync(s => s.UserName == user);
    cart.CartTotalPrice += price;


public async Task AddOne(int id)

    using var tran = _context.Database.BeginTransactionAsync();
    
    var cartitem = await _context.CartItem.Include(d => d.Dish).FirstOrDefaultAsync(s => s.Id == id);
    var u = GetCurrentUserName();
    var c = _context.Cart.FirstOrDefault(p => p.UserName == u);

    if (cartitem != null)
    
        if (cartitem.CartId != c.Id)
        
            return;
        

        cartitem.Quantity += 1;
        cartitem.cartItemPrice = cartitem.Dish.Price * cartitem.Quantity;
        await AddToTotalPrice(cartitem.Dish.Price);
        await _context.SaveChangesAsync();
    

    await tran.CommitAsync();

并发令牌

添加到Cart.CartTotalPrice 属性[ConcurrencyCheck],如documentation 中指定的那样。

然后抓住DbUpdateConcurrencyException 并重新开始更新价格。 Handling Concurrency Conflicts

【讨论】:

似乎 [ConcurrencyCheck] 修复了它。谢谢

以上是关于对控制器函数的多次调用会导致问题(ASP.NET MVC Web 应用程序中的 EF Core)的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 在 Ajax 调用控制器后显示视图

asp.net mvc 4控制器并行执行多个ajax调用

带有 ADO .NET 的 ASP .NET MVC 会导致问题吗?

Asp.Net jQuery $.getJSON 有时会导致整页回发?

ajax 请求是不是会导致更新 asp.net 会话?

IoC 是不是会导致 ASP.NET MVC Controller 构造函数的参数过多?