[asp.net-mvc] POST 작업에서 뷰 모델을 도메인 모델에 다시 매핑하는 방법은 무엇입니까?

ViewModels 및 Automapper 사용에 대한 인터넷에서 찾은 모든 기사는 “Controller-> View”방향 매핑의 지침을 제공합니다. 모든 선택 목록과 함께 도메인 모델을 하나의 특수한 ViewModel로 가져 와서보기에 전달합니다. 명확하고 괜찮습니다.
보기에는 양식이 있으며 결국 POST 작업에 있습니다. 여기서 모든 Model Binder 는 바인딩 및 유효성 검사를위한 명명 규칙의 일부에서 원래 ViewModel 과 [분명히] 관련된 다른 View Model 과 함께 [분명히] 장면에 표시됩니다 .

도메인 모델에 어떻게 매핑합니까?

삽입 작업으로합시다. 동일한 Automapper를 사용할 수 있습니다. 하지만 업데이트 작업이라면 어떨까요? 리포지토리에서 도메인 엔터티를 검색하고 ViewModel의 값에 따라 속성을 업데이트하고 리포지토리에 저장해야합니다.

부록 1 (2010 년 2 월 9 일) : 때때로 모델의 속성을 할당하는 것만으로는 충분하지 않습니다. View Model의 값에 따라 Domain Model에 대한 조치를 취해야합니다. 즉, 도메인 모델에서 일부 메서드를 호출해야합니다. 아마도 뷰 모델을 처리하기 위해 컨트롤러와 도메인 사이에있는 일종의 애플리케이션 서비스 계층이 있어야합니다.


이 코드를 구성하는 방법과 다음 목표를 달성하기 위해 어디에 배치해야합니까?

  • 컨트롤러를 얇게 유지
  • SoC 관행을 존중
  • 도메인 기반 설계 원칙을 따릅니다.
  • 건조하다
  • 계속하려면 …



답변

나는 사용 IBuilder의 인터페이스를하고 사용하여 구현 ValueInjecter을

public interface IBuilder<TEntity, TViewModel>
{
      TEntity BuildEntity(TViewModel viewModel);
      TViewModel BuildViewModel(TEntity entity);
      TViewModel RebuildViewModel(TViewModel viewModel);
}

… (구현) RebuildViewModelBuildViewModel(BuilEntity(viewModel))

