Asp.net mvc 3 复杂视图上的自动映射(多重循环)
今天早些时候,一位乐于助人的人(这里是Stack Overflow)向我指出,我查看了它,我非常喜欢它!但是现在我有点被卡住了 在我的代码第一个MVC3应用程序中,在我的[Home/Index]上,我需要显示来自实体的以下信息:Asp.net mvc 3 复杂视图上的自动映射(多重循环),asp.net-mvc-3,entity-framework-4.1,ef-code-first,automapper,Asp.net Mvc 3,Entity Framework 4.1,Ef Code First,Automapper,今天早些时候,一位乐于助人的人(这里是Stack Overflow)向我指出,我查看了它,我非常喜欢它!但是现在我有点被卡住了 在我的代码第一个MVC3应用程序中,在我的[Home/Index]上,我需要显示来自实体的以下信息: 帖子列表[int-Id,string-Body,int-Likes,string p.User.FirstName,string p.User.LastName] 标记列表[整数Id,字符串名称] 我的数据库中存在的所有作者的列表[string UrlFriendlyN
public class IndexVM
{
public int Id { get; set; }
public string Body { get; set; }
public int Likes { get; set; }
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
}
在Home Controller上,我有索引ActionMethod:
public ActionResult Index()
{
var Posts = postsRepository.Posts.ToList();
Mapper.CreateMap<Post, IndexVM>();
var IndexModel = Mapper.Map<List<Post>, List<IndexVM>>(Posts);
return View(IndexModel);
}
我的问题是,我如何既能达到第2点和第3点,又不打破第1点的成绩
我尝试将目前用于IndexVM的内容放入一个子类,并在父类上具有List属性,但没有成功。来自ASP.NET MVC2 In Action手册: 有些屏幕比单个表更复杂。它们可能具有 多个表和其他数据的附加字段:图像、标题、, 小计,图表,图表,以及其他让事情复杂化的东西 景色。表示模型解决方案可以扩展以处理所有这些问题。 开发人员可以自信地维护最粗糙的屏幕,只要 因为演示模型设计得很好。如果屏幕确实包含 多个复杂元素,表示模型可以是包装器, 将它们全部组合起来并减轻标记文件的复杂性。A. 好的表示模型并不会掩盖这种复杂性,它代表了这种复杂性 准确且尽可能简单,它可以在 从显示屏上选择屏幕 制作一个表示屏幕的ViewModel。然后构建它并将其传递给视图。这本书很好,它谈到了如何使用演示模型。使用AutoMapper,想想没有它您将如何完成映射,然后利用它。AutoMapper不会做任何魔术,它消除了键盘敲击 将AutoMapper放在一边,列出您的需求:
Public class IndexVM
{
Public List<PostDisplay> Posts {get; set;}
Public List<TagDisplay> Tags {get; set;}
Public List<AuthorDisplay> Authors {get; set;}
}
公共类IndexVM
{
公共列表发布{get;set;}
公共列表标记{get;set;}
公共列表作者{get;set;}
}
在这种情况下,视图的组成方式将要求您构建它:
public ActionResult Index()
{
var posts = postsRepository.Posts.ToList();
var tags = postsRepository.Tags.ToList();
var authors = postsRepository.Authors.ToList();
Mapper.CreateMap<Post, PostDisplay>();
Mapper.CreateMap<Tag, TagDisplay>();
Mapper.CreateMap<Author, AuthorDisplay>();
private var IndexVM = new IndexVM
{
Posts = Mapper.Map<List<Post>, List<PostDisplay>>(posts),
Tags = Mapper.Map<List<Tag>, List<TagDisplay>>(tags),
Authors = Mapper.Map<List<Author>, List<AuthorDisplay>>(authors)
};
return View(IndexVM);
}
public ActionResult Index()
{
var posts=postsRepository.posts.ToList();
var tags=postsRepository.tags.ToList();
var authors=postsRepository.authors.ToList();
CreateMap();
CreateMap();
CreateMap();
私有变量IndexVM=新的IndexVM
{
Posts=Mapper.Map(Posts),
Tags=Mapper.Map(标记),
Authors=Mapper.Map(作者)
};
返回视图(IndexVM);
}
因此,您最终得到的是一个要传递到视图的ViewModel,它准确地表示您想要显示的内容,并且不与域模型紧密耦合。我想不出让AutoMapper将三个单独的结果列表映射到一个对象的方法
为了澄清这一点,AutoMapper将映射子集合,使其具有如下结构:
public class OrderItemDto{}
public class OrderDto
{
public List<OrderItemDto> OrderItems { get; set; }
}
公共类OrderItemDto{}
公共类OrderDto
{
公共列表OrderItems{get;set;}
}
将映射到:
public class OrderItem{}
public class Order
{
public List<OrderItem> OrderItems { get; set; }
}
公共类OrderItem{}
公共阶级秩序
{
公共列表OrderItems{get;set;}
}
只要您告诉它如何映射类型:OrderDto->Order和OrderItemDto->OrderItem。作为在单个viewmodel中包含所有实体列表的替代方法,您可以使用@Html.Action。然后,在屏幕视图中:
@Html.Action("Index", "Posts")
@Html.Action("Index", "Tags")
@Html.Action("Index", "Authors")
这样,您的索引/屏幕视图和模型就不需要了解其他视图模型。部分由单独的子操作方法在单独的控制器上传递
所有automapper的内容仍然适用,但您仍然可以将实体单独映射到viewmodels。不同之处在于,您可以在PostsController.Index()、TagsController.Index()和AuthorsController.Index()中进行映射,而不是在HomeController.Index()中进行映射
对评论1的回应
public class IndexVM
{
// need not implement anything for Posts, Tags, or Authors
}
然后,在3个不同的控制器上实现3种不同的方法。下面是PostsController的一个示例。对于TagsController和AuthorsController,请遵循相同的模式
// on PostsController
public PartialViewResult Index()
{
var posts = postsRepository.Posts.ToList();
// as mentioned, should do this in bootstrapper, not action method
Mapper.CreateMap<Post, PostModel>();
// automapper2 doesn't need source type in generic args
var postModels = Mapper.Map<List<PostModel>>(posts);
return PartialView(postModels);
}
在IndexVM上保持视图的强类型
@model IEnumerable<BlogWeb.ViewModels.IndexVM>
对评论2的回应
自举。。。您的Mapper.CreateMap配置只需在每个应用程序域中进行一次。这意味着您应该从应用程序开始执行所有CreateMap调用。将它们放在控制器代码中只会产生不必要的开销。当然,需要创建映射,但不是在每个请求期间
这也有助于单元测试。如果将所有Mapper.CreateMap调用放在一个静态方法中,则可以从单元测试方法以及Global.asax应用程序_Start调用该方法。然后在单元测试中,有一种方法可以测试CreateMap调用是否设置正确:
AutoMapperBootStrapper.CreateAllMaps();
Mapper.AssertConfigurationIsValid();
谢谢你的回复,德里克。我已经照你的建议去做了。但我现在不知道如何继续与汽车制造商。我如何告诉AutoMapper以我的ViewModel现在的方式进行操作?谢谢,还有,看看这本书,它有一个很好的章节是关于演示模型的。只是想让你知道,我不小心投了反对票,而不是投了赞成票。
public ActionResult Index()
{
return View(new IndexVM);
}
@model IEnumerable<BlogWeb.ViewModels.IndexVM>
@Html.Action("Index", "Posts")
AutoMapperBootStrapper.CreateAllMaps();
Mapper.AssertConfigurationIsValid();