4

У меня проблема с привязкой к модели в моем приложении ASP.NET MVC 2 RC, которое использует NHibernate для доступа к данным. Мы пытаемся создать приложение в Ruby on Rails и иметь очень простую архитектуру, где объекты домена используются полностью из базы данных в представлении.Связывание модели ASP.NET MVC 2 с NHibernate и выпадающими списками

Приложение имеет несколько сущностей доменов, которые могут быть проиллюстрированы следующими двумя классами:

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 

Это делает много смысла, так как продукт уже имеет назначенную категорию и только первичный ключ этой существующей категории изменяется. Вместо этого должен быть назначен другой экземпляр категории.

Я думаю, пользовательский ModelBinder может быть создан для решения этой проблемы, но есть ли более простой способ сделать эту работу? Могут (и должны) объекты домена быть изменены, чтобы справиться с этим?

+0

Вы нашли решение этой проблемы? У меня точно такая же проблема. – nabeelfarid

+0

Нет, я так и не нашел хорошего решения (однако мы не потратили много времени на его поиск). Мы обработали проблему явно за пределами связующего. – HakonB

+0

Не могли бы вы дать мне какой-то намек на то, как вы справляетесь с этим за пределами связующего. Вы вообще не используете TryUpdateModel/UpdateModel? – nabeelfarid

ответ

0

Решение, которое мы выбрали в то время было что-то похожее на это:

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; 
} 

Мы просто сказать модель связующего, чтобы исключить свойство ассоциации и обрабатывать это вручную. Не очень, но работал в то время ....

0

Я уже использовал подобные методы с классами Linq to SQL без проблем. Я не думаю, что для этого вам понадобится специальный ModelBinder. UpdateModel должен обновлять класс продукта, в который вы переходите, а не подкласс класса, прикрепленный к нему. Проверьте html, сгенерированный помощником DropDownListFor. Как называется элемент? Это должно быть имя поля внешнего ключа в вашей таблице продуктов (например, «CategoryID» или «Product.CategoryID», а не «Category.Id»). Если это «Category.Id» - попробуйте изменить первый параметр DropDownListFor на «model => model.Category» или «model => model.CategoryID» (или независимо от поля внешнего ключа). Это должно заставить UpdateModel обновлять поле внешнего ключа в классе Product, а не идентификатор класса категории.

+1

Внешний ключ недоступен, так как отношения полностью обрабатываются NHibernate. В итоге я просто обрабатывал случай категории вручную и не создавал настраиваемое связующее устройство – HakonB

2

я решил аналогичную проблему с полей со списком на моей странице редактирования, изменив следующую строку

@Html.DropDownListFor(x => x.Employee.Id, new SelectList(ViewBag.Employees, "Id", "DisplayName")) 

по

@Html.DropDownListFor(x => x.Employee, new SelectList(ViewBag.Employees, "Id", "DisplayName")) 

Так что я удалил «.Id», как предложил Брайан.Перед изменением модель содержала только идентификатор сотрудника, и после изменения Binder также загрузил все детали сотрудника в модель.

Смежные вопросы