自动映射器可以映射分页列表吗?

问题描述:

我想用这样的业务对象的分页目录映射到视图模型对象的分页列表:自动映射器可以映射分页列表吗?

var listViewModel = _mappingEngine.Map<IPagedList<RequestForQuote>, IPagedList<RequestForQuoteViewModel>>(requestForQuotes); 

的分页列表实现类似于罗布科纳的实现在这里: http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/

如何设置Automapper来执行此操作?

AutoMapper不支持开箱即用,因为它不知道IPagedList<>的任何实现。然而,你有两个选择:

  1. 编写自定义IObjectMapper,利用现有的磁盘阵列/ EnumerableMappers作为指导。这是我个人的方式。

  2. 编写自定义类型转换器,使用:

    Mapper 
        .CreateMap<IPagedList<Foo>, IPagedList<Bar>>() 
        .ConvertUsing<MyCustomTypeConverter>(); 
    

    和内部使用Mapper.Map到列表中的每个元素映射。

+1

有人可以提供一个坚实的'PagedListTypeConverter'实现吗? – 2012-09-12 12:52:09

+2

特洛伊古德的PagedList工作TypeConverter成一个简单的ViewModel可以在这里找到:http://stackoverflow.com/questions/12470156/automapper-custom-type-converter-not-working/12538611#12538611 – 2012-09-21 21:49:05

AutoMapper几种类型的列表和阵列之间自动处理转换: http://automapper.codeplex.com/wikipage?title=Lists%20and%20Arrays

它不会出现自动转换自IList继承名单的自定义类型,但周围的工作可能是:

