简体   繁体   English

如何在 MVC 5 和 EF 6 中保存对相关表的更改 - Entity Framework Master-Detail

[英]How to save changes to related table in MVC 5 and EF 6 - Entity Framework Master-Detail

I have two tables, Promotion and PromotionLine, with a foreign key defined as PromotionLine.PromoID = Promotion.ID我有两个表,Promotion 和 PromotionLine,外键定义为 PromotionLine.PromoID = Promotion.ID

PromotionLines are associated with the Promotion model with the following in the Promotion class: PromotionLines 与 Promotion 模型相关联,在 Promotion 类中具有以下内容:

public IList<PromotionLine> PromotionLineItems { get; set; }

I chose not to use virtual because I don't want the promo lines loaded if we're just using a summary view to show high level Promotion info (such as a list of Promotions).我选择不使用虚拟,因为如果我们只是使用摘要视图来显示高级促销信息(例如促销列表),我不希望加载促销行。

When promotion details are needed, I get the promotion lines:当需要促销详细信息时,我会得到促销行:

    public static Promotion GetInstance(int? promotionId)
    {
        if (promotionId == null) return null;
        using (APP01Entities entities = new APP01Entities())
        {
            return entities.Promotions
                .Include(s => s.PromotionState)
                .Include(h => h.PromotionHeaderType)
                .Include(l => l.PromotionLineItems)
                .Include(c => c.PromotionComments)
                .FirstOrDefault(p => p.ID == promotionId);
        }

    }

This works, and I can access the promotion lines in my view.这有效,我可以在我的视图中访问促销行。

However, when I go to update changes, I encounter the error:但是,当我去更新更改时,我遇到了错误:

“A referential integrity constraint violation occurred: The property value(s) of 'Promotion.ID' on one end of a relationship do not match the property value(s) of 'PromotionLine.PromotionID' on the other end.” “发生了参照完整性约束违规:关系一端的‘Promotion.ID’的属性值与另一端‘PromotionLine.PromotionID’的属性值不匹配。”

I understand WHY this error is occurring.我明白为什么会发生这个错误。 I don't know how to get around it.我不知道如何绕过它。 I'm using the default update method (created by EF scaffolding):我正在使用默认更新方法(由 EF 脚手架创建):

public bool Update()
    {
        try
        {
            using (APP01Entities entities = new APP01Entities())
            {
                entities.Promotions.Attach(this);

                var entity = entities.ChangeTracker.Entries<Promotion>().FirstOrDefault(e => e.Entity == this);

                if (entity == null)
                {
                    return false;
                }
                entity.State = EntityState.Modified;
                entities.SaveChanges();
            }
            return true;
        }
        catch (System.Data.Entity.Validation.DbEntityValidationException e)
        {
            throw e.Improve();
        }
    }

The problem is with:问题在于:

entities.Promotions.Attach(this);

"this" has the promotion lines. “这”有宣传线。 entities.Promotions does not. entity.Promotions 没有。

Here is how I'm calling the update method:这是我调用更新方法的方式:

    [HttpPost]
    public ActionResult Edit(Promotion promotion)
    {
        if (ModelState.IsValid)
        {
            promotion.Update();
        }
        return View(promotion);
    }

Questions问题

  • How do I get the promotion lines added to entities.Promotions?如何将促销行添加到entities.Promotions?
  • or, should I be approaching this update differently?或者,我应该以不同的方式处理此更新吗?

This is not a trivial task.这不是一项微不足道的任务。 You need to update your object graph.您需要更新对象图。 In other word you need a Master-Detail update.换句话说,您需要主从更新。

To keep the answer simple I suppose I have an Order entity that have OrderDetails property that is a List<OrderDetail> .You should pay attention when editing:为了简单OrderDetails ,我想我有一个Order实体,它有一个List<OrderDetail> OrderDetails属性。编辑时应该注意:

  • There are some OrderDetail that have been added to OrderDetails and the main sign of them is having Id property equal to 0.有一些OrderDetail已添加到OrderDetails ,它们的主要标志是Id属性等于 0。
  • Some OrderDetail have been removed and no longer exist in OrderDetails一些OrderDetail已被删除,不再存在于OrderDetails
  • Some OrderDetail have been changed.一些OrderDetail已更改。

When updating the Order you should update the Order itself and also apply above changes.更新Order您应该更新Order本身并应用上述更改。

Steps脚步

