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

问题描述

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

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

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

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

这个问题有时会导致cartItemPrice改变,有时不会改变,而CartTotalPrice总是改变。

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

 <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();
    }
}

这里有什么问题,如果可以解决?

谢谢。

标签: c#asp.net-mvcasync-awaitcontrollerentity-framework-core

解决方案


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

您可以通过两种方式解决此问题:

交易

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]

并再次捕获DbUpdateConcurrencyException并重新开始更新价格。处理并发冲突


推荐阅读