var pagedListOfRequestForQuote = new PagedList<RequestForQuoteViewModel>(
     AutoMapper.Mapper.Map<List<RequestForQuote>, List<RequestForQuoteViewModel>>(((List<RequestForQuote>)requestForQuotes), 
     page ?? 1, 
     pageSize 
+0

此方法失去'StartRecordIndex','EndRecordIndex','TotalItemCount'和'TotalPageCount'性质。 – 2012-09-12 12:32:51

我在AutoMapper上创建了一个小包装,将PagedList<DomainModel>映射到PagedList<ViewModel>

public class MappingService : IMappingService 
{ 
    public static Func<object, Type, Type, object> AutoMap = (a, b, c) => 
    { 
     throw new InvalidOperationException(
      "The Mapping function must be set on the MappingService class"); 
    }; 

    public PagedList<TDestinationElement> MapToViewModelPagedList<TSourceElement, TDestinationElement>(PagedList<TSourceElement> model) 
    { 
     var mappedList = MapPagedListElements<TSourceElement, TDestinationElement>(model); 
     var index = model.PagerInfo.PageIndex; 
     var pageSize = model.PagerInfo.PageSize; 
     var totalCount = model.PagerInfo.TotalCount; 

     return new PagedList<TDestinationElement>(mappedList, index, pageSize, totalCount); 
    } 

    public object Map<TSource, TDestination>(TSource model) 
    { 
     return AutoMap(model, typeof(TSource), typeof(TDestination)); 
    } 

    public object Map(object source, Type sourceType, Type destinationType) 
    { 
     if (source is IPagedList) 
     { 
      throw new NotSupportedException(
       "Parameter source of type IPagedList is not supported. Please use MapToViewModelPagedList instead"); 
     } 

     if (source is IEnumerable) 
     { 
      IEnumerable<object> input = ((IEnumerable)source).OfType<object>(); 
      Array a = Array.CreateInstance(destinationType.GetElementType(), input.Count()); 

      int index = 0; 
      foreach (object data in input) 
      { 
       a.SetValue(AutoMap(data, data.GetType(), destinationType.GetElementType()), index); 
       index++; 
      } 
      return a; 
     } 

     return AutoMap(source, sourceType, destinationType); 
    } 

    private static IEnumerable<TDestinationElement> MapPagedListElements<TSourceElement, TDestinationElement>(IEnumerable<TSourceElement> model) 
    { 
     return model.Select(element => AutoMap(element, typeof(TSourceElement), typeof(TDestinationElement))).OfType<TDestinationElement>(); 
    } 
} 

用法:

PagedList<Article> pagedlist = repository.GetPagedList(page, pageSize); 
mappingService.MapToViewModelPagedList<Article, ArticleViewModel>(pagedList); 

它,你将不得不使用元素类型是很重要的!

如果您有任何问题或建议,请随时发表评论:)

如果您使用Troy Goode's PageList,有一个StaticPagedList类,它可以帮助你进行映射。

// get your original paged list 
IPagedList<Foo> pagedFoos = _repository.GetFoos(pageNumber, pageSize); 
// map to IEnumerable 
IEnumerable<Bar> bars = Mapper.Map<IEnumerable<Bar>>(pagedFoos); 
// create an instance of StaticPagedList with the mapped IEnumerable and original IPagedList metadata 
IPagedList<Bar> pagedBars = new StaticPagedList<Bar>(bars, pagedFoos.GetMetaData()); 

使用jrummell的回答,我创建了以Troy Goode's PagedList工作的扩展方法。它使你不必到处放这么多的代码...

public static IPagedList<TDestination> ToMappedPagedList<TSource, TDestination>(this IPagedList<TSource> list) 
    { 
     IEnumerable<TDestination> sourceList = Mapper.Map<IEnumerable<TSource>, IEnumerable<TDestination>>(list); 
     IPagedList<TDestination> pagedResult = new StaticPagedList<TDestination>(sourceList, list.GetMetaData()); 
     return pagedResult; 

    } 

用法为:

var pagedDepartments = database.Departments.OrderBy(orderBy).ToPagedList(pageNumber, pageSize).ToMappedPagedList<Department, DepartmentViewModel>(); 
+0

这节省了我很多写作。 – 2012-09-19 14:47:18

+0

这对我有用! – Ryan 2012-11-25 02:31:38

+0

当你想让AutoMapper忽略的字段时,这将如何工作? – Ciwan 2014-02-19 13:40:19

我需要返回IPagedList<>与AutoMapper版本6.0.2序列化的版本,支持IMapper ASP.NET Web API的接口。因此,如果这个问题是我怎么支持以下内容:

//Mapping from an enumerable of "foo" to a different enumerable of "bar"... 
var listViewModel = _mappingEngine.Map<IPagedList<RequestForQuote>, PagedViewModel<RequestForQuoteViewModel>>(requestForQuotes); 

那么可以这样做:

定义PagedViewModel<T>
来源:AutoMapper Custom Type Converter not working

public class PagedViewModel<T> 
{ 
    public int FirstItemOnPage { get; set; } 
    public bool HasNextPage { get; set; } 
    public bool HasPreviousPage { get; set; } 
    public bool IsFirstPage { get; set; } 
    public bool IsLastPage { get; set; } 
    public int LastItemOnPage { get; set; } 
    public int PageCount { get; set; } 
    public int PageNumber { get; set; } 
    public int PageSize { get; set; } 
    public int TotalItemCount { get; set; } 
    public IEnumerable<T> Subset { get; set; } 
} 

写打开通用转换器从IPagedList<T>PagedViewModel<T>
来源:https://github.com/AutoMapper/AutoMapper/wiki/Open-Generics

public class Converter<TSource, TDestination> : ITypeConverter<IPagedList<TSource>, PagedViewModel<TDestination>> 
{ 
    public PagedViewModel<TDestination> Convert(IPagedList<TSource> source, PagedViewModel<TDestination> destination, ResolutionContext context) 
    { 
     return new PagedViewModel<TDestination>() 
     { 
      FirstItemOnPage = source.FirstItemOnPage, 
      HasNextPage = source.HasNextPage, 
      HasPreviousPage = source.HasPreviousPage, 
      IsFirstPage = source.IsFirstPage, 
      IsLastPage = source.IsLastPage, 
      LastItemOnPage = source.LastItemOnPage, 
      PageCount = source.PageCount, 
      PageNumber = source.PageNumber, 
      PageSize = source.PageSize, 
      TotalItemCount = source.TotalItemCount, 
      Subset = context.Mapper.Map<IEnumerable<TSource>, IEnumerable<TDestination>>(source) //User mapper to go from "foo" to "bar" 
     }; 
    } 
} 

配置映射器

new MapperConfiguration(cfg => 
    { 
     cfg.CreateMap<RequestForQuote, RequestForQuoteViewModel>();//Define each object you need to map 
     cfg.CreateMap(typeof(IPagedList<>), typeof(PagedViewModel<>)).ConvertUsing(typeof(Converter<,>)); //Define open generic mapping 
    });