繁体   English   中英

DBContext - 删除挂起的更改

[英]DBContext - remove pending changes

我有一个 MVC 应用程序,每个请求创建一次 DBContext。

在此请求中,我尝试保存订单列表

...

foreach (var order in orders)
{
  SaveOrder(order);
}

public SaveOrder(Order order)
{
  _context.Orders.Add(order);
  _context.SaveChanges();
}

...

但是,如果列表中的第一个订单引发异常,则其余订单都不会保存。

我试过捕捉异常然后使用

  _context.Orders.Remove(order)

但是在下一次调用数据库上下文中的 SaveChanges() 时,原始异常仍然会触发。

一些文章似乎建议为每个动作使用一个新的上下文,并用 using 语句包装——但这并不昂贵(它不会每次都创建一个新的连接吗?)

这样做的正确方法是什么? 有没有办法删除所有挂起的更改?

谢谢

可能这会有所帮助

public void SaveOrders()
{
    try
    {
        foreach (var order in orders)
        {
            if (!IsOrderEntryValid(order))
            {
                _invalidOrders.Add(order);
                continue;
            }
            if(!_context.Orders.Exists(/* write your logic to check if the order exists*/))
                _context.Orders.Add(order);

        }
        _context.SaveChanges();
    }
    catch(Exception ex)
    {
        // log the exception
    }
}

public ValidateOrder(Order order)
{
    // do some validations here that would not violate the data format and rules, cause violations and exceptions.
}

由于问题中给出的信息,这是非常通用的。 我敢肯定,您会想出验证和确保保存数据的方法不会因为数据库违规、约束违规、重复等而引发异常。您会从它抛出的异常中学到和/或必须记录它。 对我来说,一个不断发展的系统涉及对平台及其与数据相关的行为的学习。

要处理要从上下文中删除项目的情况,您需要将其与 DbContext 分离,而不是调用Remove Remove可能会导致一些不良后果,例如删除现有行。

因此,在您的情况下, SaveOrder 调用应该通过执行以下操作来工作:

public void SaveOrder(Order order)
{
    try
    {
        _context.Orders.Add(order);
        _context.SaveChanges();
    }
    catch (DbUpdateException ex)
    {
        _context.Entry(order).State = EntityState.Detached; // De-associate from the poisoned order.
        // TODO: Consider logging that this order could not be saved or returning a result to that effect.
    }
}   

请注意,如果 Order 实体具有作为此操作的一部分添加/更新的子项,则您也需要分离它们。 IE

    catch (DbUpdateException ex)
    {
        _context.Entry(order).State = EntityState.Detached; 
        foreach(var orderLine in order.OrderLines)
        {
            _context.Entry(orderLine).State = EntityState.Detached;
        }
    }

仅适用于由操作添加或以其他方式更新的行。 如果此操作未创建/更新客户记录,则您不希望分离 Order.Customer。

我更喜欢使用工作单元模式,它将插入新订单视为单个操作,包括一个工作单元。 如果我创建 5 个订单,每个订单彼此独立(1 个失败不会影响其他订单),那么它们是 5 个独立的操作。 启动作用域 DbContext 通常是避免交叉操作“中毒”的最安全选项,并且不会产生大量成本。 对于接触相同数据的操作,会产生额外的读取成本,尽管这些通常是按 ID 场景(客户按 ID、产品按 ID 等)获取的,因此它们的成本很低。 将订单周围的附加和分离状态弄得太多会导致更严重的问题,因为在 Save 调用之后,“订单”引用可能是,也可能不是现在被跟踪的实体。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM