2010-01-15 15 views
18

vorrei mappare una lista paginata di oggetti di business a un elenco di paging di oggetti vista del modello utilizzando qualcosa di simile:Può l'Automapper mappare un elenco a pagine?

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

L'implementazione lista paging è simile alla realizzazione di Rob Conery qui: http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/

Come si può impostare Automapper per farlo?

risposta

12

AutoMapper non supporta questo fuori dalla scatola, in quanto non conosce alcuna implementazione di IPagedList<>. Dovete comunque un paio di opzioni:

  1. Scrivi una consuetudine IObjectMapper, utilizzando la matrice esistente/EnumerableMappers come guida. Questo è il modo in cui andrei personalmente.

  2. Scrivi una TypeConverter personalizzato, utilizzando:

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

    e dentro uso Mapper.Map per mappare ogni elemento della lista.

+1

Qualcuno può fornire un'implementazione solida di 'PagedListTypeConverter'? –

+2

Un TypeConverter funzionante per la PagedList di Troy Goode in un semplice ViewModel può essere trovato qui: http://stackoverflow.com/questions/12470156/automapper-custom-type-converter-not-working/12538611#12538611 –

0

automapper gestisce automaticamente le conversioni tra diversi tipi di liste e array: http://automapper.codeplex.com/wikipage?title=Lists%20and%20Arrays

Non sembra per convertire automaticamente i tipi personalizzati di liste ereditate da IList, ma un lavoro intorno potrebbe essere:

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

Questo metodo perde 'StartRecordIndex',' EndRecordIndex', 'e' TotalItemCount' proprietà TotalPageCount'. –

1

ho creato un piccolo wrapper automapper per mappare PagedList<DomainModel> a 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); 

E 'importante che si dovrebbe usare l'elemento tipi!

Se avete qualche domanda o suggerimento, non esitate a lasciare un commento :)

6

Se stai usando Troy Goode's PageList, c'è una classe StaticPagedList che può aiutare a mappare.

// 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

Utilizzando la risposta di jrummell, ho creato un metodo di estensione che funziona con Troy Goode's PagedList. Esso ti impedisce di dover mettere così tanto codice ovunque ...

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; 

    } 

L'uso è:

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

Questo mi ha salvato molto di scrivere. –

+0

Questo ha funzionato per me! – Ryan

+0

Come funzionerebbe quando hai campi che vuoi che AutoMapper ignori? – Ciwan

0

avevo bisogno di restituire una versione serializzabile di IPagedList<> con automapper versione 6.0.2 che supporta il IMapper interfaccia per API Web ASP.NET.Quindi, se la domanda era come faccio a supportare quanto segue:

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

Poi si potrebbe fare questo:

Definire PagedViewModel<T>
Fonte: 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; } 
} 

Write aprire il convertitore generico da IPagedList<T> a PagedViewModel<T>
Fonte: 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" 
     }; 
    } 
} 

Configura 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 
    }); 
Problemi correlati