9

Sto provando a utilizzare le proiezioni di Automapper su IQueryables di Entity Framework.Automapper 4.2.1 Le proiezioni LINQ funzionano solo con static Mapper.CreateMap?

All'avvio dell'applicazione, creo e aggiungo tutti i miei profili di mappatura che creano mappe con il metodo CreateMap non statico.

Tutti questi profili sono registrati nel mio contenitore IoC.

Ottengo l'eccezione di mappatura mancante anche se vedo il profilo di mappatura nell'istanza del mio mappingConfiguration.

Quale potrebbe essere il problema? Mi sto perdendo qualcosa? Sto usando Automapper 4.2.1

Ho notato che quando si aggiunge un Mapper.CreateMap statico, funziona bene. Le proiezioni funzionano solo con l'API statica? Voglio evitare l'API statica.

codice completo:

public class ItemEntityToItemView : Profile 
{ 
    public override void Configure() 
    { 
     CreateMap<ItemEntity, ItemView>(); 

     // Without this line, I get missing Map type configuration. 
     Mapper.CreateMap<ItemEntity, ItemView>(); 
    } 
} 


public interface IEntitiesProjector 
{ 
    IQueryable<T> SelectTo<T>(IQueryable source); 
} 

public class EntitiesProjector : IEntitiesProjector 
{ 
    private readonly IMapperConfiguration _mapperConfig; 

    public EntitiesProject(IMapperConfiguration mapperConfig) 
    { 
     _mapperConfig = mapperConfig; 
    } 

    public IQueryable<T> SelectTo<T>(IQueryable source) 
    { 
     return source.ProjectTo<T>(_mapperConfig); 
    } 
} 

public class ItemsRepository : IITemsRepository 
{ 
    public IQueryable<ItemEntity> GetById(int id) 
    { 
     return _dbSet.Where(x => x.Id == id); 
    } 
} 

public class Service 
{ 
    private readonly IEntitiesProjector _projector; 

    public Service(IEntitiesProject entitiesProjector) 
    { 
     _projector = entitiesProjector; 
    } 

    public List<T> GetItem(int id) 
    { 
     IQueryable<ItemEntity> itemsQueryable = ItemsRepository.GetById(id); 

     return _projector.SelectTo<ItemView>(itemsQueryable); 
    } 
} 

My Autofac registration : 

builder.RegisterAssemblyTypes().AssignableTo(typeof(Profile)).As<Profile>(); 

builder.Register(c => new MapperConfiguration(cfg => 
{ 
    cfg.CreateMap<IdentityUser, AspNetUser>().ReverseMap(); 
})).AsSelf().As<IMapperConfiguration>().SingleInstance(); 

builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)).As<IMapper>().InstancePerLifetimeScope(); 

builder.Register<EntitiesProjector>().As<IEntitiesProjector>().SingleInstance(); 
+0

inserisci il tuo codice campione –

+0

Aggiunto il mio profilo .. si suppone che funzioni? O è noto che le proiezioni funzionano solo quando si utilizza l'API statica? –

+0

Quando uso 'ProjectTo()', devo aggiungere un parametro di tipo generico e fornire una configurazione del mapper come parametro. Ne hai di più nel tuo codice di domanda molto incompleto. Btw: Sto usando 'utilizzando AutoMapper.QueryableExtensions;' per ottenere le mie estensioni di sovraccarico 'ProjectTo' – grek40

risposta

10

La ragione è la seguente blocco:

public class EntitiesProjector : IEntitiesProjector 
{ 
    private readonly IMapperConfiguration _mapperConfig; 

    public EntitiesProject(IMapperConfiguration mapperConfig) 
    { 
     _mapperConfig = mapperConfig; 
    } 

    public IQueryable<T> SelectTo<T>(IQueryable source) 
    { 
     return source.ProjectTo<T>(_mapperConfig); 
    } 
} 

source.ProjectTo è un metodo di estensione che ha 5 sovraccarichi. Nella documentazione passano l'istanza della classe MappingConfiguration e si passa all'istanza di IMapperConfiguration (interfaccia). Pensi che avrà lo stesso effetto, ma non lo fa. L'interfaccia IMapperConfiguration non implementa l'interfaccia IConfigurationProvider e quello (IConfigurationProvider) è il tipo di sovraccarico corretto di ProjectTo accettato. Ma, c'è un altro sovraccarico di ProjectTo, che accetta "object parameters". Perché accetta oggetti - abbinerà tutto ciò che non si adatta ad altri sovraccarichi. Quindi quello che stai veramente chiamando è il sovraccarico ProjectTo(object), che non ha nulla a che fare con la configurazione, e il tuo IMapperConfiguration insieme ai profili e alle mappe è completamente ignorato.

Quickfix sarà

public class EntitiesProjector : IEntitiesProjector 
{ 
    private readonly IConfigurationProvider _mapperConfig; 

    public EntitiesProjector(IMapperConfiguration mapperConfig) 
    { 
     _mapperConfig = (IConfigurationProvider)mapperConfig; 
    } 

    public IQueryable<T> SelectTo<T>(IQueryable source) 
    { 
     return source.ProjectTo<T>(_mapperConfig); 
    } 
} 

Ma naturalmente si dovrebbe registrare il migliore configurazione come IConfigurationProvider nel vostro contenitore, cioè fix solo rapido per garantire problema è davvero qui.

Come per statico Mapper.CreateMap - beh è statico, quindi funziona indipendentemente da ciò che si passa a ProjectTo.

Come nota a margine questo mostra come non progettare api. Ogni volta che si verificano molti sovraccarichi e uno di essi accetta un oggetto generico e fa esattamente diverso da tutti gli altri sovraccarichi, questo è un problema.

+0

Ottima risposta. Grazie! –