5

我看过一些类似问题的答案,但它们似乎并不适合我。

我正在尝试从 Entity Framework: DbContext(page 90) 中合并一个模式,但它似乎不起作用。我正在使用的代码如下:

[HttpPost]
public ActionResult Edit(Order order)
{
     if (ModelState.IsValid)
     {
         db.Orders.Add(order);
         db.Entry(order).State = EntityState.Modified;

         foreach (var orderDetail in order.OrderDetails)
         {
              if (orderDetail.OrderId == 0)
              {
                  db.Entry(orderDetail).State = EntityState.Added;
              }
              else
              {
                  db.Entry(orderDetail).State = EntityState.Modified;
              }
              // The example order that I'm updating has two child entities
              // so this orderId will be for the third, added one.
              int addedOrderDetailId = order.OrderDetails[2].OrderId;
          }
          db.SaveChanges();
          return RedirectToAction("Index");
     }

     ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "CompanyName", order.CustomerId);

     return View(order);

}

我一直在运行一个示例,其中 Order 对象有两个现有的 OrderDetail 对象,我正在尝试添加第三个。我包含了 addedOrderDetailId 变量,以便我可以将其添加到“Watch”并查看它何时更改

我发现正在发生的是,实体框架正在将添加的 OrderDetail 对象的 OrderId (进入 foreach 循环时为 0)更新为 Order 对象的 OrderId。这发生在通过 foreach 循环的第一次迭代之后(当第一个子实体的状态更改为已修改时。这意味着所有三个子实体都被标记为已修改。这导致 SaveChanges() 尝试更新条目进入不存在的数据库。

如果其他人遇到过这个问题,那么我将非常感谢任何解决此问题的建议。我还必须处理被删除的现有子对象,但我还没有解决这个问题,所以如果有人知道这种模式,那也将不胜感激。

编辑:

在听取了 Slauma 的建议并删除了 db.Orders.Add(order)。我能够将调用移动到 foreach 循环下的 db.Entry(order).State 。这使我可以循环遍历循环并将每个 OrderDetail 对象的状态设置为针对现有对象进行修改并为添加的对象添加状态。然后,我只需将父项的 OrderId 分配给子项的 OrderId 即可,更新成功。我还包含了在编辑过程中用于删除子对象的代码。我不确定这有多有效,但它确实有效。这是修改后的代码:

    [HttpPost]
    public ActionResult Edit(Order order)
    {
        if (ModelState.IsValid)
        {
            List<int> previousProductIds = db.OrderDetails
                .Where(ep => ep.OrderId == order.OrderId)
                .Select(ep => ep.ProductId)
                .ToList();

            List<int> currentProductIds = order.OrderDetails
                .Select(o => o.ProductId)
                .ToList();

            List<int> deletedProductIds = previousProductIds
                .Except(currentProductIds).ToList();


            foreach (var deletedProductId in deletedProductIds)
            {
                OrderDetail deletedOrderDetail = db.OrderDetails
                    .Where(od => od.OrderId == order.OrderId && od.ProductId == deletedProductId)
                    .Single();

                db.Entry(deletedOrderDetail).State = EntityState.Deleted;
            }

            foreach (var orderDetail in order.OrderDetails)
            {
                if (orderDetail.OrderId == 0)
                {
                    db.Entry(orderDetail).State = EntityState.Added;
                    orderDetail.OrderId = order.OrderId;
                }
                else
                {
                    db.Entry(orderDetail).State = EntityState.Modified;
                }
            }
            db.Entry(order).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "CompanyName", order.CustomerId);
        return View(order);
    }
4

1 回答 1

1

从您的代码中删除这一行:

db.Orders.Add(order);

这实际上会将包含所有 orderDetails的订单置于Added状态。关系修正(在 中自动发生Add)将把OrderIdof all OrderDetails设置为 order 的 key。当您进入循环时orderDetail.OrderId!= 0所有详细项目都将进入循环,并且您始终会进入将状态设置为 的分支Modified。循环完成后,没有 orderDetail 项目处于Added状态。

于 2012-04-05T15:23:19.023 回答