本文参考了Taswar Bhatti的博客,他写了《Instant AutoMapper》这本书。遗憾的是,这本电子版书在国内还买不到,也下载不到。也只能从他的有限几篇博文中来窥探一二了。

本文模拟了一个关于订单的应用场景,涉及到的方面包括:

※ 显示所有订单

※ 显示客户信息

※ 显示订单,但不显示view model OrderDto中的集合导航属性

※ 把源中的DateTime类型转换成int类型

※ 把源中的bool类型转换成string类型

※ 把源中的集合导航属性IEnumerable<OrderItems> LineItems转换成目标中的计算数量的string类型

显示所有订单

□ 思路

从数据库获取Domain model,再转换成View model.

View Model的属性,要方便读取。

Domain model的一些属性、方法是ViewModel不需要的,比如复杂属性Customer,计算总额的方法。

□ Domian model

//订单模型,差不多包含以下方面:

//客户:复杂类型

//下单时间

//一个LineItem的集合

//一个计算总价的方法

//等等

public class Order

{

public string OrderNo{get;set;}

public Customer Customer{get;set;}

public DateTime PurchaseDate{get;set;}

public bool ShipToHomeSddress{get;set;}

public Guid InternalId{get;set;}

public IEnumerable<OrderItems> LineItems{get;set;}

public decimal GetTotal()

{

return LineItems == null ? 0 : LineItems.Sum(x => x.GetTotalPrice());

}

}

//LineItems

//名称、价格、数量,计算每个Line的金额=价格*数量

public class OrderItems

{

public decimal Price{get;set;}

public string Name{get;set;}

public int Quantity{get;set;}

public decimal GetTotalPrice()

{

return Price * Quantity;

}

}

public class Customer

{

public string FirstName{get;set;}

public string LastName{get;set;}

public string Bio{get;set;}

public string GetName()

{

return FirstName + ' ' + LastName;

}

}

□ View model

public class OrderDto

{

public string CustomerName{get;set;} //对应源中复杂属性Customer+Customer的属性,符合惯例

public decimal Total{get;set;} //对应源中GetTotal方法,符合惯例

public string OrderNumber{get;set;} //对应domain model中的OrderNo,需要映射配置

public IEnumerable<OrderItemDto> LineItems{get;set;} //与源中属性保存一致,别忘了OrdeerItemDto需要配置

}

public class OrderItemsDto

{

public string Name{get;set;}

public int Quantity{get;set;}

public decimal Price{get;set;}

}

public class CustomerDto

{

public string Bio{get;set;}

public string Name{get;set;} //与源中的GetName对应

}

□ 控制器

public ActionResult OrderItems()

{

var orders = _repository.GetAll();

Mapper.CreateMap<Order, OrderDto>

.ForMember(dest => dest.OrderNumber, opt => opt.MapFrom(src => src.orderNo));

Mapper.CreateMap<OrderItems, OrderItemsDto>();

var model = Mapper.Map<IEnumerable<Order>, IEnumerable<OrderDto>>(orders);

return View(model);

}

□ 视图

@model IEnumerable<OrderDto>

@foreach(var item in Model)

{

@item.OrderNumber

@item.CustomerName

@item.Total

@foreach(var child in item.LineItems)

{

@string.Format("({0}) {1} - {2}", @child.Quantity, @Child.Name, @Child.Price)<br />

}

}

显示客户信息

□ 思路

假设Domain model Customer的属性Bio有可能是null,如果映射到CustomerDto的Bio属性,也会是null值。

用到了某属性是null的替换方法.NullSubstitute();

□ 控制器

public ActionResult Index()

{

var customers = _repository.GetAll();

AutoMapper.Mapper.CreateMap<Customer, CustomerDto>()

.ForMember(dest => dest.Bio, opt => opt.NullSubstitute("N/A"))

var model = AutoMapper.Mapper.Map<IEnumerable<Customer>, IEnumerable<CustomerDto>>(customers);//集合与集合的映射

return View(model);

}

