如何将 ProjectTo 从基本类型转换为仅在运行时已知的类型?
How to ProjectTo from a base type to a type only known at runtime?
我们正在使用 Entity Framework 核心,其中包含一组共享基础 class 的实体。
public class EntityBase { ... }
public class FirstEntityChild : EntityBase { ... }
public class SecondEntityChild : EntityBase { ... }
我们使用它来查询 FirstEntityChild
或 SecondEntityChild
而无需在编译时知道是哪一个。
为了向我们的视图提供数据,我们有视图模型。
public class FirstEntityChildViewModel { ... }
public class SecondEntityChildViewModel { ... }
我们希望使用 AutoMapper 的 ProjectTo
将查询结果从我们的数据库实体映射到视图模型。我们设置了从 FirstEntityChild
到 FirstEntityChildViewModel
和从 SecondEntityChild
到 SecondEntityChildViewModel
的映射配置文件。我们没有来自 EntityBase
.
的地图
我们目前正在尝试使用扩展方法通过类型推断来完成此任务:
public static IQueryable<TDestination> ProjectTo<TSource, TDestination>(
this IQueryable<TSource> query,
TSource sourceTypeInstance,
TDestination destinationTypeInstance,
IConfigurationProvider configuration)
{
return query.ProjectTo<TDestination>(configuration);
}
我们按如下方式使用它,假设 sourceType
是 FirstEntityChild
或 SecondEntityChild
,并且 targetType 是 FirstEntityChildViewModel
或 SecondEntityChildViewModel
,两者都只在运行时才知道:
var sourceInstance = Activator.CreateInstance(sourceType);
var targetInstance = Activator.CreateInstance(targetType);
var results = await query
.ProjectTo(sourceInstance, targetInstance, mapper.ConfigurationProvider)
.ToListAsync();
我们面临的问题发生在我们的 ProjectTo
扩展中。当我调试并停在该行时,sourceTypeInstance
和 destinationTypeInstance
在调试器中分别显示为 FirstEntityChild
和 FirstEntityChildViewModel
。但是当该行执行时,AutoMapper 尝试从 EntityBase
映射到 object
, 我们没有对应的映射配置文件(我也没有认为甚至是可能的):
InvalidOperationException:缺少从 EntityBase 到 System.Object 的映射。使用 Mapper.CreateMap.
创建
是否可以指出 AutoMapper 应该使用的实际派生类型?还是我们现在只是遇到了泛型的局限性?
您可以使用反射从 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[] { } });
}
我们正在使用 Entity Framework 核心,其中包含一组共享基础 class 的实体。
public class EntityBase { ... }
public class FirstEntityChild : EntityBase { ... }
public class SecondEntityChild : EntityBase { ... }
我们使用它来查询 FirstEntityChild
或 SecondEntityChild
而无需在编译时知道是哪一个。
为了向我们的视图提供数据,我们有视图模型。
public class FirstEntityChildViewModel { ... }
public class SecondEntityChildViewModel { ... }
我们希望使用 AutoMapper 的 ProjectTo
将查询结果从我们的数据库实体映射到视图模型。我们设置了从 FirstEntityChild
到 FirstEntityChildViewModel
和从 SecondEntityChild
到 SecondEntityChildViewModel
的映射配置文件。我们没有来自 EntityBase
.
我们目前正在尝试使用扩展方法通过类型推断来完成此任务:
public static IQueryable<TDestination> ProjectTo<TSource, TDestination>(
this IQueryable<TSource> query,
TSource sourceTypeInstance,
TDestination destinationTypeInstance,
IConfigurationProvider configuration)
{
return query.ProjectTo<TDestination>(configuration);
}
我们按如下方式使用它,假设 sourceType
是 FirstEntityChild
或 SecondEntityChild
,并且 targetType 是 FirstEntityChildViewModel
或 SecondEntityChildViewModel
,两者都只在运行时才知道:
var sourceInstance = Activator.CreateInstance(sourceType);
var targetInstance = Activator.CreateInstance(targetType);
var results = await query
.ProjectTo(sourceInstance, targetInstance, mapper.ConfigurationProvider)
.ToListAsync();
我们面临的问题发生在我们的 ProjectTo
扩展中。当我调试并停在该行时,sourceTypeInstance
和 destinationTypeInstance
在调试器中分别显示为 FirstEntityChild
和 FirstEntityChildViewModel
。但是当该行执行时,AutoMapper 尝试从 EntityBase
映射到 object
, 我们没有对应的映射配置文件(我也没有认为甚至是可能的):
InvalidOperationException:缺少从 EntityBase 到 System.Object 的映射。使用 Mapper.CreateMap.
创建是否可以指出 AutoMapper 应该使用的实际派生类型?还是我们现在只是遇到了泛型的局限性?
您可以使用反射从 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[] { } });
}