如何在没有往返的情况下删除项目

How to remove items without round trip

代码

  var items = await ctx.Cartitems.Where((c) => c.Cartid == GetCartId() && c.Toodeid == product).ToListAsync();
  ctx.Cartitems.RemoveRange(items);
  await ctx.SaveChangesAsync();

从 EF Core 的购物车中删除产品。 它用于向数据库发出命令:SELECT 和 DELETE。

如何从数据库中删除项目以便只向服务器发送单个命令?

ASP.NET 5 MVC Core 应用程序使用 EF Core 和 Npgsql

如果您有 CartItemId 或构成复合 PK 的 ID,则可以通过附加存根购物车 ID 并将其标记为删除来简化删除操作。根据 DbContext 的生命周期范围和此调用所在的位置,您可能需要在附加之前根据本地 DbContext 缓存检查每一个。

因此,假设您的 UI 可以将 CartItemId 的集合传递给刷新:

// This looks for any locally loaded cart items. We will remove these rather than
// attaching stubs which would raise an exception. This doesn't hit the DB.
var localCachedCartItems = _context.CartItems.Local
    .Where(x => cartItemIds.Contains(x.CartItemId))
    .ToList();
// Get the IDs to exclude from the Id list to create stubs.
var localCachedCartItemIds = localCachedCartItems
    .Select(x => x.CartItemId)
    .ToList();
// Build stubs for the remaining cart items.
var cartItemsToRemove = cartItemIds.Except(localCachedCartItemIds)
    .Select(id => new CartItem { CartItemId = id })
    .ToList();

foreach(var stub in cartItemsToRemve)
{
    _context.Attach(stub);
    _context.Entity(stub).State = EntityState.Deleted;
}

_context.SaveChanges();

如果您使用的是局部范围的 DbContext(即 /w using 块),那么您可以跳过 Local 检查并只创建存根:

using(var context = new AppDbContext())
{
    var cartItemsToRemove = cartItemIds
        .Select(id => new CartItem { CartItemId = id })
        .ToList();

    foreach(var stub in cartItemsToRemve)
    {
        _context.Attach(stub);
        _context.Entity(stub).State = EntityState.Deleted;
    }

    context.SaveChanges();
}

Entity Framework 主要用作更改跟踪器,记录对跟踪实体的更改,然后在调用 SaveChanges 时执行和提交这些更改。但是为了跟踪删除等更改,它需要首先实际跟踪这些实体。为此,它需要从数据库中查询这些实体以了解实际存在哪些实体。

如果您只想通过实体的主要标识符删除实体,那么您可以通过将假实体附加到更改跟踪器然后删除它们来使用一些低级的东西,这导致 EF 从数据库中删除对象。像这样的事情需要更多的内部知识,而且并不容易理解。所以我建议您避免使用这些方法。

可以做的是使用在Entity Framework 之上提供批量更新的扩展。这些通常会绕过更改跟踪器(意味着更改会立即执行)并且不需要您先将实体加载到上下文中。有几个图书馆可以做到这一点: