如何从基本类型 ProjectTo 到仅在运行时已知的类型?

Jim*_*mmy 5 c# automapper entity-framework-core

我们使用 Entity Framework Core,其中包含一组共享基类的实体。

public class EntityBase { ... }

public class FirstEntityChild : EntityBase { ... }
public class SecondEntityChild : EntityBase { ... }
Run Code Online (Sandbox Code Playgroud)

我们使用它,这样我们就可以查询 aFirstEntityChild或 a ,SecondEntityChild而无需在编译时知道是哪一个。

为了向我们的视图提供数据,我们有视图模型。

public class FirstEntityChildViewModel { ... }
public class SecondEntityChildViewModel { ... }
Run Code Online (Sandbox Code Playgroud)

我们希望使用 AutoMapperProjectTo将数据库实体的查询结果映射到视图模型。我们设置了从FirstEntityChildFirstEntityChildViewModel和从SecondEntityChild到 的映射配置文件SecondEntityChildViewModel。我们没有来自 的地图EntityBase

我们目前正在尝试通过扩展方法进行类型推断来实现此目的:

public class EntityBase { ... }

public class FirstEntityChild : EntityBase { ... }
public class SecondEntityChild : EntityBase { ... }
Run Code Online (Sandbox Code Playgroud)

我们按如下方式使用它,假设sourceType是 或FirstEntityChildSecondEntityChild并且 targetType 是 或FirstEntityChildViewModelSecondEntityChildViewModel并且两者仅在运行时已知:

var sourceInstance = Activator.CreateInstance(sourceType);
var targetInstance = Activator.CreateInstance(targetType);

var results = await query
    .ProjectTo(sourceInstance, targetInstance, mapper.ConfigurationProvider)
    .ToListAsync();
Run Code Online (Sandbox Code Playgroud)

我们面临的问题发生在我们的ProjectTo扩展内部。当我在该行上调试并停止时,sourceTypeInstance并分别destinationTypeInstance出现在调试器中。但是当该行执行时,AutoMapper 尝试从 映射我们没有映射配置文件(我认为这是不可能的):FirstEntityChildFirstEntityChildViewModelEntityBaseobject

InvalidOperationException:缺少从 EntityBase 到 System.Object 的映射。使用Mapper.CreateMap 创建。

是否可以指示 AutoMapper 应使用的实际派生类型?或者我们现在只是遇到了仿制药的局限性?

小智 0

您可以使用反射从 ProjectTo 和目标类型创建通用方法,然后调用该方法来获取 ProjectTo 的结果。例如:

public static IQueryable<TDestination> ProjectTo<TSource, TDestination>(
    this IQueryable<TSource> query,
    TSource sourceTypeInstance,
    TDestination destinationTypeInstance,
    IConfigurationProvider configuration)
{
    var projectToMethod = typeof(AutoMapper.QueryableExtensions.Extensions)
            .GetMethod("ProjectTo", new Type[]
            {
                typeof(IQueryable),
                typeof(IConfigurationProvider),
                typeof(IDictionary<string, object>),
                typeof(string[])
            })
            .MakeGenericMethod(typeof(TDestination));
    return projectToMethod.Invoke(query, new object[] { query, configuration, new Dictionary<string, object>(), new string[] { } });
}
Run Code Online (Sandbox Code Playgroud)