Связывание модели MVC 2 RC с Nhibernate и раскрывающимися списками
-
20-09-2019 - |
Вопрос
У меня есть проблемы с привязкой модели в моем приложении ASP.NET MVC 2 RC, которое использует NHIBERNATE для доступа к данным. Мы пытаемся построить приложение в Ruby on Rails Way и имеем очень простую архитектуру, где доменные объекты используются вплоть от базы данных до представления.
Приложение имеет пару доменных объектов, которые могут быть проиллюстрированы следующими двумя классами:
public class Product {
...
public Category Category { get; set; }
}
public class Category {
public int Id { get; set; }
public string Name { get; set; }
}
В представлении о том, что форма редактирования имеет следующий оператор для отображения раскрывающегося списка:
<%= Html.DropDownListFor(model => model.Category.Id,
new SelectList(ViewData["categories"] as IList<Category>, "Id", "Name"),
"-- Select Category --" ) %>
Пожалуйста, не обращайте внимания на использование данных «непреднамеренного» для просмотра для сохранения сбора категорий.
Метод действия, который получает сообщение формы, аналогичен следующему. Обратите внимание, что атрибут TransactionFilter добавляет обработку транзакций nhibernate и совершает транзакцию, если никаких исключений не происходит, и проверка достигает успеха.
[HttpPost]
[TransactionFilter]
public ActionResult Edit(int id, FormCollection collection) {
var product = _repository.Load(id);
// Update the product except the Id
UpdateModel(product, null, null, new[] {"Id"}, collection);
if (ModelState.IsValid) {
return RedirectToAction("Details", new {id});
}
return View(product);
}
Моя проблема заключается в том, что product.category.id устанавливается со значением, выбранным в форме, например, Category.id = "2". Использование связующего модели по умолчанию приводит к следующему типу исключения nhibernate:
identifier of an instance of Name.Space.Entities.Category was altered from 4 to 2
Это имеет большой смысл, так как продукт уже имеет категорию, и только основной ключ этой существующей категории изменяется. Другой экземпляр категории должен был быть назначен вместо этого.
Я предполагаю, что пользовательский модель может быть создан для решения этой проблемы, но есть ли более простой способ сделать эту работу? Могут ли (и должны) быть изменены доменные объекты, чтобы справиться с этим?
Решение 3
Решение, которое мы выбрали в то время, было что -то похожее на это:
TryUpdateModel(product, null, null, new[] {"Category"}, collection);
int categoryId;
if (int.TryParse(collection["Category.Id"], NumberStyles.Integer, CultureInfo.InvariantCulture, out categoryId) && categoryId > 0) {
product.Category = _categoryRepository.Load(categoryId);
}
else {
product.Category = null;
}
Мы просто говорим модели связующего, чтобы исключить свойство ассоциации и обрабатывать это вручную. Не красиво, но работал в то время ....
Другие советы
Я решил аналогичную проблему с коробками со спиками на моей странице редактирования, изменив следующую строку
@Html.DropDownListFor(x => x.Employee.Id, new SelectList(ViewBag.Employees, "Id", "DisplayName"))
по
@Html.DropDownListFor(x => x.Employee, new SelectList(ViewBag.Employees, "Id", "DisplayName"))
Поэтому я удалил «.id», как предложил Брайан. Перед изменением модель содержала только удостоверение личности сотрудника, и после изменения переплет также загрузил все детали сотрудника в модель.
Я использовал аналогичные методы с классами LINQ для SQL, прежде чем без проблем. Я не думаю, что вам понадобится пользовательский модельный бинд для этого. UpdateModel должен обновлять класс продукта, который вы передаете в него, - не подключенный к нему категорию подкласс. Проверьте HTML, сгенерированный вспомогательным вспомогательным. Как называется элемент? Это должно быть название поля иностранного ключа в вашей таблице продуктов (например, «Категория» или «Product.categoryid», а не "Category.id"). Если это "category.id" - попробуйте изменить первый параметр DropdownList для либо "model => model.category", либо "model => model.categoryid" (или каким -либо полем иностранного ключа). Это должно привести к тому, что UpdateModel обновляется только поле иностранного ключа в классе продукта, а не идентификатор класса категории.