我们正在尝试将IQueryable<EntityObject>
的实例强制转换为IQueryable<SpecificEntityObject>
,SpecificEntityObject
类型仅在运行时已知。
我们尝试使用下面的代码,但由于类型或命名空间'objType'不存在而无法编译。
var t = query.ElementType;
Type objType = typeof(IQueryable<>).MakeGenericType(t);
var typed = query.Cast<IEnumerable<objType>>();
var grouped = typed.GroupByMany(groupBy.Select(grp => grp.Expression).ToArray());
有什么想法吗?
答案 0 :(得分:5)
使用以下IQueryable扩展通用方法query.ToDTO<sourceType,DestType>();
:
public static class QueryableExtensions
{
public static IQueryable<TDest> ToDTO<TSource, TDest>(this IQueryable<TSource> source)
{
List<TDest> destinationList = new List<TDest>();
List<TSource> sourceList = source.ToList<TSource>();
var sourceType = typeof(TSource);
var destType = typeof(TDest);
foreach (TSource sourceElement in sourceList)
{
TDest destElement = Activator.CreateInstance<TDest>();
//Get all properties from the object
PropertyInfo[] sourceProperties = typeof(TSource).GetProperties();
foreach (PropertyInfo sourceProperty in sourceProperties)
{
//and assign value to each propery according to property name.
PropertyInfo destProperty = destType.GetProperty(sourceProperty.Name);
destProperty.SetValue(destElement, sourceProperty.GetValue(sourceElement, null), null);
}
destinationList.Add(destElement);
}
return destinationList.AsQueryable();
}
}
答案 1 :(得分:1)
对于其他想要从db查询中投射非db值的人来说,来自this的u/Luis Aguilar项目对我来说非常非常有帮助。
我有一个非常大的遗留数据库(450GB),需要提供给OData / WebAPI。
OData要求意味着在将数据返回给用户之前,我无法过滤源数据。我们可以把它弄清楚,但除此之外,他们的数据是按照自己的意愿进行查询。
然而,更重要的是,遗留数据过于复杂,无法按原样公开,并且需要大量业务逻辑来整理必要的数据(Include
导航属性/外键,冗长子句谓词,等)。
这意味着在查询已经实现之后,分页和结果限制才可用。
此类事物的正常快捷方式涉及涉及物化/急切加载的各种策略。但是,由于数据集的大小和缺少过滤,这将导致大量进程内存膨胀和内存不足崩溃。
所以,一些代码。这是我的配置调用,类似于AutoMapper或OData所需:
using ExpressionFramework.Projections;
using ExpressionFramework.Projections.Configuration;
public class ProjectionModelBuilder : ProjectionModel
{
protected override void OnModelCreating(ProjectionModelBuilder modelBuilder)
{
ClientDTO.ProjectionModel(modelBuilder);
OrderDTO.ProjectionModel(modelBuilder);
AnotherDTO.ProjectionModel(modelBuilder);
}
}
这种设计允许我将DTO类中的投影规则与其余的业务逻辑保持在一起。这是DTO级代码的样子:
public static void ProjectionModel(ProjectionModelBuilder modelBuilder)
{
modelBuilder
.Projection<ClientDTO>()
.ForSource<Client>(configuration =>
{
configuration.Property(dto => dto.Name).ExtractFrom(entity => entity.Name);
// etc
});
}
Client
是我的实体/ EDM类型,映射到db表和大量外键。
然后获得翻译/预测Queryable
,就是这样:
IClientQueryService service = _ioc.Resolve<IClientQueryService>(); // Repository pattern
var q = service.GetClients(); // withManyNavigationIncludes
var r = q.Where<Item>(
i =>
i.Name != null
&& i.Name != ""
// lather rinse repeat, with many sub-objects navigated also
).AsQueryable();
var projectionModel = new ProjectionModelBuilder();
var s = projectionModel.Project<ClientDTO, Client>(r).AsQueryable();
只有最后两行是相关的,但其余部分包含在上下文中。
我要做的最后一件事是在路易斯的this.IsAutoConfigured = false;
的构造函数中设置ProjectionSourceTypeConfiguration.cs
。码;这允许我手动订购我的投影定义,因此父类中的导航属性将成功配置它们的投影。
我无法感谢https://stackoverflow.com/users/543712/luis-aguilar他的工作。在编写了我自己的LINQ Provider / ExpressionVisitor
之后,各种泛型方法调用,翻译和树木路径仍然存在各种问题,他的项目是天赐之物。
如果您确实发现必须为了性能或其他原因而对您自己的表达式处理进行管道处理,我建议首先提出these two个答案。< / p>
答案 2 :(得分:0)
如果您开始使用反射,则需要将其与所有方法一起使用。所以你需要创建
var myEnumType = typeof(IEnumerable<>).MakeGenericType(objType);
并且还可以在运行时找到扩展方法Cast匹配所需的类型。
myEnumType.GetMethod("Cast", BindingFlags.Public |
BindingFlags.Static,
null,
CallingConventions.Any,
new Type[] {typeof(object)},
null);
那么你就可以调用那个方法
答案 3 :(得分:0)
var t = query.ElementType;
Type objType = typeof(IQueryable<>).MakeGenericType(t);
var typed = query.Cast<object>();
var grouped = typed.GroupByMany(groupBy.Select(grp => grp.Expression).ToArray());