Search code examples
c#asp.net-mvccheckboxmvvmsaving-data

Not saving the changes I make when I deselect Orders using checkboxes from an existing Delivery


I'm having difficulty in saving changes I make to a existing Delivery on the Edit Delivery page when I try to deselect Orders that have already been linked to that Delivery.

I want to be able to remove those Orders I've already added when I initially Created the Delivery and add more based on the Orders available today and then save.

Currently, it doesn't save when I deselect the Orders that I have previously added through the Create method, so those Orders are still linked to the Delivery. However, it does allow me to add more Orders so that's alright.

So, essentially, the problem lies in the POST method of Edit.

Can anyone please advise me on a fix or a way forward? Thank you in advance.

View Models:

 public class DeliveryVM
{
    public int? ID { get; set; }
    public DateTime Dispatched_Date { get; set; }
    public List<OrderVM> Orders { get; set; }
}

public class OrderVM
{
    public int ID { get; set; }
    public string Name { get; set; }
    public DateTime Date { get; set; }
    public int DeliveryID { get; set; }
    public bool IsSelected { get; set; }
}

Models:

public class Order
{
    public int OrderID { get; set; }
    public int? DeliveryID { get; set; }
    public DateTime Expected_Date { get; set; }
    public virtual Delivery Delivery { get; set; }
    public virtual ICollection<OrderItem> OrderItems { get; set; }
}

public class Delivery
{

    public int DeliveryID { get; set; }
    public DateTime Dispatched_Date { get; set; }
    public virtual ICollection<Order> Orders { get; set; }
}

Edit Method in Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(DeliveryVM model)
{
    // Get the data model based on the ID of the view model
    Delivery delivery = db.Deliverys.Find(model.ID);
    // Map the view model properties to the data model
    delivery.DriverID = model.DriverID;
     ...
    // Mark as modified and save
    IEnumerable<int> selectedOrders = model.Orders.Where(o => o.IsSelected).Select(o => o.ID);
    foreach (int ID in selectedOrders)
    {
        Order order = db.Orders.Where(o => o.OrderID == ID).FirstOrDefault();
        order.DeliveryID = delivery.DeliveryID;
        db.Entry(order).State = EntityState.Modified;
        db.SaveChanges();
    }

    return RedirectToAction("Details", new { id = delivery.DeliveryID });

}

Solution

  • Your current code is only modifying the orders that have been selected in the Edit view, and unnecessarily updating orders that were previously selected.

    You need to make a comparison with the original orders, and take the appropriate action

    // Get the original selected orders
    IEnumerable<int> originalOrders = delivery.Orders.Select(o => o.OrderID);
    // Get the selected orders from the Edit view
    IEnumerable<int> selectedOrders = model.Orders.Where(o => o.IsSelected).Select(o => o.ID);
    // Get the orders that have been added
    IEnumerable<int> newOrders = selectedOrders.Except(originalOrders);
    // Get the orders that have been deleted
    IEnumerable<int> deletedOrders = originalOrders.Except(selectedOrders);
    foreach (int ID in newOrders)
    {
      // Get the order, set its DeliveryID property and save (as per your existing code)
    }
    IEnumerable<Order> toDelete= db.Orders.Where(o => deletedOrders.Contains(o.OrderID));
    foreach (Order order in toDelete)
    {
      order.DeliveryID = null;
      db.Entry(order).State = EntityState.Modified;
    }
    db.SaveChanges();
    

    Side note: There is no need to update items that have not changed, but if you wanted to get them, it would be

    IEnumerable<int> unchangedOrders= originalOrders.Intersect(selectedOrders);