ASP.NET MVC Редактирайте стойностите на CheckBoxList в базата данни

Имам проблеми с разбирането как да извлека и редактирам стойностите на DevId от моята таблица CustomerDevice в моята база данни в CheckBoxList въз основа на стойността на CustId.

Моят метод за действие с индекс за CustomerDeviceController показва списък с клиенти от моята таблица с клиенти. Имам ActionLink с етикет „Редактиране“, който предава стойността на CustId към метода на действие CustomerDeviceController [HttpGet] Edit(int? id), който в момента показва всички стойности на CheckBoxListItem от таблицата Devices. Въпреки това CheckBoxList не показва проверените стойности на DevId от таблицата CustomerDevice в базата данни към CheckBoxList, които се отнасят до CustId, вместо това показва проверка за всяка от стойностите на CheckBoxList.

Частта, която имам проблеми с разбирането и измислянето, е как мога да покажа избраните стойности на DevId от таблицата CustomerDevice в моята база данни в CheckBoxList въз основа на CustId и след това да редактирам/актуализирам модифицираните CheckBoxListItems на [HttpPost] Edit Действие Метод обратно към моята таблица CustomerDevice в моята база данни, ако е необходимо.

Моля, вижте следния код по-долу, който имам досега.

Модели

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 class Device
{
    public int DevId { get; set; }
    public string DevType { 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; }
}

ViewModels

public class CustomerDeviceFormViewModel
{
    public int CustId { get; set; }
    public string CustDisplayName { get; set; }
    public List<CheckBoxListItem> Devices { get; set; }
}

CustomerDeviceController

public ActionResult Edit(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 = deviceList.Where(x => x.DevId == device.DevId).Any()
        });
    }
    customervm.Devices = checkBoxListItems;
    return View(customervm);
}

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

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

            foreach (var deviceId in vmEdit.Devices.Where(x => x.IsChecked).Select(x => x.ID))
            {
                var customerDevices = new CustomerDevice
                {
                    CustId = vmEdit.CustId,
                    DevId = deviceId
                };

                db.Entry(customerDevices).State = EntityState.Modified;
            }

            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(vmEdit);
    }

Edit.chtml

<div class="form-group">
    Please select the Devices to assign to <b>@Html.DisplayFor(c => c.CustDisplayName)</b>
</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>

Shared/EditorTemplate/CheckBoxListItem.chtml

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


person Brian Brian    schedule 31.10.2016    source източник


Отговори (3)


Вашият код за задаване на стойността IsChecked винаги ще връща true (вашият цикъл основно се казва ако колекцията съдържа мен (което, разбира се, го прави), тогава го задайте на true).

Трябва да получите избраните стойности за всеки Customer, като прочетете стойностите от вашата CustomerDevice таблица

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);
person Community    schedule 31.10.2016
comment
когато копирам/поставя вашето решение, се казва, че ми липсва } expected. Този ред от код IEnumerable<int> selectedDevices = db.CustomerDevices.Where(x => x.CustId == id).Select(x => x.DevId); просто създава ли int масив към променливата selectedDevices? - person Brian Brian; 01.11.2016
comment
Вижте редакцията (2-ри последен ред липсваше ;). И да, selectedDevices е колекция, съдържаща само DevId стойностите - person ; 01.11.2016
comment
Благодаря ти! Получих друго съобщение за грешка, но намерих решението за него. Промених var deviceList = db.Devices; на var deviceList = db.Devices.ToList(); - person Brian Brian; 01.11.2016
comment
Все още ли не работи? (Мога да създам проста цигулка за вас, за да покажа как работи, ако все още имате проблеми) - person ; 01.11.2016
comment
сега работи добре. Просто трябва да разбера [HttpPost] метода на действие за редактиране сега за актуализиране на стойностите на DevId, ако е необходимо. - person Brian Brian; 01.11.2016
comment
След това просто получавате var selected = model.Devices.Where(x => x.IsChecked).Select(x => x.Id); - person ; 01.11.2016
comment
Не съм сигурен дали трябва да добавя var selected = model.Devices.Where(x => x.IsChecked).Select(x => x.Id); в моя [HttpPost] метод за действие за редактиране. Редактирах оригиналната си публикация, за да ви покажа какво имам в момента за моя [HttpPost] метод за действие за редактиране. - person Brian Brian; 01.11.2016
comment
Не, първо трябва да изтриете съществуващите CustomerDevice за клиента и след това да добавите „новите“. Ще актуализирам отговора скоро - person ; 01.11.2016
comment
Добре, благодаря ти много!! Наистина ще съм благодарен да ми помогнете с последната част, когато можете. - person Brian Brian; 01.11.2016
comment
Добавих кода, който предоставихте за POST, но сега получавам съобщение за грешка. В Microsoft.EntityFrameworkCore.dll възникна изключение от тип „System.InvalidOperationException“, но не беше обработено в потребителския код - person Brian Brian; 01.11.2016
comment
Допълнителна информация: Екземплярът от тип обект „CustomerDevice“ не може да бъде проследен, защото друг екземпляр от този тип със същия ключ вече се проследява. - person Brian Brian; 01.11.2016
comment
Когато добавяте нови обекти, за повечето типове ключове ще бъде създадена уникална стойност на временен ключ, ако не е зададен ключ (т.е. ако на свойството на ключа е присвоена стойността по подразбиране за неговия тип). Ако изрично задавате ключови стойности за нови обекти, уверете се, че те не се сблъскват със съществуващи обекти или временни стойности, генерирани за други нови обекти. Когато прикачвате съществуващи обекти, уверете се, че само един екземпляр на обект с дадена стойност на ключ е прикачен към контекста. - person Brian Brian; 01.11.2016
comment
Използвате ли EF6 (имате нужда от това за метода RemoveRange() - в противен случай просто премахнете всеки един в цикъл. И извикайте SaveChanges(), преди да добавите новите - person ; 01.11.2016
comment
Не, използвам Entity Framework Core. Не съм сигурен как да премахна всеки един в цикъл :( Бихте ли ми помогнали с тази последна стъпка, толкова близо. - person Brian Brian; 01.11.2016

Ето фрагмент от кода на Razor, който съм използвал:

   foreach (SelectListItem p in Model.PositionList)
    {
    @Html.Raw(p.Text + "<input type=checkbox name=\"PositionIDs\" id=\"PositionIDs\" value=" + @p.Value + (Model.Positions != null && Model.Positions.Any(pos => pos.ScoreCardId == Convert.ToInt32(p.Value)) ? " checked />" : " />"));
    }
person Duston    schedule 31.10.2016
comment
Мисля, че проблемът ми може да е в CustomerDeviceController, а не в View. - person Brian Brian; 01.11.2016

Може да искате да разгледате пакета MvcCheckBoxList NuGet:

https://www.nuget.org/packages/MvcCheckBoxList/

Това прави правенето на някои мощни неща с CheckBoxList много по-лесно в MVC - и може да бъде по-добър подход за коригиране на вашите проблеми с CheckBox.

person niico    schedule 01.11.2016
comment
Въпреки че тази връзка може да отговори на въпроса, по-добре е да включите основните части от отговора тук и да предоставите връзката за справка. Отговорите само за връзка могат да станат невалидни, ако свързаната страница се промени. - От преглед - person Or Duan; 01.11.2016
comment
@OrDuan Като цяло съм съгласен с вашето мнение и ако имах конкретен код за коригиране на конкретен проблем, щях да го включа. Въпреки това, тъй като това е пакет NuGet, обяснението на пълната му работа в отговора може да е малко прекомерно? - person niico; 01.11.2016
comment
Това няма нищо общо с въпроса на OP, който е за това как правилно да зададете стойностите на квадратчетата за отметка въз основа на данни в базата данни - person ; 02.11.2016
comment
Не съм съгласен - използването на този инструмент може да позволи на OP да направи това по по-добър начин - така разбрах за този пакет и бях благодарен. Това е нещо, за което не мислиш, ако не знаеш за него. Това е алтернативен начин за отстраняване на проблема на OP. - person niico; 02.11.2016
comment
Кодът на OP за генериране на html е наред. Въпросът е как да получите правилните данни от базата данни и използването на различен инструмент за генериране на html не прави абсолютно нищо за решаване на проблема. - person ; 03.11.2016
comment
Как да направя X с Y Знаете ли, че ако използвате Z, е много по-лесно. Този вид отговор промени значително подхода ми към определени проблеми към по-добро в миналото - и мисля, че трябва да бъде насърчаван. Стратегия срещу тактика. Може да помогне на ОП да разреши по-добре проблема си - за което е този сайт. - person niico; 03.11.2016
comment
Това не само е твое мнение, но и не е отговор на въпроса. Ако искате, добавете връзката като коментар, а не в раздела за отговори (който идентификатор за отговорите на въпроса) - person ; 03.11.2016
comment
Всички отговори са мнения. Той отговаря на въпроса, като подхожда към него от различен ъгъл - спецификата не е важна, след като го направите. Колко време ще ми отнеме да шофирам до Аржентина? Мислил ли си да летиш със самолет, не знаех, че това е опция, благодаря. Можете да живеете във вашия земен свят. Харесвам варианта да летя сам. Нека се съгласим да не сме съгласни. - person niico; 03.11.2016