zoukankan      html  css  js  c++  java
  • 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

    }

  • 相关阅读:
    access数据库
    备份
    本机测试三级域名
    xp共享
    An error occurred on the server when processing the URL解决方法
    GridView导出Excel研究
    SQL触发器实例讲解1
    谈不上喜悦,算得上疲劳作战
    架构讨论
    梦——软件问题最终用硬件方式解决——跳出思维怪圈(原创)
  • 原文地址:https://www.cnblogs.com/darrenji/p/3570495.html
Copyright © 2011-2022 走看看