Asp.net ядро MVC для редактирования значений CheckBoxList С в базе
У меня возникли проблемы с обновлением значений CheckBoxList в таблицу CustomerDevice в моей базе данных на [HttpPost] Edit Action Method CustomerDeviceController.
Метод действия Index для CustomerDeviceController отображает список клиентов из таблицы my Customers. У меня есть ActionLink с надписью "Edit", который передает значение CustId в CustomerDeviceController [HttpGet] Edit (int? id) метод действия, который затем отображает все выбранные значения DevId, назначенные CustId в CheckBoxList, эта часть работает нормально.
Проблема, с которой я столкнулся, заключается в том, что если я изначально добавил значения DevId (1, 3, 4 и 7) для CustId 1006, а затем решил удалить только значение DevId 1, то на самом деле он удаляет значения DevId (3, 4 и 7) и оставляет значение DevId 1.
Таким образом, кажется, что он добавляет значения DevId, которые я выбираю для удаления, и значения DevId, которые я хочу сохранить, он удаляет. Я включил мои модели, модель представления, контроллера и представления. Я надеюсь, что кто-то может увидеть, что я делаю неправильно или нужно добавить, чтобы исправить эту проблему.
Модели
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 string CustCompanyName { get; set; } public string CustAddress { get; set; } public string CustPhoneNumber { get; set; } public string CustMobileNumber { get; set; } public string CustEmailAddress { get; set; } public List<customerdevice> 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<customerdevice> CustomerDevices { get; set; } }
public class WebFormContext : DbContext { public WebFormContext(DbContextOptions<webformcontext> options) : base(options) { } public DbSet<customer> Customers { get; set; } public DbSet<state> States { get; set; } public DbSet<device> Devices { get; set; } public DbSet<customerdevice> CustomerDevices { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<customer>() .HasKey(c => c.CustId); modelBuilder.Entity<customer>() .Property(c => c.CustDisplayName) .HasColumnType("varchar(100)") .HasMaxLength(100) .IsRequired(); modelBuilder.Entity<customer>() .Property(c => c.CustFirstName) .HasColumnType("varchar(50)") .HasMaxLength(50); modelBuilder.Entity<customer>() .Property(c => c.CustLastName) .HasColumnType("varchar(50)") .HasMaxLength(50); modelBuilder.Entity<customer>() .Property(c => c.CustCompanyName) .HasColumnType("varchar(50)") .HasMaxLength(50); modelBuilder.Entity<customer>() .Property(c => c.CustAddress) .HasColumnType("varchar(100)") .HasMaxLength(100) .IsRequired(); modelBuilder.Entity<customer>() .Property(c => c.CustPhoneNumber) .HasColumnType("varchar(12)") .HasMaxLength(12); modelBuilder.Entity<customer>() .Property(c => c.CustMobileNumber) .HasColumnType("varchar(12)") .HasMaxLength(12); modelBuilder.Entity<customer>() .Property(c => c.CustEmailAddress) .HasColumnType("varchar(320)") .HasMaxLength(320); modelBuilder.Entity<device>() .HasKey(d => d.DevId); modelBuilder.Entity<device>() .Property(d => d.DevType) .HasColumnType("varchar(50)") .HasMaxLength(50) .IsRequired(); modelBuilder.Entity<customerdevice>() .HasKey(c => new { c.CustId, c.DevId }); modelBuilder.Entity<customerdevice>() .HasOne(cd => cd.Customer) .WithMany(c => c.CustomerDevices) .HasForeignKey(cd => cd.CustId); modelBuilder.Entity<customerdevice>() .HasOne(cd => cd.Device) .WithMany(d => d.CustomerDevices) .HasForeignKey(cd => cd.DevId); } }
модель представления
public class CustomerDeviceFormViewModel { public int CustId { get; set; } public string CustDisplayName { get; set; } public List<checkboxlistitem> Devices { get; set; } }
CustomerDeviceController
public class CustomerDeviceController : Controller { private WebFormContext db; public CustomerDeviceController(WebFormContext context) { db = context; } // GET: /<controller>/ public IActionResult Index() { return View(db.Customers.ToList()); } public ActionResult Create(int? id) { if (id == null) { return NotFound(); } var customervm = new CustomerDeviceFormViewModel(); { Customer customer = db.Customers.SingleOrDefault(c => c.CustId == id); if (customer == null) { return NotFound(); } customervm.CustId = customer.CustId; customervm.CustDisplayName = customer.CustDisplayName; // Retrieves list of Devices for CheckBoxList var deviceList = db.Devices.ToList(); var checkBoxListItems = new List<checkboxlistitem>(); foreach (var device in deviceList) { checkBoxListItems.Add(new CheckBoxListItem() { ID = device.DevId, Display = device.DevType, IsChecked = false //On the create view, no devices are selected by default }); } customervm.Devices = checkBoxListItems; return View(customervm); } } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Create(CustomerDeviceFormViewModel vm) { if (ModelState.IsValid) { foreach (var deviceId in vm.Devices.Where(x => x.IsChecked).Select(x => x.ID)) { var customerDevices = new CustomerDevice { CustId = vm.CustId, DevId = deviceId }; db.CustomerDevices.Add(customerDevices); } db.SaveChanges(); return RedirectToAction("Index"); } return View(vm); } public ActionResult Edit(int? id) { Customer customer = db.Customers.SingleOrDefault(c => 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<int> selectedDevices = db.CustomerDevices .Where(x => x.CustId == id).Select(x => x.DevId); // Build view model var model = new CustomerDeviceFormViewModel() { CustId = customer.CustId, CustDisplayName = customer.CustDisplayName, Devices = deviceList.Select(x => 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 => c.CustomerDevices) .SingleOrDefault(c => c.CustId == vmEdit.CustId); if (customer == null) { return NotFound(); } IEnumerable<int> selectedDevices = vmEdit.Devices.Where(x => x.IsChecked).Select(x => x.ID); // Add the new selected devices foreach (int deviceId in selectedDevices) { var customerDevice = customer.CustomerDevices.FirstOrDefault(cd => 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); } }
Изменить Вид
@using (Html.BeginForm("Edit", "CustomerDevice")) { <div class="form-group"> Please select the Devices to assign </div> <div class="form-group"> @Html.EditorFor(x => x.Devices) </div> @Html.HiddenFor(c => c.CustId) <div class="form-group"> <button type="submit" class="btn btn-primary">Submit</button> </div> }
Общий вид\EditorTemplates\CheckBoxListItems. chtml
<div class="checkbox"> <label> @Html.HiddenFor(x => x.ID) @Html.CheckBoxFor(x => x.IsChecked) @Html.LabelFor(x => x.IsChecked, Model.Display) </label> <br> </div>
Изменить представление (исходный код), отображающее значения CheckBoxList:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Edit Device(s) to Customer - WebForm</title> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/">WebForm</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a href="/">Home</a></li> <li><a href="/Customer">Customer</a></li> <li><a href="/CustomerDevice">Customer Device</a></li> <li><a href="/Home/Contact">Contact</a></li> </ul> </div> </div> </div> <div class="container body-content"> <h2>Edit Device(s) to Customer</h2> <form action="/CustomerDevice/Edit/1006" method="post"> <div class="form-group"> Please select the Devices to assign to Mary Doe </div> <div class="form-group"> <div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_0__ID" name="Devices[0].ID" type="hidden" value="1" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_0__IsChecked" name="Devices[0].IsChecked" type="checkbox" value="true" /> <label for="Devices_0__IsChecked">Desktop</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_1__ID" name="Devices[1].ID" type="hidden" value="2" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_1__IsChecked" name="Devices[1].IsChecked" type="checkbox" value="true" /> <label for="Devices_1__IsChecked">Laptop</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_2__ID" name="Devices[2].ID" type="hidden" value="3" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_2__IsChecked" name="Devices[2].IsChecked" type="checkbox" value="true" /> <label for="Devices_2__IsChecked">Keyboard</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_3__ID" name="Devices[3].ID" type="hidden" value="4" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_3__IsChecked" name="Devices[3].IsChecked" type="checkbox" value="true" /> <label for="Devices_3__IsChecked">Mouse</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_4__ID" name="Devices[4].ID" type="hidden" value="5" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_4__IsChecked" name="Devices[4].IsChecked" type="checkbox" value="true" /> <label for="Devices_4__IsChecked">Headset</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_5__ID" name="Devices[5].ID" type="hidden" value="6" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_5__IsChecked" name="Devices[5].IsChecked" type="checkbox" value="true" /> <label for="Devices_5__IsChecked">iPad</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_6__ID" name="Devices[6].ID" type="hidden" value="7" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_6__IsChecked" name="Devices[6].IsChecked" type="checkbox" value="true" /> <label for="Devices_6__IsChecked">Power Adapter</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_7__ID" name="Devices[7].ID" type="hidden" value="8" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_7__IsChecked" name="Devices[7].IsChecked" type="checkbox" value="true" /> <label for="Devices_7__IsChecked">Phone</label> </label> <br> </div> </div> <input data-val="true" data-val-required="The CustId field is required." id="CustId" name="CustId" type="hidden" value="1006" /> <div class="form-group"> <button type="submit" class="btn btn-primary">Submit</button> </div> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8OavugUS_IJDuIPr6xpVUkAb3CZQhxvBHON5YMfwP6vLHdCL6yuyiD3HruUggKlQpJ2y76owQYcGwjszMdBzS5_YJxx1D1chcDeI_8RMGmDQW-S6yT0BV4yjVVnJYFJgB65jvQOtIaMn9hY593axunQ" /><input name="Devices[0].IsChecked" type="hidden" value="false" /><input name="Devices[1].IsChecked" type="hidden" value="false" /><input name="Devices[2].IsChecked" type="hidden" value="false" /><input name="Devices[3].IsChecked" type="hidden" value="false" /><input name="Devices[4].IsChecked" type="hidden" value="false" /><input name="Devices[5].IsChecked" type="hidden" value="false" /><input name="Devices[6].IsChecked" type="hidden" value="false" /><input name="Devices[7].IsChecked" type="hidden" value="false" /></form> <hr> <p>© 2016 - WebForm</p> </div> <script src="/lib/jquery/dist/jquery.js"></script> <script src="/lib/bootstrap/dist/js/bootstrap.js"></script> <script src="/js/site.js?v=EWaMeWsJBYWmL2g_KkgXZQ5nPe-a3Ichp0LEgzXczKo"></script> <script src="/lib/jquery-validation/dist/jquery.validate.js"></script> <script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> <!-- Visual Studio Browser Link --> <script type="application/json" id="__browserLink_initializationData"> {"requestId":"359eef69ee5348909cbbb8b0835fbb27","requestMappingFromServer":false} </script> <script type="text/javascript" src="http://localhost:53061/6ddbe519e8204b1d8cafa73b53ac5a72/browserLink" async="async"></script> <!-- End Browser Link --> </body> </html>
Изменить представление (исходный код), которое показывает значения CheckBoxList, присвоенные CustId 1006:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Edit Device(s) to Customer - WebForm</title> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/">WebForm</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a href="/">Home</a></li> <li><a href="/Customer">Customer</a></li> <li><a href="/CustomerDevice">Customer Device</a></li> <li><a href="/Home/Contact">Contact</a></li> </ul> </div> </div> </div> <div class="container body-content"> <h2>Edit Device(s) to Customer</h2> <form action="/CustomerDevice/Edit/1006" method="post"> <div class="form-group"> Please select the Devices to assign to Mary Doe </div> <div class="form-group"> <div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_0__ID" name="Devices[0].ID" type="hidden" value="1" /> <input checked="checked" data-val="true" data-val-required="The IsChecked field is required." id="Devices_0__IsChecked" name="Devices[0].IsChecked" type="checkbox" value="true" /> <label for="Devices_0__IsChecked">Desktop</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_1__ID" name="Devices[1].ID" type="hidden" value="2" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_1__IsChecked" name="Devices[1].IsChecked" type="checkbox" value="true" /> <label for="Devices_1__IsChecked">Laptop</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_2__ID" name="Devices[2].ID" type="hidden" value="3" /> <input checked="checked" data-val="true" data-val-required="The IsChecked field is required." id="Devices_2__IsChecked" name="Devices[2].IsChecked" type="checkbox" value="true" /> <label for="Devices_2__IsChecked">Keyboard</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_3__ID" name="Devices[3].ID" type="hidden" value="4" /> <input checked="checked" data-val="true" data-val-required="The IsChecked field is required." id="Devices_3__IsChecked" name="Devices[3].IsChecked" type="checkbox" value="true" /> <label for="Devices_3__IsChecked">Mouse</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_4__ID" name="Devices[4].ID" type="hidden" value="5" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_4__IsChecked" name="Devices[4].IsChecked" type="checkbox" value="true" /> <label for="Devices_4__IsChecked">Headset</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_5__ID" name="Devices[5].ID" type="hidden" value="6" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_5__IsChecked" name="Devices[5].IsChecked" type="checkbox" value="true" /> <label for="Devices_5__IsChecked">iPad</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_6__ID" name="Devices[6].ID" type="hidden" value="7" /> <input checked="checked" data-val="true" data-val-required="The IsChecked field is required." id="Devices_6__IsChecked" name="Devices[6].IsChecked" type="checkbox" value="true" /> <label for="Devices_6__IsChecked">Power Adapter</label> </label> <br> </div><div class="checkbox"> <label> <input data-val="true" data-val-required="The ID field is required." id="Devices_7__ID" name="Devices[7].ID" type="hidden" value="8" /> <input data-val="true" data-val-required="The IsChecked field is required." id="Devices_7__IsChecked" name="Devices[7].IsChecked" type="checkbox" value="true" /> <label for="Devices_7__IsChecked">Phone</label> </label> <br> </div> </div> <input data-val="true" data-val-required="The CustId field is required." id="CustId" name="CustId" type="hidden" value="1006" /> <div class="form-group"> <button type="submit" class="btn btn-primary">Submit</button> </div> <input name="__RequestVerificationToken" type="hidden" value="CfDJ8OavugUS_IJDuIPr6xpVUkAPOUb8w4S2Vnz2eyIV8YmkPTHJ_uvBT34rWHhobOnSJn4zwQ2tmIW1Ib3ynRht8S8j8a6WEQP3DCpB15DotmCyxr3fYyTIM_lGrE2sNXqfYfjscGCHOhY-irNE3h5jB9k" /><input name="Devices[0].IsChecked" type="hidden" value="false" /><input name="Devices[1].IsChecked" type="hidden" value="false" /><input name="Devices[2].IsChecked" type="hidden" value="false" /><input name="Devices[3].IsChecked" type="hidden" value="false" /><input name="Devices[4].IsChecked" type="hidden" value="false" /><input name="Devices[5].IsChecked" type="hidden" value="false" /><input name="Devices[6].IsChecked" type="hidden" value="false" /><input name="Devices[7].IsChecked" type="hidden" value="false" /></form> <hr> <p>© 2016 - WebForm</p> </div> <script src="/lib/jquery/dist/jquery.js"></script> <script src="/lib/bootstrap/dist/js/bootstrap.js"></script> <script src="/js/site.js?v=EWaMeWsJBYWmL2g_KkgXZQ5nPe-a3Ichp0LEgzXczKo"></script> <script src="/lib/jquery-validation/dist/jquery.validate.js"></script> <script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> <!-- Visual Studio Browser Link --> <script type="application/json" id="__browserLink_initializationData"> {"requestId":"db2020dde36447d49b6a626dad3c3c43","requestMappingFromServer":false} </script> <script type="text/javascript" src="http://localhost:53061/6ddbe519e8204b1d8cafa73b53ac5a72/browserLink" async="async"></script> <!-- End Browser Link --> </body> </html>
Я представления значения CheckBoxList с помощью кнопки "Отправить".
Что я уже пробовал:
Я пробовал устанавливать точки останова в различных областях в своем посте редактирования, и эти значения кажутся мне нормальными. Но после того, как я обновляю значения, они становятся неверными.