多次调用控制器的函数会导致问题(ASP.NET MVC 网络应用程序中的 EF Core)
Multiple calls to a controller's function causes problems (EF Core in an ASP.NET MVC web app)
我在 ASP.NET MVC 网络应用程序中使用 EF Core。
这是一家在线餐厅。我想让用户更改购物车商品的数量(仅在这一点上添加更多),然后更新他的 cartItemPrice
以及他的 cartTotalPrice
(购物车可以包含很少的购物车商品和每个购物车项目都可以包含几道菜)。
测试代码后,它工作正常,只有当我当时调用 AddOne
方法一时,cartItemPrice
和 CartTotalPrice
都应该更新。
当我多次调用该方法时出现问题(通过快速单击..双击导致问题)。
这个问题导致 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 的函数:
async/await:
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();
}
}
没有async/await:
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();
}
}
这里有什么问题,是否可以修复?
谢谢。
当服务器处理一个请求时,另一个请求正在做同样的事情并且您有数据竞争。
您可以通过两种方式解决这个问题:
交易
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
我在 ASP.NET MVC 网络应用程序中使用 EF Core。
这是一家在线餐厅。我想让用户更改购物车商品的数量(仅在这一点上添加更多),然后更新他的 cartItemPrice
以及他的 cartTotalPrice
(购物车可以包含很少的购物车商品和每个购物车项目都可以包含几道菜)。
测试代码后,它工作正常,只有当我当时调用 AddOne
方法一时,cartItemPrice
和 CartTotalPrice
都应该更新。
当我多次调用该方法时出现问题(通过快速单击..双击导致问题)。
这个问题导致 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 的函数:
async/await:
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();
}
}
没有async/await:
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();
}
}
这里有什么问题,是否可以修复?
谢谢。
当服务器处理一个请求时,另一个请求正在做同样的事情并且您有数据竞争。
您可以通过两种方式解决这个问题:
交易
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