□ 视图

@model IEnumerable<CustomerDto>

@foreach(var customer in Model)

{

@customer.Name

@Customer.Bio

}

显示订单,但不显示view model OrderDto中的集合导航属性

□ 思路

方法Ignore(),把目标中的某个属性忽略。

□ Domain model

public class Order

{

public string OrderNo { get; set; }

public Customer Customer { get; set;  }

public DateTime PurchaseDate { get; set; }

public IEnumerable<OrderItems> LineItems { get; set; }

public bool ShipToHomeAddress { get; set; }

public decimal GetTotal()

{

return LineItems == null ? 0 : LineItems.Sum(x => x.GetTotalPrice());

}

public Guid InternalId { get; set; }

}

public class OrderItems

{

public decimal Price{get;set;}

public string Name{get;set;}

public int Quantity{get;set;}

public decimal GetTotalPrice()

{

return Price * Quantity;

}

}

□ View model

public class OrderDto

{

public string CustomerName { get; set; } //与源model的导航属性的字段对应

public decimal Total { get; set; } //与源model的GetTotal()方法对应

public string OrderNumber { get; set; }

public IEnumerable<OrderItemsDto> LineItems { get; set; }

}

□ 控制器

public ActionResult Index()

{

var orders = _reposiotry.GetAll();

AutoMapper.Mapper.CreateMap<Order, OrderDto>()

.ForMember(dest => dest.OrderNumber, opt => opt.MapFrom(src => src.OrderNo))

.ForMember(dest => dest.OrderItemsDto, opt => opt.Ignore());//把目标model中的集合导航属性单体忽略

}

□ 视图

@model IEnumerable<OrderDto>

@foreach(var item in Model)

{

@item.OrderNumber

@item.CustomerName

@item.Total()

}

把源中的DateTime类型转换成int类型

□ 思路

要么直接通过MapFrom(src => src.DateTime.Hour)

要么实现IValueFormatter,TypeConverter<,>,ValueResolver<,>

□ Domain model

public class Order

{

public string OrderNo{get;set;}

public Customer Customer {get;set;}

public DateTime PurchaseDate{get;set;} //转换本属性

public IEnumerable<OrderItems> LineItmes{get;set;}

public bool ShipToHomeAddress{get;set;}

public decimal GetTotal()

{

return LineItems == null? : : LineItems.Sum(x => x.GetTotalPrice());

}

public Guid InternalId{get;set;}

}

□ View model

public class OrderDateDto

{

public int PurchaseHour{get;set;}

public int PurchaseMinute{get;set;}

public string CustomerName{get;set;}

}

□ 控制器

public ActionResult OrderDate()

{

var order = _repository.Get(3);

order.PurchaseDate = new DateTime(2011, 3, 15, 20, 30, 0);

Mapper.CreateMap<Order, OrderDateDto>()

.ForMember(dest => dest.PurchaseHour, opt => opt.MapFrom(src => src.PurcahseDate.Hour))

.ForMember(dest => dest.PurcaseMinute, opt => opt.MapFrom(src => src.PurchaseDate.Minute));

var model = Mapper.Map<Order, OrderDateDto>(order);

return View(model);

}

□ 视图

@model OrderDateDto

@Model.CustomerName

@Model.PurchaseHour

@Model.PurchaseMinute

把源中的bool类型转换成string类型

□ Domain model

public class Order

{

public string OrderNo { get; set; }

public Customer Customer { get; set;  }

public DateTime PurchaseDate { get; set; }

public IEnumerable<OrderItems> LineItems { get; set; }

public bool ShipToHomeAddress { get; set; } //转换本属性

public decimal GetTotal()

{

return LineItems == null ? 0 : LineItems.Sum(x => x.GetTotalPrice());

}

public Guid InternalId { get; set; }

}

□ View model

public class OrderShipDto

{

public string ShipHome { get; set; }

public string CustomerName { get; set; }

}

