9

Ich versuche, Automapper-Projektionen auf Entity Framework IQueryables zu verwenden.Automapper 4.2.1 LINQ-Projektionen funktionieren nur mit statischer Mapper.CreateMap?

Beim Start der Anwendung, ich alle meine Mapping-Profile erstellen und hinzufügen, die Karten mit der nicht-statischen CreateMap-Methode erstellen.

Alle diese Profile sind in meinem IoC-Container registriert.

Ich bekomme die fehlende Mapping-Ausnahme, obwohl ich das Mapping-Profil in der Instanz meiner MappingConfiguration sehe.

Was könnte das Problem sein? Fehle ich etwas? Ich benutze Automapper 4.2.1

Ich habe festgestellt, dass beim Hinzufügen einer statischen Mapper.CreateMap funktioniert es gut. Funktionieren Projektionen nur mit statischer API? Ich möchte die statische API vermeiden.

vollständiger Code:

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

senden Sie Ihre Codebeispiel –

+0

Mein Profil hinzugefügt .. soll es funktionieren? Oder ist bekannt, dass Projektionen nur bei Verwendung der statischen API funktionieren? –

+0

Wenn ich 'ProjectTo()' 'verwende, muss ich einen generischen Typparameter hinzufügen und eine Mapperkonfiguration als Parameter bereitstellen. Sie haben von denen in Ihrem sehr unvollständigen Fragecode nie. Btw: Ich benutze'AutoMapper.QueryableExtensions; ', um meine 'ProjectTo' Überladung Erweiterungen zu bekommen – grek40

Antwort

10

Der Grund ist der folgende Block:

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 ist ein Erweiterungsverfahren, das 5 Überlastungen aufweist. In der Dokumentation übergeben sie die Instanz MappingConfiguration Klasse, und Sie übergeben Instanz IMapperConfiguration (Schnittstelle). Sie denken, dass es den gleichen Effekt haben wird, aber es nicht tut. IMapperConfiguration Schnittstelle implementiert nicht IConfigurationProvider Schnittstelle, und das (IConfigurationProvider) ist, was die korrekte Überlastung von ProjectTo akzeptiert. Aber es gibt eine weitere Überlast von ProjectTo, die "object parameters" akzeptiert. Weil es ein Objekt akzeptiert - es passt alles an, was nicht zu anderen Überladungen passt. Also, was Sie wirklich anrufen, ist ProjectTo(object) Überlastung, die nichts mit Konfiguration zu tun hat, und Ihre IMapperConfiguration zusammen mit Profilen und Karten wird vollständig ignoriert.

Quickfix

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

Aber natürlich sein wird, sollten Sie besser Ihre Konfiguration als IConfigurationProvider in Ihrem Container registrieren, das ist nur schnelle Lösung Problem, um sicherzustellen, wirklich hier ist.

Wie für statische Mapper.CreateMap - nun, es ist statisch, so funktioniert unabhängig davon, was Sie an ProjectTo übergeben.

Als eine Randnotiz zeigt dies, wie Sie nicht api entwerfen. Wann immer Sie viele Überladungen haben und einer von ihnen akzeptiert generische Objekt und macht komplett andere Sache als alle anderen Überladungen - das ist für Ärger.

+0

Ausgezeichnete Antwort. Vielen Dank! –