protected override Expression VisitProjection(SqlProjectionExpression projectionExpression) { if (typeof(RelatedDataAccessObjects <>).IsAssignableFromIgnoreGenericParameters(projectionExpression.Type)) { var elementType = projectionExpression.Type.GetGenericArguments()[0]; var originalPlaceholderCount = 0; var currentPlaceholderCount = originalPlaceholderCount; var replacedExpressions = new List <Expression>(); projectionExpression = (SqlProjectionExpression)SqlOuterQueryReferencePlaceholderSubstitutor.Substitute(projectionExpression, ref currentPlaceholderCount, replacedExpressions); var values = replacedExpressions.Select(c => Expression.Convert(this.Visit(c), typeof(object))).ToList(); var where = projectionExpression.Select.Where; var typeDescriptor = this.dataAccessModel.TypeDescriptorProvider.GetTypeDescriptor(elementType); var columns = QueryBinder.GetColumnInfos(this.dataAccessModel.TypeDescriptorProvider, typeDescriptor.PersistedProperties); var columnExpression = (SqlColumnExpression)SqlExpressionFinder.FindFirst(where, c => c.NodeType == (ExpressionType)SqlExpressionType.Column); var match = columns.Single(d => d.ColumnName == columnExpression.Name); var reference = Expression.Call(Expression.Constant(this.dataAccessModel), MethodInfoFastRef.DataAccessModelGetReferenceByValuesMethod.MakeGenericMethod(match.ForeignType.Type), Expression.NewArrayInit(typeof(object), values)); var property = typeDescriptor.GetRelationshipInfos().Single(c => c.ReferencingProperty == match.RootProperty).TargetProperty; return(Expression.Convert(Expression.Property(reference, property), this.dataAccessModel.GetConcreteTypeFromDefinitionType(property.PropertyType))); } else { var currentPlaceholderCount = 0; var replacedExpressions = new List <Expression>(); projectionExpression = (SqlProjectionExpression)SqlOuterQueryReferencePlaceholderSubstitutor.Substitute(projectionExpression, ref currentPlaceholderCount, replacedExpressions); var newColumnIndexes = projectionExpression.Select.Columns.Select((c, i) => new { c.Name, i }).ToDictionary(d => d.Name, d => d.i); var savedScope = this.scope; this.scope = new ProjectionBuilderScope(newColumnIndexes); var projectionProjector = Expression.Lambda(this.Visit(projectionExpression.Projector), objectProjector, dataReader, versionParameter, dynamicParameters); this.scope = savedScope; var values = replacedExpressions.Select(c => (Expression)Expression.Convert(Visit(c), typeof(object))).ToList(); var method = TypeUtils.GetMethod <SqlQueryProvider>(c => c.BuildExecution(default(SqlProjectionExpression), default(LambdaExpression), default(object[]))); MethodInfo evaluate; if (projectionExpression.Type.GetSequenceElementType() == null) { evaluate = MethodInfoFastRef.ExecutionBuildResultEvaluateMethod.MakeGenericMethod(projectionExpression.Type); } else { evaluate = MethodInfoFastRef.ExecutionBuildResultEvaluateMethod.MakeGenericMethod(typeof(IEnumerable <>).MakeGenericType(projectionExpression.Type.GetSequenceElementType())); } return(Expression.Call(Expression.Call(Expression.Property(this.objectProjector, "QueryProvider"), method, Expression.Constant(projectionExpression), projectionProjector, Expression.NewArrayInit(typeof(object), values)), evaluate)); } }
internal static IEnumerable <Expression> GetIncludeJoins(this Expression expression) { var select = expression as SqlSelectExpression; if (select != null) { yield break; } var join = expression as SqlJoinExpression; if (join?.JoinType != SqlJoinType.Left) { yield break; } foreach (var value in join.Left.GetIncludeJoins()) { if (value == null) { if (!SqlExpressionFinder.FindExists(join.JoinCondition, c => !expressionTypes.Contains(c.NodeType))) { if (SqlExpressionFinder.FindExists(join.JoinCondition, c => c.NodeType == ExpressionType.Equal)) { yield return(join.JoinCondition); } } } else { yield return(value); } } foreach (var value in join.Right.GetIncludeJoins()) { if (value == null) { if (!SqlExpressionFinder.FindExists(join.JoinCondition, c => !expressionTypes.Contains(c.NodeType))) { if (SqlExpressionFinder.FindExists(join.JoinCondition, c => c.NodeType == ExpressionType.Equal)) { yield return(join.JoinCondition); } } } else { yield return(value); } } }