19

我想使用视图模型来显示域模型。我想自定义一个显示属性,我应该怎么做?使用 AutoMapper 进行显示是一个好习惯吗?

下面是代码示例:

public class BookController : BaseController
    {
        private IBookService bookService;

        public BookController(IBookService bookService)
        {
            this.bookService = bookService;
        }

        public ActionResult Details(int id)
        {
            var book = bookService.GetBookById(id);

            return View(Mapper.Map<BookView>(book));
        }
}

    public class Book 
    {        
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }

    public class BookView
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

如果我使用另一种方式,我可以自定义任何属性,如下所示:

  public ActionResult Details(int id)
        {
            var book = bookService.GetBookById(id);

            return View(new BookView(book));
        }

    public class BookView
    {
       public BookView(Book book){
         Name = book.Name +" Decorated";
       }
        public int Id { get; set; }
        public string Name { get; set; }
    }

我该怎么做?使用 AutoMapper 进行显示是一个好习惯吗?

更新

在下面的场景中使用 automapper 似乎更合适。例如,将视图模型映射到域模型,如下所示。有什么意见吗?

  [HttpPost]
    public ActionResult Create(BookView bookView)
    {
        try
        {
            var book = Mapper.Map<Book>(bookView);  //this is wrong

            bookService.SaveOrUpdate(book);

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

更新 2

对于通过视图模型进行的复杂自定义显示,我不想使用 automapper 来映射显示逻辑,假设 automapper 可以映射它。因为它混合了不同的目的。例如:

Mapper.CreateMap<Book, BookView>()
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name + " this is for display purpose"));

但是,使用如下所示的手动映射似乎很直观。

 public BookView(Book book){
    //mapping here
}

更新 3

引用Jimmy Bogard的话:

我认为使用 AutoMapper 因为您不想使用“=”运算符有点懒惰。相反,我们使用它来展平和重塑,优化目标类型的环境。请记住,我最初使用 AutoMapper 的动机是:

通过映射到 DTO 来保护域层免受其他层的影响

感谢@AndrewWhitaker 的链接

4

1 回答 1

22

这是 AutoMapper 的一个很好的用例(我已经在许多成功的项目中广泛使用它)。通常,您不想将域实体暴露给您的视图(在 MVC 中,这会将您的模型直接暴露给您的视图,这是不正确的)。

您不需要域实体和视图模型之间的 1-1 映射。您可以使它们看起来完全不同,并在您的CreateMap<>通话中自定义映射。要使用您的示例:

Mapper.CreateMap<Book, BookView>()
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name + " Decorated"));

最坏的情况,您可以放弃 automapper 处理复杂的情况,或者使用带有 automapper 的自定义类型解析器来完成工作。

事实上这就是 Jimmy Bogard(作者)推荐使用 AutoMapper 的方式。他特别提到了从域实体到 ASP.NET MVC ViewModels 的映射,以便与强类型视图一起使用。

另一个优点是您可以对映射配置文件进行单元测试。这样,如果最终 ViewModel 和 Model 不匹配,您将获得失败的单元测试。

更新:

我认为您添加到问题中的引用进一步支持使用 AutoMapper 从域模型映射到 ViewModel:

相反,我们使用它来展平和重塑,优化目标类型的环境。

因此,在我的示例中,您肯定会针对目标类型的环境(在本例中为视图)进行优化。

同样根据我上面引用的链接,您应该使用 automapper 映射域,只能. 考虑到这一点,无论如何,您都必须编写一些逻辑来根据从视图中收到的内容创建/更新域实体。请记住,控制器操作不应直接采用域实体(您不应信任直接来自视图的数据——让模型确定域实体是否有效)。

于 2013-05-13T18:47:50.527 回答