AutoMapper在MVC中的运用07-映射在订单场景的例子
本文参考了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-映射在订单场景的例子的更多相关文章
- AutoMapper在MVC中的运用04-string映射各种类型、一个属性映射多个属性等
本篇AutoMapper使用场景: ※ 类型转换,源string类型分别转换成int, DateTime,Type ※ 源和目标都包含复杂类型属性 ※ 把源中的一个属性映射到目标中的多个属性 类型转换 ...
- AutoMapper在MVC中的运用01-配置、使用、单元测试、举例
MVC中,如果想在Domain Model和View Model之间建立映射,用AutoMapper是一个不错的选择.不仅如此,AutoMapper能在不同对象之间建立映射,比如string与int类 ...
- AutoMapper在MVC中的运用小结
配置.单元测试.AOP注入 Decimal转换成String类型 源数组转换成目标数组 源中的集合(数组)属性转换成目标中的集合(数组)属性 子类父类间的映射 源字典集合转换成目标字典集合 枚举映射 ...
- AutoMapper在MVC中的运用05-映射中的忽略、处理null、多种映射转换
本篇AutoMapper使用场景: ※ 动态实现接口方法或属性 ※ 目标中的属性如果比源多,可以忽略多出的属性 ※ 目标有virtual属性,可忽略 ※ 目标属性值为null的解决办法 ※ int转s ...
- AutoMapper在MVC中的运用03-字典集合、枚举映射,自定义解析器
本篇AutoMapper使用场景: ※ 源字典集合转换成目标字典集合 ※ 枚举映射 ※ 自定义解析器 ※ 源中的复杂属性和Get...方法转换成目标属性 源字典集合转换成目标字典集合 □ Domain ...
- AutoMapper在MVC中的运用02-Decimal转String、集合、子父类映射
本篇AutoMapper使用场景: ※ Decimal转换成String类型 ※ 源数组转换成目标数组 ※ 源中的集合(数组)属性转换成目标中的集合(数组)属性 ※ 子类父类间的映射 Decimal转 ...
- AutoMapper在MVC中的运用06-一次性定义映射、复杂类型属性映射
本篇AutoMapper使用场景: ※ 当源和目标具有同名的复杂类型属性.集合类型属性,这2种属性对应的类间也需建立映射 ※ 一次性定义好源和目标的所有映射 ※ 一次性定义好源和目标的所有映射,目标中 ...
- MVC中使用EF增删改查,简单的例子
//这个是分页数据和总页数类 public class SummaryBase<TModel> { public SummaryBase(); public IList<TModel ...
- 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, ...
随机推荐
- arm GIC介绍之四【转】
转自:https://blog.csdn.net/sunsissy/article/details/73882718 GIC是ARM体系中重要的组件,在认识到GIC的组成和功能之后,了解到IRQ的大致 ...
- 深入了解mitmproxy(二)
主题 修改request或者response内容 介绍 mitmdump无交互界面的命令,与python脚本对接,来源于mitmproxy支持inline script,这里的script指 ...
- 拓展中国剩余定理(exCRT)摘要
清除一个误区 虽然中国剩余定理和拓展中国剩余定理只差两个字,但他俩的解法相差十万八千里,所以会不会CRT无所谓 用途 求类似$$\begin{cases}x \equiv b_{1}\pmod{a_{ ...
- React-Native 之 TabBarIOS
前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...
- Coursera台大机器学习技法课程笔记15-Matrix Factorization
很多ML模型用的都是数值特征,那么对于分类特征,该怎么做呢? 以linear network为例:先对特征进行转换,转换成有意义的特征后,再对其进行线性组合 进一步,模型可表示为:使Ein最小,我们就 ...
- SVN服务器搭建和使用-转载
SVN服务器搭建和使用(一)-转载 原文地址:http://www.cnblogs.com/xiaobaihome/archive/2012/03/20/2407610.html Subversion ...
- 用 scikit-learn 和 pandas 学习线性回归
用 scikit-learn 和 pandas 学习线性回归¶ from https://www.cnblogs.com/pinard/p/6016029.html 就算是简单的算法,也需要跑通整 ...
- 【LOJ】#2264. 「CTSC2017」吉夫特
题解 根据一番认真严肃的猜结论和打表证明之后 我们可以得到 \(f[i] = (\sum_{a[i] \& a[j] == a[j]} f[j]) + 1\) 统计所有的\(f[i] - 1\ ...
- python 包详解
包 包是一种管理 Python 模块命名空间的形式,采用"点模块名称". 比如一个模块的名称是 A.B, 那么他表示一个包 A中的子模块 B . 就好像使用模块的时候,你不用担心不 ...
- H5地理位置定位
一:介绍使用的知识点 1.地理定位的原理 2.geolocation对象 3.Geolocation Api 4.getCurrentPosition的第一个参数 5.getCurrentPositi ...