如何在POST操作中将视图模型映射回域模型?

互联网上使用ViewModel和利用Automapper的每篇文章都给出了“Controller – > View”方向映射的指导原则。 您将域模型和所有select列表一起放入一个专门的ViewModel中,并将其传递给视图。 这很清楚,很好。
该视图有一个表单,最终我们在POST操作中。 在这里,所有的模型绑定器都与[明显]另一个 View模型一起出现,它至less在命名约定的部分中与原始ViewModel 明显相关,以便进行绑定和validation。

你如何将其映射到你的域模型?

让它成为插入动作,我们可以使用相同的Automapper。 但是,如果这是更新行为呢? 我们必须从Repository检索我们的Domain Entity,根据ViewModel中的值更新它的属性并保存到Repository中。

附录1(2010年2月9日):有时,分配模型的属性是不够的。 根据视图模型的值,应该对域模型采取一些行动。 也就是说,应该在域模型上调用一些方法。 可能应该有一种应用程序服务层,站在控制器和域之间来处理视图模型…


如何组织这个代码,并把它放在哪里来实现以下目标?

  • 保持控制器很薄
  • 尊重SoC的实践
  • 遵循域驱动devise原则
  • 是干的
  • 未完待续 …

我使用IBuilder接口并使用ValueInjecter实现它

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

…(实现) RebuildViewModel只是调用BuildViewModel(BuilEntity(viewModel))

 [HttpPost] public ActionResult Update(ViewModel model) { if(!ModelState.IsValid) { return View(builder.RebuildViewModel(model); } service.SaveOrUpdate(builder.BuildEntity(model)); return RedirectToAction("Index"); } 

顺便说一句,我不写ViewModel我写inputcuz它短得多,但这并不重要
希望能帮助到你

更新:我现在在ProDinner的ASP.net MVC演示应用程序中使用这种方法,现在叫做IMapper,还提供了这个方法的详细解释

像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数据查看模型+validation是在ModelBinder中完成的(可以使用自定义绑定进行parsing)
  • error handling(即通过Repository捕获数据访问exception抛出)可以通过[HandleError]filter完成

控制器操作非常简单,关注点是分开的:映射问题在AutoMapperconfiguration中解决,validation由ModelBinder完成,通过Repository进行数据访问。

我想说,你重复使用术语ViewModel在客户端交互的两个方向。 如果你已经阅读了足够的ASP.NET MVC代码,你可能已经看到了ViewModel和EditModel之间的区别。 我认为这很重要。

ViewModel表示呈现视图所需的所有信息。 这可能包括在静态非交互式场所中呈现的数据,以及纯粹用于执行检查以确定究竟要呈现的数据的数据。 控制器GET操作通常负责为其视图打包ViewModel。

一个EditModel(或者一个ActionModel)表示执行用户想要为该POST执行的操作所需的数据。 所以一个EditModel实际上是试图描述一个动作。 这可能会排除ViewModel中的一些数据,虽然相关,但我认为认识到它们的确有所不同是很重要的。

一个想法

也就是说,你可以非常容易地从Model – > ViewModel进行AutoMapperconfiguration,而从EditModel – > Model进行configuration。 那么不同的Controller动作只需要使用AutoMapper。 地狱的EditModel可以有一个function,以validation其模型的属性,并将这些值应用到模型本身。 它没有做任何其他的事情,你有MVC ModelBinders无论如何映射请求到EditModel。

另一个想法

除此之外,我最近一直在思考的是,ActionModel的理念是,客户向你发布的内容实际上是对用户执行的几个操作的描述,而不仅仅是一个大的数据。 这肯定会需要一些JavaScript的客户端pipe理,但这个想法是有趣的,我认为。

本质上,当用户在屏幕上执行操作时,Javascript会开始创build一个操作对象列表。 一个例子是用户可能在员工信息屏幕上。 他们更新姓氏,并添加一个新地址,因为员工最近已经结婚了。 在封面下面,这产生一个ChangeEmployeeName和一个AddEmployeeMailingAddress对象到列表。 用户点击“保存”提交更改,并提交两个对象的列表,每个对象只包含执行每个操作所需的信息。

您将需要一个更智能的ModelBinder,然后默认的一个,但良好的JSON序列化程序应该能够照顾客户端操作对象到服务器端的映射。 服务器端的(如果你在一个2层环境中的话)可以很容易地完成在他们使用的模型上完成操作的方法。 因此,Controller动作最终只是获取Model实例的Id以及要执行的动作列表。 或者这些行为在他们身上存在着使他们非常分离的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 } 

这真的使回发行动相当通用,因为你依靠你的ModelBinder来让你正确的IUserAction实例和你的IUserAction实例来执行正确的逻辑本身或(更可能)与信息调用模型。

如果您处于三层环境中,则可以将IUserAction设置为简单的DTO,以跨越边界进行拍摄,并在应用层以类似的方式执行。 根据你如何做这一层,它可以很容易地分裂,仍然留在交易(想到的是阿加莎的要求/反应,并利用DI和NHibernate的身份地图)。

无论如何,我确定这不是一个完美的想法,这将需要在客户端的一些JS来pipe理,我还没有能够做一个项目,但看看它是如何展开的,但这个职位正在试图思考如何到那里再回来,所以我想我会给我的想法。 我希望它有帮助,我很乐意听到其他方式来pipe理互动。

您不需要将viewmodel映射到域,因为您的viewmodel可能比domain模型创build的多。 Viewmodels针对屏幕(ui)进行了优化,与领域模型不同。

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

Interesting Posts