Here are steps:以下是步骤:

  1. Get original order from database.从数据库中获取原始订单。
  2. Update the value of original order using edited order.使用编辑后的订单更新原始订单的值。
  3. Find list of added items (Id of added items is 0).查找添加项目的列表(添加项目的 ID 为 0)。
  4. Find list of removed items (list of order details of original order where id of original order details is not between ids of order details of edited order).查找已删除项目的列表(原始订单的订单详情列表,其中原始订单详情的 id 不在已编辑订单的订单详情的 id 之间)。
  5. Find list of edited items (list of order details of original order where id of original order details is between ids of order details of edited order).查找已编辑商品的列表(原始订单的订单详情列表,其中原始订单详情的 id 介于已编辑订单的订单详情 id 之间)。
  6. Use a loop over deleted items list and set state of them to removed.在已删除项目列表上使用循环并将它们的状态设置为已删除。
  7. Use a loop over edited items list and update value of original order details that have been loaded in context.在已编辑的项目列表上使用循环并更新已在上下文中加载的原始订单详细信息的值。
  8. Use a loop over added items list and set state of them to added.在添加的项目列表上使用循环并将它们的状态设置为添加。
  9. Set the state of original order to modified.将原始订单的状态设置为已修改。
  10. Save context changes.保存上下文更改。

Code代码

Here is the code:这是代码:

public void Update(Order editedOrder)
{
    using(var context = new YourDbContext())
    {   
        //Get original order from database.
        var originalOrder = context.Orders.Including("OrderDetails")
            .Where(x => x.OrderId == editedOrder.OrderId).FirstOrDefault();

        //Update the value of original order using edited order.
        context.Entry(originalOrder).CurrentValues.SetValues(editedOrder);

        //Find list of added items (Id of added items is 0).
        var addedList = editedOrder.OrderDetails
            .Where(y => y.OrderDetailId == 0).ToList();

        //Find list of removed items.
        var deletedList = originalOrder.OrderDetails
            .Where
            (
                x =>!editedOrder.OrderDetails.Select(y => y.OrderDetailId)
                        .Contains(x.OrderDetailId)
            )
            .ToList();

        //Find list of edited items.
        var editedList = editedOrder.OrderDetails
            .Where
            (
                y => originalOrder.OrderDetails.Select(z => z.OrderDetailId)
                         .Contains(y.OrderDetailId)
            )
            .ToList();

        //Use a loop over deleted items list and set state of them to removed.
        deletedList.ForEach(deletedDetail =>
        {
            originalOrder.OrderDetails.Remove(deletedDetail);
            context.Entry(editedOrder).State = EntityState.Deleted;
        });

        //Use a loop over edited items list 
        //and update value of original order details  that have been loaded in context.
        editedList.ForEach(editedDetail =>
        {
            var originalOrderDetail = originalOrder.OrderDetails
                .Where(x => x.OrderDetailId == editedDetail.OrderDetailId)
                .FirstOrDefault();
           context.Entry(originalOrderDetail).CurrentValues.SetValues(editedDetail);
        });

        //Use a loop over added items list and set state of them to added.
        addedList.ForEach(addedDetail =>
        {
            originalOrder.OrderDetails.Add(addedDetail);
        });

        //Set the state of original order to modified.
        context.Entry(oroginalOrder).State = System.Data.Entity.EntityState.Modified;

        //Save context changes.
        context.SaveChanges();
    }
}

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

相关问题 如何使用实体框架在XAF中实现真正的主从细节? - How to implement a true Master-Detail in XAF using Entity Framework? 如何在实体框架中插入/更新主从? - How to insert/update master-detail in Entity Framework? 使用实体框架核心进行表拆分。 将表展平到主从 - Table Splitting with Entity Framework Core. Flatten Table to Master-Detail 没有外键的实体框架主从数据输入 - Entity Framework master-detail data entry without foreign key 实体框架6多个嵌套的主细节插入 - Entity Framework 6 multiple nested master-detail insert 实体框架-如何将多个更改(添加,更新,删除)保存到数据库(主详细信息) - Entity Framework - how to save multiple changes (add, update, delete) to DB (Master detail) 如何在ASP.NET MVC 5中插入主 - 详细信息表 - How to Insert to Master-detail tables in ASP.NET MVC 5 实体框架 6:主细节视图显示单个 HashSet 而不是过滤的细节项 - Entity Framework 6: Master-Detail view shows single HashSet instead of filtered detail items 正确的方式实体框架主 - 详细插入记录代码插入子 - Correct way Entity framework master-detail insert record code for inserting child 实体框架,代码优先:将主 - 细节与零对一关系相结合 - Entity Framework, code-first: combining master-detail with zero-to-one relationship
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM