目前我正在开发一个项目,该项目在Entityframework之上构建了一个额外的层,用于将查询从实体转换为DTO。我们使用自定义可查询来抽象表达式创建,以在实现之前调用convert。
public Expression ConvertExpression(Expression origExpression)
{
var expandedExpression = ExpressionExtensions.Expand(origExpression);
var dummyValueExpr = expandedExpression as ConstantExpression;
if (null != dummyValueExpr)
{
// Check if the expression is actually a dummy marker for some wrapper queryable
var dummyQueryableValueConstant = dummyValueExpr.Value as IDummyQueryableValueConstant;
if (null == dummyQueryableValueConstant)
{
// It's possible that the constant value is also another ConvertedQueryable.
var innerQueryable = dummyValueExpr.Value as IConvertedQueryable;
if ((null != innerQueryable) && (innerQueryable != this) && (innerQueryable.Expression is ConstantExpression))
{
return innerQueryable.ConvertExpression(innerQueryable.Expression);
}
}
if (null != dummyQueryableValueConstant)
{
return this.ConvertExpression(dummyQueryableValueConstant.StoredQueryable.Expression);
}
}
return expandedExpression;
}
我们已经重写了IQueryable Provider方法,以便在执行前调用我们的转换:
public override object Execute(Expression expression)
{
var constructors = AddConstructorsFromExpression(expression);
var convertedExpression = this.ExpressionConverter.Visit(expression);
var result = this._queryProvider.Execute(convertedExpression);
if (null == result)
{
return null;
}
var types = GetInnerAndOuterTypesForInnerObject(result, convertedExpression.Type, expression.Type);
return this._innerToOuterConverterFactory()
.Convert(result, types.Key, types.Value, x => GetConstructorOrNull(constructors, x));
}
当我不使用GroupBy或Select(x => new {x})时,Include语句正常工作;我的第一个直觉是可查询生成的表达式是错误的。所以我基于使用我们的上下文和使用northwind上的entityframework来映射表达式
.Call System.Linq.Queryable.GroupBy( .Call System.Linq.Queryable.Where( .Call(.Call .Constant1 [StagingNorthWindTest.Customer]>(System.Data.Entity.Core.Objects.ObjectQuery1 [StagingNorthWindTest.Customer])。MergeAs(.Constant(AppendOnly)) ).IncludeSpan(.Constant(System.Data.Entity.Core.Objects.Span)), '(。Lambda#Lambda1))
.Lambda#Lambda1(StagingNorthWindTest.Customer $ x){ 真正 }
.Lambda#Lambda2(StagingNorthWindTest.Customer $ x){ $ x.City }
.Call System.Linq.Queryable.GroupBy( .Call System.Linq.Queryable.Where( .Call(.Call .Constant1 [BDBPayroll.Services.DataAccess.RowEntities.DivisionRptPackageRow]>(System.Data.Entity.Core.Objects.ObjectQuery1 [BDBPayroll.Services.DataAccess.RowEntities.DivisionRptPackageRow])。MergeAs(.Constant( AppendOnly)) ).IncludeSpan(.Constant(System.Data.Entity.Core.Objects.Span)), '(。Lambda#Lambda1))
.Lambda#Lambda1(BDBPayroll.Services.DataAccess.RowEntities.DivisionRptPackageRow $ x) { 真正 }
.Lambda#Lambda2(BDBPayroll.Services.DataAccess.RowEntities.DivisionRptPackageRow $ x) { $ x.DivisionRptPackageID }
对于针对northwind的相同操作生成的表达式与我们的上下文使用相同的语法和路径。然而,内部DbQueryProvider似乎忽略了我的包含跨度,尽管它们正确包含包含。
实体框架在生成Projections I.E Group by或匿名选择时是否有什么特别之处?
修改
当我使用普通的EF时,我终于找到了一个小的区别,include调用了dbQuery Path,而当我使用我的上下文时,它调用了QueryableExtensions.CommonInclude
if (dbQuery != null)
return (IQueryable<T>) dbQuery.Include(path);
ObjectQuery<T> objectQuery = source as ObjectQuery<T>;
if (objectQuery != null)
return (IQueryable<T>) objectQuery.Include(path);
return QueryableExtensions.CommonInclude<IQueryable<T>>(source, path);
这两种方法有什么区别?