ExecuteStoreCommand“Delete”将删除后的不同记录计数返回给“DeleteObject”,为什么?

问题描述 投票:0回答:1

这里有一个奇怪的。我在SQL Server 2012和C#上使用EF 6。

如果我使用DeleteObject删除记录,我得到:

        //order.orderitem count = 11

        db.OrderItem.DeleteObject(orderitem);  
        db.SaveChanges();

        var order = db.order.First(r => r.Id == order.id);

        //Order.OrderItem count = 10, CORRECT

如果我删除订单项,使用ExecuteStoreCmd内联DML,我得到:

        //order.orderitem count = 11

        db.ExecuteStoreCommand("DELETE FROM ORDERITEM WHERE ID ={0}", orderitem.Id);

        var order = db.Order.First(r => r.Id == order.id);

        //order.orderitem count = 11, INCORRECT, should be 10

因此,ExecuteStoreCommand版本报告11,但是OrderItem肯定是从数据库中删除的,所以它应该报告10.此外我认为First()会进行Eager搜索,从而重新填充“order.orderitem”集合。

任何想法为什么会这样?谢谢。

编辑:我正在使用ObjectContext

编辑2:这是我使用“分离”的最接近的工作解决方案。有趣的是,“分离”实际上需要大约2秒!不确定它在做什么,但它确实有效。

db.ExecuteStoreCommand("DELETE FROM ORDERITEM WHERE ID ={0}", orderitem.Id);
db.detach(orderitem);

重新查询和重新填充数据集会更快。我如何强制重新查询?我认为以下会这样做:

 var order = db.order.First(r => r.Id == order.id);

编辑3:这似乎有助于强制刷新后删除,但仍然需要大约2秒:

db.Refresh(RefreshMode.StoreWins,Order.OrderItem);

我仍然没有真正理解为什么一个人不能仅仅重新查询Order.First(r => r.id == id)类型的查询信息需要花费不到2秒的时间。

entity-framework entity-framework-6
1个回答
1
投票

这可能是因为当您执行ExecuteStoredCommand时,Order及其订单项已为上下文所知。 EF不知道该命令与Order的任何缓存副本有关,因此该命令将被发送到数据库,但不会更新任何已加载的实体状态。 WHere-因为第一个会查找任何加载的OrderItem,当被告知从DbSet中删除它时,它会查找引用该订单项的任何加载实体。

如果您不想确保在删除之前加载实体,那么您将需要检查是否已加载实体,并刷新或分离其关联的引用。

如果orderitem代表一个实体应该只能使用:

db.OrderItems.Remove(orderitem);

如果订单已加载,则应自动删除订单商品。如果订单未加载,没有丢失,将在稍后请求时从数据库加载,并从DB加载订单项集。

但是,如果要使用SQL执行方法,则分离任何本地实例应将其从本地缓存中删除。

db.ExecuteStoreCommand("DELETE FROM ORDERITEM WHERE ID ={0}", orderitem.Id);
var existingOrderItem = db.OrderItems.Local.SingleOrDefault(x => x.Id == orderItem.Id);
if(existingOrderItem != null)
    db.Entity(existingOrderItem).State = EntityState.Detached;

我不相信你需要检查orderItem的订单以刷新除此之外的任何东西,但我不是100%肯定。通常,虽然在修改数据状态时,我选择加载适用的顶级实体并删除它的子级。

因此,如果我有命令从订单中删除订单商品:

public void RemoveOrderItem(int orderId, int orderItemId)
{
    using (var context = new MyDbContext())
    {
        // TODO: Validate that the current user session has access to this order ID
        var order = context.Orders.Include(x => x.OrderItems).Single(x => x.OrderId == orderId);
        var orderItem = order.OrderItems.SingleOrDefault(x => x.OrderItemId == orderItemId);
        if (orderItem != null)
            order.OrderItems.Remove(orderItem);

        context.SaveChanges();
    }
}

这种方法的关键点。

  • 虽然它确实意味着再次为操作加载数据状态,但这个负载是ID,所以它很快。
  • 我们可以/应该验证所请求的数据是否适用于用户。应记录他们不应访问的订单的任何命令,并且会话结束。
  • 我们知道我们将处理当前的数据状态,而不是根据数据首次读取的时间点对值/数据做出决策。
© www.soinside.com 2019 - 2024. All rights reserved.