asp.net MVC 2 RC 모델 바인딩 NHibernate 및 드롭 다운 목록
-
20-09-2019 - |
문제
데이터 액세스에 nhibernate를 사용하는 ASP.NET MVC 2 RC 응용 프로그램에서 모델 바인딩에 문제가 있습니다. 우리는 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 Transaction Handling을 추가하고 예외가 발생하지 않고 유효성 검사가 성공하면 트랜잭션을 위반합니다.
[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가 양식 (예 : 범주)에서 선택한 값으로 설정되어 있다는 것입니다. 기본 모델 바인더를 사용하면 다음 유형의 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'를 제거했습니다. 변경 전에 모델에는 직원의 ID 만 포함되었으며 변경 후 바인더는 직원의 모든 세부 사항을 모델에로드했습니다.
문제없이 LINQ에서 SQL 클래스와 유사한 기술을 사용했습니다. 나는 당신이 이것을 위해 사용자 정의 모델 바인더가 필요하다고 생각하지 않습니다. UpdateModel은 첨부 된 카테고리 하위 클래스가 아닌 제품 클래스를 업데이트해야합니다. DropdownListfor 헬퍼로 생성 된 HTML을 점검하십시오. 요소의 이름은 무엇입니까? 제품 테이블 (예 : "CategoryId"또는 "Product.categoryId"Not "Category.Id")의 외국 키 필드의 이름이어야합니다. "category.id"인 경우 - DropdownListfor의 첫 번째 매개 변수를 "model => model.category"또는 "model => model.categoryId"(또는 외국 키 필드가 무엇이든)로 변경하십시오. 이로 인해 UpdateModel은 카테고리 클래스 ID가 아닌 제품 클래스에서 외국 키 필드 만 업데이트해야합니다.