□ 自定义解析器

public class CustomBoolResolver : ValueResolver<Order, string>

{

protected override string ResolveCore(Order source)

{

return source.ShipToHomeAddress? "Yes" : "No";

}

}

控制器

public ActionResult OrderShip()

{

var orders = _repository.GetAll();

Mapper.CreateMap<Order, OrderShipDto>()

.ForMember(dest => dest.ShipHome, opt => opt.ResolveUsing<CustomBoolResolver>());

var model = Mapper.Map<IEnumerable<Order>, IEnumerable<OrderShipDto>>(orders);

return View(model);

}

视图

@item.CustomerName

@item.ShipHome

把源中的集合导航属性IEnumerable<OrderItems> LineItems转换成目标中的计算数量的string类型

□ 思路

对于LineItems同时用到自定义ValueResolver<Order, int>和IValueFormatter。

□ Domain model

public class Order

{

public string OrderNo { get; set; }

public Customer Customer { get; set;  }

public DateTime PurchaseDate { get; set; }

public IEnumerable<OrderItems> LineItems { get; set; }

public bool ShipToHomeAddress { get; set; }

public decimal GetTotal()

{

return LineItems == null ? 0 : LineItems.Sum(x => x.GetTotalPrice());

}

public Guid InternalId { get; set; }

}

□ View model

public class NumberOfOrderDto

{

public string CustomerName { get; set; }

public string NumberOfOrders { get; set; }

}

□ 自定义解析

public class CustomOrderCount : ValueResolver<Order, int>

{

protected override int ResolveCore(Order source)

{

return source.LineItems.Count();

}

}

□ 自定义formatter格式

public class FormatOrderCount : IValueFormatter

{

public string FormatValue(ResolutionContext context)

{

int num = (int).context.SourceValue;

if(num<=1)

return "Number of Order:" + num;

return "Number of Orders:" + num;

}

}

□ 控制器

public ActionResult NumberOfOrders()

{

var orders = _repository.GetAll();

orders.First().LineItems = new List<OrderItems>(); //在order类中的构造函数中没有初始化,所以这里要初始化

Mapper.CreateMap<Order, NumerOfOrderDto>()

.ForMember(dest => dest.NumberOfOrders, opt => {

opt.ResolveUsing<CutomOrderCount>();

opt.AddFormatter<FormatOrderCount>();

})

var model = Mapper.Map<IEnumerable<Order>, IEnumerable<NumberOfOrderDto>>(orders);

return View(model);

}

□ 视图

@model IEnumerable<NumberOfOrderDto>

@foreach(var order in Model)

{

@order.CustomerName

@order.NumberOfOrders

}

