2010-01-15 14 views
18

Je voudrais mapper une liste paginée d'objets d'affaires à une liste paginée des objets du modèle de vue en utilisant quelque chose comme ceci:Est-ce que Automapper peut mapper une liste paginée?

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

La mise en œuvre de la liste paginée est similaire à la mise en œuvre de Rob Conery ici: http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/

Comment configurer Automapper pour cela?

Répondre

12

AutoMapper ne prend pas en charge ce hors de la boîte, car il ne connaît aucune implémentation de IPagedList<>. Vous avez toutefois deux options:

  1. Ecrire une coutume IObjectMapper, en utilisant le tableau existant/EnumerableMappers comme guide. C'est ainsi que j'irais personnellement.

  2. Ecrire un TypeConverter personnalisé, en utilisant:

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

    et à l'intérieur de l'utilisation Mapper.Map carte chaque élément de la liste.

+1

Quelqu'un peut-il fournir une solide mise en œuvre 'PagedListTypeConverter'? –

+2

Un TypeConverter travaillant pour PagedList de Troy Goode dans un simple ViewModel peut être trouvé ici: http://stackoverflow.com/questions/12470156/automapper-custom-type-converter-not-working/12538611#12538611 –

0

AutoMapper gère automatiquement les conversions entre plusieurs types de listes et les tableaux: http://automapper.codeplex.com/wikipage?title=Lists%20and%20Arrays

Il ne semble pas convertir automatiquement les types personnalisés de listes héritées de IList, mais un travail pourrait autour être:

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

Cette méthode perd les propriétés 'StartRecordIndex',' 'EndRecordIndex', TotalItemCount' et' TotalPageCount'. –

1

J'ai créé un petit wrapper autour AutoMapper à la carte 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>(); 
    } 
} 

Utilisation:

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

Il est important que vous devez utiliser l'élément types!

Si vous avez des questions ou suggestions, s'il vous plaît ne hésitez pas à commenter :)

6

Si vous utilisez Troy Goode's PageList, il y a une classe StaticPagedList qui peut vous aider à tracer.

// 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()); 
31

En utilisant la réponse de jrummell, je créé une méthode d'extension qui fonctionne avec Troy Goode's PagedList. Il vous évite d'avoir à mettre tellement de code partout ...

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; 

    } 

Utilisation est:

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

Cela m'a sauvé beaucoup De l'écriture. –

+0

Cela a fonctionné pour moi! – Ryan

+0

Comment cela fonctionnerait quand vous avez des champs que vous souhaitez AutoMapper ignorer? – Ciwan

0

je devais retourner une version sérialisable de IPagedList<> avec la version 6.0.2 AutoMapper qui prend en charge la IMapper interface pour l'API Web ASP.NET.Donc, si la question était de savoir comment puis-je soutenir:

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

Alors on pourrait faire:

Définir PagedViewModel<T>
Source: 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; } 
} 

Ecrire convertisseur générique ouvert de IPagedList<T> à PagedViewModel<T>
Source: 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" 
     }; 
    } 
} 

Configurer mappeur

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