ASP.NET MVC Редактировать значения CheckBoxList в базе данных

У меня возникли проблемы с пониманием того, как получить и отредактировать значения DevId из моей таблицы CustomerDevice в моей базе данных в CheckBoxList на основе значения CustId.

Метод My Index Action для CustomerDeviceController отображает список клиентов из моей таблицы Customers. У меня есть ActionLink с пометкой «Изменить», который передает значение CustId методу действия CustomerDeviceController [HttpGet] Edit(int? id), который в настоящее время отображает все значения CheckBoxListItem из таблицы «Устройства». Однако 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; }
}

Модели просмотра

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

Контроллер устройств клиента

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] Edit Action Method. - person Brian Brian; 01.11.2016
comment
Нет, сначала нужно удалить существующие CustomerDevice для клиента, а затем добавить «новые». Я обновлю ответ в ближайшее время - person ; 01.11.2016
comment
Хорошо, большое спасибо!! Я был бы очень признателен, если бы вы помогли мне с последней частью, когда сможете. - person Brian Brian; 01.11.2016
comment
Я добавил код, который вы предоставили для POST, но теперь я получаю сообщение об ошибке. Исключение типа «System.InvalidOperationException» возникло в Microsoft.EntityFrameworkCore.dll, но не было обработано в пользовательском коде - 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, а не в представлении. - person Brian Brian; 01.11.2016

Возможно, вы захотите взглянуть на пакет NuGet MvcCheckBoxList:

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
Это не имеет ничего общего с вопросом ОП о том, как правильно установить значения флажков на основе данных в базе данных. - person ; 02.11.2016
comment
Я не согласен - использование этого инструмента может позволить ОП сделать это лучше - именно так я узнал об этом пакете и был благодарен. Это то, о чем вы не думаете, если вы не знаете об этом. Это альтернативный способ решить проблему ОП. - person niico; 02.11.2016
comment
Код OP для генерации html в порядке. Вопрос в том, как получить правильные данные из базы данных, и использование другого инструмента для генерации html абсолютно не решает проблему. - person ; 03.11.2016
comment
Как мне сделать X с Y Знаете ли вы, что если вы используете Z, это намного проще. Такой ответ сильно изменил мой подход к некоторым проблемам в лучшую сторону в прошлом, и я думаю, что его следует поощрять. Стратегия против тактики. Это может помочь ОП лучше решить их проблему - для этого и предназначен этот сайт. - person niico; 03.11.2016
comment
Это не только ваше мнение, но и не ответ на вопрос. Если хотите, добавьте ссылку как комментарий, а не в раздел ответов (какой id для ответов на вопрос) - person ; 03.11.2016
comment
Все ответы являются мнениями. Он отвечает на вопрос, подходя к нему под другим углом — когда вы это делаете, подробности не важны. Сколько времени мне потребуется, чтобы доехать до Аргентины? Вы думали о полете? Я не знал, что это вариант, спасибо. Вы можете жить в своем наземном мире. Мне нравится вариант полета самому. Давайте согласимся не согласиться. - person niico; 03.11.2016