在ASP.NET MVC项目中,我们使用AutoMapper从域模型映射到viewmodel - 有时也会在执行此操作时展平层次结构。这就像一个魅力,使我们的观点的渲染逻辑非常精简和简单。
当我们想要从viewmodel(或postmodel或editmodel)转向域模型,,特别是在更新对象时时,会出现混淆。我们不能使用自动/双向映射,因为:
ChangeManagerForEmployee()
”或类似方法。Jimmy Bogards的文章The case for two-way mapping in AutoMapper中也对此进行了描述,但对此的解决方案没有详细描述,只是说明了:
从EditModel到CommandMessages - 来自松散类型 EditModel为强类型,分解的消息。一个EditModel 可能会生成六条消息。
在类似的SO question中,Mark Seeman有一个答案,他提到了
我们使用抽象映射器和服务将PostModel映射到域对象
但遗漏了细节 - 概念和技术实施。
我们现在的想法是:
UpdateModel()
有人可以提供一些示例,说明它们如何从FormCollection通过editmodel / postmodel进入域模型吗? “CommandMessages”或“抽象映射器和服务”?
答案 0 :(得分:2)
我使用以下模式:
[HttpPost]
public ActionResult Update(UpdateProductViewModel viewModel)
{
// fetch the domain model that we want to update
Product product = repository.Get(viewModel.Id);
// Use AutoMapper to update only the properties of this domain model
// that are also part of the view model and leave the other properties unchanged
AutoMapper.Map<UpdateProductViewModel, Product>(viewModel, product);
// Pass the domain model with updated properties to the DAL
repository.Update(product);
return RedirectToAction("Success");
}
答案 1 :(得分:1)
您可能需要考虑CQRS(命令查询责任隔离 - 我认为这可能是您缺少的概念),甚至可能使用事件采购。
基本上是将读取逻辑与数据源分离并写入数据源的做法,甚至可能意味着有不同的数据模型进行读写。
这可能是一个很好的起点:http://abdullin.com/cqrs/
答案 2 :(得分:0)
选项C:将所有内容都放在控制器操作中。接下来,如果它变得多毛,则分解为服务(抽象映射器)或消息作为方法(命令消息方式)。
命令消息方式:
public ActionResult Save(FooSaveModel model) {
MessageBroker.Process(model);
return RedirectToAction("List");
}
处理器:
public class FooSaveModelProcessor : IMessageHandler<FooSaveModel> {
public void Process(FooSaveModel message) {
// Message handling logic here
}
}
这实际上只是将表单的“处理”移出控制器操作并转移到单独的专用处理程序中。
但是,如果控制器动作变得多毛,我只会真正走这条路。否则,只需获取表单并根据需要对域模型进行适当的更新。
答案 3 :(得分:0)
这与我一直在做的事情有一些相似之处。我的视图模型的层次结构只是从它的域对象等价物中稍微扁平化了,但是我必须处理在保存时调用显式服务方法来做一些事情,比如添加到子集合,更改重要值等,而不是简单地反向映射。我还必须在快照之前和之后进行比较。
我的保存是将Ajax作为JSON发布到MVC操作,并将该操作神奇地绑定回MVC的视图模型结构。然后,我使用AutoMapper将顶级视图模型及其后代转换回其等效的域结构。我为客户端添加了新子项(我使用Knockout.js)并且需要调用显式服务方法的情况定义了许多自定义AutoMapper ITypeConverters。类似的东西:
foreach (ChildViewModel childVM in viewModel.Children)
{
ChildDomainObject childDO = domainObject.Children.Where(cdo => cdo.ID.Equals(childVM.ID))).SingleOrDefault();
if (childDO != null)
{
Mapper.Map<ChildViewModel, ChildDomainObject>(childVM, childDO);
}
else
{
MyService.CreateChildDO(someData, domainObject); // Supplying parent
}
}
我对删除做了类似的事情,这个过程在整个结构中很好地级联。我想平面结构可能更容易使用或更难 - 我有一个带有ID的AbstractDomainViewModel,我可以使用它进行上述匹配,这有助于。
我需要在更新之前和之后进行比较,因为我的服务层调用触发器验证,这会影响对象图的其他部分,这就决定了我需要返回的JSON作为Ajax响应。我只关心与UI相关的更改,因此我将保存的域对象转换回新的视图模型,然后使用辅助方法比较2个视图模型,使用手动前期检查和反射的组合。