9

我正在尝试在实体框架 IQueryables 上使用 Automapper 投影。

在应用程序启动时,我创建并添加了所有使用非静态 CreateMap 方法创建地图的映射配置文件。

所有这些配置文件都在我的 IoC 容器中注册。

尽管我在 mappingConfiguration 的实例中看到了映射配置文件,但我得到了缺少的映射异常。

可能是什么问题呢?我错过了什么吗?我正在使用 Automapper 4.2.1

我注意到在添加静态 Mapper.CreateMap 时,它工作正常。投影是否仅适用于静态 API?我想避免使用静态 API。

完整代码:

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();
4

1 回答 1

9

原因是以下块:

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是一种扩展方法,有 5 个重载。在文档中,他们在MappingConfiguration那里传递类的实例,而您正在传递IMapperConfiguration(接口)的实例。你认为它会产生同样的效果,但事实并非如此。IMapperConfigurationinterface 没有实现IConfigurationProvider接口,并且 ( IConfigurationProvider) 是正确的重载ProjectTo接受。但是,还有另一个重载ProjectTo,它接受“ object parameters”。因为它接受对象 - 它会匹配任何不适合其他重载的东西。所以你真正调用的是ProjectTo(object)重载,它与配置无关,你的IMapperConfiguration连同配置文件和地图完全被忽略了。

快速修复将是

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

但是当然,您最好将您的配置注册为IConfigurationProvider在您的容器中,这只是快速修复以确保问题确实存在。

至于静态Mapper.CreateMap- 它是静态的,所以不管你传递给ProjectTo.

作为旁注,这向您展示了如何不设计 api。每当您有许多重载并且其中一个接受泛型对象并且做与所有其他重载完全不同的事情时 - 这就是自找麻烦。

于 2016-04-16T22:13:25.290 回答