简体   繁体   English

Automapper map 可以分页列表吗?

[英]Can Automapper map a paged list?

I'd like to map a paged list of business objects to a paged list of view model objects using something like this:我想 map 业务对象的分页列表到视图 model 对象的分页列表,使用如下:

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

The paged list implementation is similar to Rob Conery's implementation here: http://blog.wekeroad.com/2007/12/10/as.net-mvc-pagedlistt/分页列表实现类似于 Rob Conery 在这里的实现: http://blog.wekeroad.com/2007/12/10/as.net-mvc-pagedlistt/

How can you setup Automapper to do this?您如何设置 Automapper 来执行此操作?

Using jrummell's answer, I created an extension method that works with Troy Goode's PagedList . 使用jrummell的答案,我创建了一个与Troy Goode的PagedList一起使用的扩展方法。 It keeps you from having to put so much code everywhere... 它让你不必在任何地方放置如此多的代码......

    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;

    }

Usage is: 用法是:

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

AutoMapper does not support this out of the box, as it doesn't know about any implementation of IPagedList<> . AutoMapper不支持开箱即用,因为它不知道IPagedList<>任何实现。 You do however have a couple of options: 但是你有两个选择:

  1. Write a custom IObjectMapper , using the existing Array/EnumerableMappers as a guide. 使用现有的Array / EnumerableMappers作为指南编写自定义IObjectMapper This is the way I would go personally. 这是我亲自去的方式。

  2. Write a custom TypeConverter, using: 编写自定义TypeConverter,使用:

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

    and inside use Mapper.Map to map each element of the list. 并在里面使用Mapper.Map来映射列表的每个元素。

If you're using Troy Goode's PageList , there's a StaticPagedList class that can help you map. 如果你正在使用Troy Goode的 StaticPagedList ,那么有一个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());

I created a little wrapper around AutoMapper to map PagedList<DomainModel> to PagedList<ViewModel> . 我在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>();
    }
}

Usage: 用法:

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

It is important that you would have to use the element types! 重要的是你必须使用元素类型!

If you have any question or suggestions, please feel free to comment :) 如果您有任何问题或建议,请随时评论:)

AutoMapper automatically handles conversions between several types of lists and arrays: http://automapper.codeplex.com/wikipage?title=Lists%20and%20Arrays AutoMapper自动处理几种类型的列表和数组之间的转换: http ://automapper.codeplex.com/wikipage?title = List%20and%20Arrays

It doesn't appear to automatically convert custom types of lists inherited from IList, but a work around could be: 它似乎不会自动转换从IList继承的自定义类型的列表,但解决方法可能是:

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

I needed to return a serializable version of IPagedList<> with AutoMapper version 6.0.2 that supports the IMapper interface for ASP.NET Web API. 我需要使用支持ASP.NET Web API的IMapper接口的AutoMapper版本6.0.2返回可序列化版本的IPagedList<> So, if the question was how do I support the following: 那么,如果问题是我如何支持以下内容:

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

Then one could do this: 然后人们可以这样做:

Define PagedViewModel<T> 定义PagedViewModel<T>
Source: AutoMapper Custom Type Converter not working 来源: AutoMapper自定义类型转换器无法正常工作

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; }
}

Write open generic converter from IPagedList<T> to PagedViewModel<T> 将开放式通用转换器从IPagedList<T>写入PagedViewModel<T>
Source: https://github.com/AutoMapper/AutoMapper/wiki/Open-Generics 资料来源: 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"
        };
    }
}

Configure mapper 配置映射器

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
    });

It is easy with Automapper .net core 8.1.1 Automapper .net core 8.1.1 很容易

You just need to add type map to your mapperProfile and mapping the object inside pagedList您只需要将类型映射添加到您的 mapperProfile 并映射 pagedList 内的对象

CreateMap(typeof(IPagedList<>), typeof(IPagedList<>));
CreateMap<RequestForQuote, RequestForQuoteViewModel>().ReverseMap();

and you can use it directly in mapper.Map - Initialize mapper from IMapper in the class constructor并且您可以直接在 mapper.Map 中使用它 - 在类构造函数中从 IMapper 初始化映射器

RequestForQuote result
_mapper.Map<IPagedList<RequestForQuoteViewModel>>(result);

If you are using X.PageList then you can simply use this code:如果您正在使用 X.PageList 那么您可以简单地使用此代码:

PagedList<exampleDTO> result = new PagedList<exampleDTO>(item, _mapper.Map<List<exampleDTO>>(item.ToList()));

The PageList lets you to create new PageList with modified items. PageList 允许您使用修改后的项目创建新的 PageList。

more information 更多信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM