我在这里读过http://lostechies.com/jimmybogard/2009/09/18/the-case-for-two-way-mapping-in-automapper/关于你可能不应该试图取消展平一个展平的对象,但考虑到我如何使用带有实体框架的存储库,应该是实体模型,而不是ViewModels。
我开始怀疑我是否应该采取不同的方法,有人对这类事情有任何最佳实践吗?或者是时候开始使用ValueInjector using AutoMapper来取消对DTO的渲染了吗?并且不太关心将RecipeCreateViewModel映射回Recipe?
下面是我的代码,让你了解我目前的情况。
// Entities
public class Recipe {
public int Id { get; set; }
public string Name { get; set; }
public Course Course { get; set; }
}
public class Course {
public int Id { get; set; }
public string Name { get; set; }
}
// View Model
public class RecipeCreateViewModel {
// Recipe properties
public int Id { get; set; }
public string Name { get; set; }
// Course properties, as primitives via AutoMapper
[Required]
public int CourseId { get; set; }
// Don't need CourseName in the viewmodel but it should probably be set in Recipe.Course.Name
//public string CourseName { get; set; }
// For a drop down list of courses
public SelectList CourseList { get; set; }
}
// Part of my View
@model EatRateShare.WebUI.ViewModels.RecipeCreateViewModel
...
<div class="editor-label">
Course
</div>
<div class="editor-field">
@* The first param for DropDownListFor will make sure the relevant property is selected *@
@Html.DropDownListFor(model => model.CourseId, Model.CourseList, "Choose...")
@Html.ValidationMessageFor(model => model.CourseId)
</div>
...
// Controller actions
public ActionResult Create() {
// map the Recipe to its View Model
var recipeCreateViewModel = Mapper.Map<Recipe, RecipeCreateViewModel>(new Recipe());
recipeCreateViewModel.CourseList = new SelectList(courseRepository.All, "Id", "Name");
return View(recipeCreateViewModel);
}
[HttpPost]
public ActionResult Create(RecipeCreateViewModel recipe) {
if (ModelState.IsValid) {
// set the course name based on the id that was posted
// not currently checking if the repository doesn't find anything.
recipe.CourseName = courseRepository.Find(recipe.CourseId).Name;
var recipeEntity = Mapper.Map<RecipeCreateViewModel, Recipe>(recipe);
recipeRepository.InsertOrUpdate(recipeEntity);
recipeRepository.Save();
return RedirectToAction("Index");
} else {
recipe.CourseList = new SelectList(courseRepository.All, "Id", "Name");
return View(recipe);
}
}
如果你遵循"自然"(非常主观)流,它就像这个
要创建域模型
ViewModel->映射器->域实体->存储库->映射器->Persistence实体
要显示更新视图模型
持久性实体->映射器->ViewModel
在第一种情况下,您将dto处理为域实体(应用业务规则等),然后将其发送到以特定方式持久化的存储库(EF实体)
在第二种情况下,您希望加载一个视图模型(DTO),该视图模型将用于更新域模型。您不是直接从存储库中重新加载整个域实体,然后将其映射到DTO。
你可能会说这种情况不适用于你,因为你直接针对EF工作。好吧,这就是诀窍,领域模型!=持久性模型!=视图模型。他们都是不同的,有不同的关注点。
因此,通过适当的分离,您将始终拥有:视图模型->映射->域实体->映射->持久性实体,而方向相反:持久性实体->映射->视图模型