[HttpPost]
public ActionResult Update(ViewModel model)
{
   if(!ModelState.IsValid)
    {
       return View(builder.RebuildViewModel(model);
    }

   service.SaveOrUpdate(builder.BuildEntity(model));
   return RedirectToAction("Index");
}

btw 나는 ViewModel을 쓰지 않습니다. 입력은 훨씬 짧기 때문에 작성하지만
도움이되기를 바랍니다.

업데이트 :
현재 ProDinner ASP.net MVC 데모 앱 에서이 접근 방식을 사용하고 있습니다. 이제 IMapper 라고합니다.이 접근 방식을 자세히 설명하는 pdf도 제공됩니다.


답변

AutoMapper와 같은 도구를 사용하여 원본 개체의 데이터로 기존 개체를 업데이트 할 수 있습니다. 업데이트를위한 컨트롤러 작업은 다음과 같습니다.

[HttpPost]
public ActionResult Update(MyViewModel viewModel)
{
    MyDataModel dataModel = this.DataRepository.GetMyData(viewModel.Id);
    Mapper<MyViewModel, MyDataModel>(viewModel, dataModel);
    this.Repostitory.SaveMyData(dataModel);
    return View(viewModel);
}

위의 스 니펫에서 볼 수있는 것과는 별개로 :

  • 모델을보기위한 POST 데이터 + 유효성 검사는 ModelBinder에서 수행됩니다 (사용자 지정 바인딩으로 확장 가능).
  • 오류 처리 (예 : 저장소에서 발생하는 데이터 액세스 예외 포착)는 [HandleError] 필터로 수행 할 수 있습니다.

컨트롤러 작업은 매우 얇고 우려 사항이 분리되어 있습니다. 매핑 문제는 AutoMapper 구성에서 해결되고 유효성 검사는 ModelBinder에서 수행되며 데이터 액세스는 Repository에서 수행됩니다.


답변

클라이언트 상호 작용의 양방향에 대해 ViewModel이라는 용어를 재사용한다고 말하고 싶습니다. 야생에서 충분한 ASP.NET MVC 코드를 읽었다면 ViewModel과 EditModel의 차이를 보았을 것입니다. 중요하다고 생각합니다.

ViewModel은 뷰를 렌더링하는 데 필요한 모든 정보를 나타냅니다. 여기에는 정적 비대화 형 장소에서 렌더링되는 데이터와 정확히 렌더링 할 항목을 결정하기위한 검사를 수행하기위한 데이터가 포함될 수 있습니다. 컨트롤러 GET 작업은 일반적으로 해당 뷰에 대한 ViewModel 패키징을 담당합니다.

EditModel (또는 ActionModel)은 사용자가 해당 POST에 대해 수행하려는 작업을 수행하는 데 필요한 데이터를 나타냅니다. 따라서 EditModel은 실제로 액션을 설명하려고합니다. 이것은 아마도 ViewModel에서 일부 데이터를 제외시킬 것이며 관련이 있지만 실제로 다르다는 것을 깨닫는 것이 중요하다고 생각합니다.

하나의 아이디어

즉, Model-> ViewModel에서 이동하는 AutoMapper 구성과 EditModel-> Model에서 이동할 다른 구성을 매우 쉽게 가질 수 있습니다. 그런 다음 다른 컨트롤러 작업은 AutoMapper를 사용하기 만하면됩니다. EditModel은 모델에 대한 속성의 유효성을 검사하고 해당 값을 모델 자체에 적용하는 기능을 가질 수 있습니다. 다른 작업을 수행하지 않고 MVC에 ModelBinders가있어 어쨌든 요청을 EditModel에 매핑합니다.

또 다른 아이디어

그 외에도 최근에 제가 생각했던 ActionModel의 아이디어에서 이런 종류의 작업은 클라이언트가 다시 게시하는 것은 실제로 사용자가 수행 한 여러 작업에 대한 설명이며 하나의 큰 데이터 덩어리가 아니라는 것입니다. 이것은 확실히 관리하기 위해 클라이언트 측에 일부 Javascript가 필요하지만 아이디어가 흥미 롭다고 생각합니다.

기본적으로 사용자가 제시 한 화면에서 작업을 수행 할 때 Javascript는 작업 개체 목록을 만들기 시작합니다. 예를 들어 사용자가 직원 정보 화면에있을 수 있습니다. 직원이 최근에 결혼했기 때문에 성을 업데이트하고 새 주소를 추가합니다. 내부적으로 이것은 목록에 a ChangeEmployeeNameAddEmployeeMailingAddress객체를 생성 합니다. 사용자가 ‘저장’을 클릭하여 변경 사항을 커밋하고 각 작업을 수행하는 데 필요한 정보 만 포함 된 두 개체 목록을 제출합니다.

더 지능적인 ModelBinder가 필요하지만, 좋은 JSON 시리얼 라이저는 클라이언트 측 작업 개체와 서버 측 작업 개체의 매핑을 처리 할 수 ​​있어야합니다. 서버 측 (2 계층 환경에있는 경우)은 작업하는 모델에서 작업을 완료 한 메서드를 쉽게 가질 수 있습니다. 따라서 컨트롤러 작업은 모델 인스턴스가 가져올 Id와 이에 대해 수행 할 작업 목록을 얻습니다. 또는 행동에 이드가있어 매우 분리되어 있습니다.

따라서 아마도 다음과 같은 것이 서버 측에서 실현 될 수 있습니다.

public interface IUserAction<TModel>
{
     long ModelId { get; set; }
     IEnumerable<string> Validate(TModel model);
     void Complete(TModel model);
}

[Transaction] //just assuming some sort of 2-tier with transactions handled by filter
public ActionResult Save(IEnumerable<IUserAction<Employee>> actions)
{
     var errors = new List<string>();
     foreach( var action in actions )
     {
         // relying on ORM's identity map to prevent multiple database hits
         var employee = _employeeRepository.Get(action.ModelId);
         errors.AddRange(action.Validate(employee));
     }

     // handle error cases possibly rendering view with them

     foreach( var action in editModel.UserActions )
     {
         var employee = _employeeRepository.Get(action.ModelId);
         action.Complete(employee);
         // against relying on ORMs ability to properly generate SQL and batch changes
         _employeeRepository.Update(employee);
     }

     // render the success view
}

올바른 논리 자체를 수행하거나 정보를 사용하여 모델을 호출하기 위해 올바른 IUserAction 인스턴스와 IUserAction 인스턴스를 얻기 위해 ModelBinder에 의존하고 있기 때문에 게시 작업을 상당히 일반적으로 만듭니다.

3 계층 환경에있는 경우 IUserAction은 경계를 가로 질러 촬영하고 앱 계층에서 유사한 방법으로 수행 할 간단한 DTO로 만들 수 있습니다. 해당 레이어를 수행하는 방법에 따라 매우 쉽게 분할되어 트랜잭션에 남아있을 수 있습니다 (Agatha의 요청 / 응답과 DI 및 NHibernate의 ID 맵을 활용하는 것입니다).

어쨌든 완벽한 아이디어는 아니라고 확신합니다. 관리하려면 클라이언트 측에서 JS가 필요하고 아직 프로젝트가 어떻게 진행되는지 확인하기 위해 프로젝트를 수행 할 수 없었지만 게시물은 방법에 대해 생각하려고했습니다. 거기에 다시 돌아와서 나는 내 생각을 줄 것이라고 생각했습니다. 도움이 되었기를 바라며 상호 작용을 관리하는 다른 방법에 대해 듣고 싶습니다.


답변

viewmodel이 도메인 모델보다 많이 생성 될 수 있으므로 viewmodel을 도메인에 매핑 할 필요가 없습니다. 화면 (UI)에 최적화되어 있고 도메인 모델과 다른 뷰 모델.

http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/


답변