AutoMapper在MVC中的运用07-映射在订单场景的例子的更多相关文章

  1. AutoMapper在MVC中的运用04-string映射各种类型、一个属性映射多个属性等

    本篇AutoMapper使用场景: ※ 类型转换,源string类型分别转换成int, DateTime,Type ※ 源和目标都包含复杂类型属性 ※ 把源中的一个属性映射到目标中的多个属性 类型转换 ...

  2. AutoMapper在MVC中的运用01-配置、使用、单元测试、举例

    MVC中,如果想在Domain Model和View Model之间建立映射,用AutoMapper是一个不错的选择.不仅如此,AutoMapper能在不同对象之间建立映射,比如string与int类 ...

  3. AutoMapper在MVC中的运用小结

    配置.单元测试.AOP注入 Decimal转换成String类型 源数组转换成目标数组 源中的集合(数组)属性转换成目标中的集合(数组)属性 子类父类间的映射 源字典集合转换成目标字典集合 枚举映射 ...

  4. AutoMapper在MVC中的运用05-映射中的忽略、处理null、多种映射转换

    本篇AutoMapper使用场景: ※ 动态实现接口方法或属性 ※ 目标中的属性如果比源多,可以忽略多出的属性 ※ 目标有virtual属性,可忽略 ※ 目标属性值为null的解决办法 ※ int转s ...

  5. AutoMapper在MVC中的运用03-字典集合、枚举映射,自定义解析器

    本篇AutoMapper使用场景: ※ 源字典集合转换成目标字典集合 ※ 枚举映射 ※ 自定义解析器 ※ 源中的复杂属性和Get...方法转换成目标属性 源字典集合转换成目标字典集合 □ Domain ...

  6. AutoMapper在MVC中的运用02-Decimal转String、集合、子父类映射

    本篇AutoMapper使用场景: ※ Decimal转换成String类型 ※ 源数组转换成目标数组 ※ 源中的集合(数组)属性转换成目标中的集合(数组)属性 ※ 子类父类间的映射 Decimal转 ...

  7. AutoMapper在MVC中的运用06-一次性定义映射、复杂类型属性映射

    本篇AutoMapper使用场景: ※ 当源和目标具有同名的复杂类型属性.集合类型属性,这2种属性对应的类间也需建立映射 ※ 一次性定义好源和目标的所有映射 ※ 一次性定义好源和目标的所有映射,目标中 ...

  8. MVC中使用EF增删改查,简单的例子

    //这个是分页数据和总页数类 public class SummaryBase<TModel> { public SummaryBase(); public IList<TModel ...

  9. ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下

    ADO.NET   一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data  → DataTable, ...

随机推荐

  1. MySQL灾备恢复在线主从复制变成主主复制及多源复制【转】

    生产主主复制(A<--->B),和灾备主从复制(B--->C).当生产出现问题时,数据写入切换到灾备数据库,待生产恢复后,将灾备回写到生产.步骤如下: 1.灾备与生产其中一台建立主主 ...

  2. 【译】在Asp.Net Core 中使用外部登陆(google、微博...)

    原文出自Rui Figueiredo的博文<External Login Providers in ASP.NET Core> (本文很长) 摘要:本文主要介绍了使用外部登陆提供程序登陆的 ...

  3. Vmware中Linux或macOS客户端如何回收硬盘空间

    Vmware对于Windows的客户端,使用GUI操作硬盘回收和整理磁盘即可.对于Linux或macOS客户端,需要在安装Vmware Tools之后,在客户端OS的终端Terminal里输入命令进行 ...

  4. LeetCode(19):删除链表的倒数第N个节点

    Medium! 题目描述: 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了 ...

  5. java LinkedList(链表)

    LinkedList也像ArrayList一样实现了基本的List接口,但是它执行某些操作(在List的中间插入和移除)时比ArrayList更高效,但在随机访问方面却要逊色一些 LinkedList ...

  6. react 的JSX语法需要注意哪些点?

    注释方式 ReactDOM.render( <div> {/*JSX 中的注释方式*/} </div>, document.getElementById('root') ) j ...

  7. 如何用NAnt管理单文件程序仓库

    因为学习C#各种特性和使用方法的需要,常常会编写和收集一些例子代码.一段时间之后,这种代码的数量就增加到无法通过简单粗暴的方式进行管理了.采用NAnt进行管理是一个不错的选择,虽然部分特性只有MSBu ...

  8. 利用 Vmware 安装 Linux 虚拟机

    之前写过一篇利用MS系的 Hyper-v 安装 Ubuntu 的教程,这里给出使用 Vmware 安装 Linux 的教程.(ps:Hyper-v 的体验感不太好,而且不够大众化) 1.准备工作 1. ...

  9. dojo 加载自定义module的路径问题

    因为最近想学学ArcGIS API for JavaScript ,翻了下ESRI的官网guide,发现其是基于dojo框架的,看了两页实在看不懂,于是先来熟悉下dojo框架.人蠢不能怪社会%> ...

  10. Codeforces 466E Information Graph

    Information Graph 把询问离线之后就能随便搞了, 去check一下是不是祖先, 可以用倍增也能用dfs序. #include<bits/stdc++.h> #define ...