CheckBoxList Update Issue
<p>I'm using ASP.NET Core MVC, EntityFramework Core and C#.</p>

<p>I'm having trouble updating the CheckBoxList values to the CustomerDevice table in my Database on the [HttpPost] Edit Action Method CustomerDeviceController. The CustomerDevice table is a JOIN table that has a Many to Many between the Customer and Device tables.</p>

<p>My Index Action Method for the CustomerDeviceController displays a list of Customers from my Customers table. I have an ActionLink labeled "Edit" that passes the CustId value to the CustomerDeviceController [HttpGet] Edit(int? id) Action Method which then displays all selected DevId values assigned to the CustId to the CheckBoxList, this part works fine.</p>

<p>When I try to update the CheckBoxList values now it adds the DevId values that I choose to remove and the DevId values that I want to keep it removes.</p>

<p>So for Example: If I initially added DevId values (1, 3, 4 and 7) for CustId 1006 and then decide to Edit to remove just DevId value 1 it actually removes DevId values (3, 4 and 7) and leaves DevId value 1.</p>

<p><strong>Models</strong></p>

<pre><code>public class CheckBoxListItem
{
    public int ID { get; set; }
    public string Display { get; set; }
    public bool IsChecked { get; set; }
}

public class Customer
{
    public int CustId { get; set; }
    public string CustDisplayName { get; set; }
    public string CustFirstName { get; set; }
    public string CustLastName { get; set; }

    public List&lt;CustomerDevice&gt; CustomerDevices { get; set; }
}

public class CustomerDevice
{
    public int CustId { get; set; }
    public int DevId { get; set; }

    public Customer Customer { get; set; }
    public Device Device { get; set; }
}

public class Device
{
    public int DevId { get; set; }
    public string DevType { get; set; }

    public List&lt;CustomerDevice&gt; CustomerDevices { get; set; }
}

public class WebFormContext : DbContext
{
    public WebFormContext(DbContextOptions&lt;WebFormContext&gt; options)
        : base(options)
    { }

    public DbSet&lt;Customer&gt; Customers { get; set; }
    public DbSet&lt;Device&gt; Devices { get; set; }
    public DbSet&lt;CustomerDevice&gt; CustomerDevices { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity&lt;Customer&gt;()
            .HasKey(c =&gt; c.CustId);

        modelBuilder.Entity&lt;Customer&gt;()
            .Property(c =&gt; c.CustDisplayName)
            .HasColumnType("varchar(100)")
            .HasMaxLength(100)
            .IsRequired();

        modelBuilder.Entity&lt;Customer&gt;()
            .Property(c =&gt; c.CustFirstName)
            .HasColumnType("varchar(50)")
            .HasMaxLength(50);

        modelBuilder.Entity&lt;Customer&gt;()
            .Property(c =&gt; c.CustLastName)
            .HasColumnType("varchar(50)")
            .HasMaxLength(50);

        modelBuilder.Entity&lt;Device&gt;()
            .HasKey(d =&gt; d.DevId);

        modelBuilder.Entity&lt;Device&gt;()
            .Property(d =&gt; d.DevType)
            .HasColumnType("varchar(50)")
            .HasMaxLength(50)
            .IsRequired();

        modelBuilder.Entity&lt;CustomerDevice&gt;()
        .HasKey(c =&gt; new { c.CustId, c.DevId });

        modelBuilder.Entity&lt;CustomerDevice&gt;()
            .HasOne(cd =&gt; cd.Customer)
            .WithMany(c =&gt; c.CustomerDevices)
            .HasForeignKey(cd =&gt; cd.CustId);

        modelBuilder.Entity&lt;CustomerDevice&gt;()
            .HasOne(cd =&gt; cd.Device)
            .WithMany(d =&gt; d.CustomerDevices)
            .HasForeignKey(cd =&gt; cd.DevId);
    }
}
</code></pre>

<p><strong>ViewModel</strong></p>

<pre><code>public class CustomerDeviceFormViewModel
{
    public int CustId { get; set; }
    public string CustDisplayName { get; set; }
    public List&lt;CheckBoxListItem&gt; Devices { get; set; }
}
</code></pre>

<p><strong>Controller</strong></p>

<pre><code>public class CustomerDeviceController : Controller
{
    // GET: /&lt;controller&gt;/
    public IActionResult Index()
    {
        return View(db.Customers.ToList());
    }


    public ActionResult Edit(int? id)
    {
        Customer customer = db.Customers.SingleOrDefault(c =&gt; c.CustId == id);
        if (customer == null)
        {
            return NotFound();
        }
        // Get all devices
        var deviceList = db.Devices.ToList();
        // Get the selected device ID's for the customer
        IEnumerable&lt;int&gt; selectedDevices = db.CustomerDevices
            .Where(x =&gt; x.CustId == id).Select(x =&gt; x.DevId);
        // Build view model
        var model = new CustomerDeviceFormViewModel()
        {
            CustId = customer.CustId,
            CustDisplayName = customer.CustDisplayName,
            Devices = deviceList.Select(x =&gt; new CheckBoxListItem()
            {
                ID = x.DevId,
                Display = x.DevType,
                IsChecked = selectedDevices.Contains(x.DevId)
            }).ToList()
        };
        return View(model);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(CustomerDeviceFormViewModel vmEdit)
    {
        if (ModelState.IsValid)
        {
            Customer customer = db.Customers
                       .Include(c =&gt; c.CustomerDevices)
                       .SingleOrDefault(c =&gt; c.CustId == vmEdit.CustId);

            if (customer == null)
            {
                return NotFound();
            }

            IEnumerable&lt;int&gt; selectedDevices = vmEdit.Devices.Where(x =&gt; x.IsChecked).Select(x =&gt; x.ID);

            // Add the new selected devices
            foreach (int deviceId in selectedDevices)
            {
                var customerDevice = customer.CustomerDevices.FirstOrDefault(cd =&gt; cd.DevId == deviceId);
                if (customerDevice != null)
                {
                    customer.CustomerDevices.Remove(customerDevice);
                }
                else
                {
                    CustomerDevice custDevice = new CustomerDevice
                    {
                        CustId = customer.CustId,
                        DevId = deviceId
                    };
                    customer.CustomerDevices.Add(custDevice);
                }
            }

            // Update the customer
            db.Customers.Update(customer); //or just db.Update(customer); same thing
                                           // Save and redirect
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(vmEdit);
    }
}
</code></pre>

<p><strong>Shared/EditorTemplates/CheckBoxListItem.chtml</strong></p>

<pre><code>&lt;div class="checkbox"&gt;
&lt;label&gt;
    @Html.HiddenFor(x =&gt; x.ID)
    @Html.CheckBoxFor(x =&gt; x.IsChecked)
    @Html.LabelFor(x =&gt; x.IsChecked, Model.Display)
&lt;/label&gt;
&lt;br /&gt;
</code></pre>

<p></p>

<p><strong>Edit View</strong></p>

<pre><code>&lt;div class="form-group"&gt;
    Please select the Devices to assign to &lt;b&gt;@Html.DisplayFor(c =&gt; c.CustDisplayName)&lt;/b&gt;
&lt;/div&gt;

&lt;div class="form-group"&gt;
    @Html.EditorFor(x =&gt; x.Devices)
&lt;/div&gt;

@Html.HiddenFor(c =&gt; c.CustId)

&lt;div class="form-group"&gt;
    &lt;button type="submit" class="btn btn-primary"&gt;Submit&lt;/button&gt;
&lt;/div&gt;
</code></pre>