protected override Expression VisitMember(MemberExpression node) { if (!_translateToSql) { var sqlExpression = _selectExpression.GetProjectionForMemberInfo(node.Member); if (sqlExpression != null) { return(BindSqlToValueBuffer(sqlExpression, node.Type)); } if (node.Member.Name == KeyName && node.Expression.TryGetReferencedQuerySource() == _groupQuerySource) { var querySourceFinder = new QuerySourceFindingExpressionVisitor(); querySourceFinder.Visit(_keySelector); var currentParameter = _queryModelVisitor.CurrentParameter; foreach (var querySource in querySourceFinder.QuerySources) { _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping( querySource, currentParameter); } return(_projectionExpressionVisitor.Visit(_keySelector)); } } return(base.VisitMember(node)); }
protected override Expression VisitMember(MemberExpression memberExpression) { if (!_translateToSql) { // For composite Key case, projection member info will be already populated var sqlExpression = _selectExpression.GetProjectionForMemberInfo(memberExpression.Member); if (sqlExpression != null) { return(BindSqlToValueBuffer(sqlExpression, memberExpression.Type)); } if (memberExpression.Member.Name == KeyName && memberExpression.Expression.TryGetReferencedQuerySource() == _groupQuerySource) { var querySourceFinder = new QuerySourceFindingExpressionVisitor(); querySourceFinder.Visit(_keySelector); var currentParameter = _queryModelVisitor.CurrentParameter; foreach (var querySource in querySourceFinder.QuerySources) { _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping( querySource, currentParameter); } sqlExpression = _projectionExpressionVisitor.Visit(_keySelector); _sqlMapping[memberExpression] = sqlExpression; return(sqlExpression); } } return(base.VisitMember(memberExpression)); }
/// <summary> /// Visits the given node. /// </summary> /// <param name="expression"> The expression to visit. </param> /// <returns> /// An Expression to the translated input expression. /// </returns> public override Expression Visit(Expression expression) { if (expression == null || _targetSelectExpression == null) { return(expression); } switch (expression) { // To save mappings so that we can compose afterwards case NewExpression newExpression: return(VisitNew(newExpression)); case MemberInitExpression memberInitExpression: return(VisitMemberInit(memberInitExpression)); case QuerySourceReferenceExpression qsre: if (_targetSelectExpression.HandlesQuerySource(qsre.ReferencedQuerySource)) { _targetSelectExpression.ProjectStarTable = _targetSelectExpression.GetTableForQuerySource(qsre.ReferencedQuerySource); } return(qsre); // Skip over Include and Correlated Collection methods case MethodCallExpression methodCallExpression when IncludeCompiler.IsIncludeMethod(methodCallExpression) || CorrelatedCollectionOptimizingVisitor.IsCorrelatedCollectionMethod(methodCallExpression): return(methodCallExpression); // Group By key translation to cover composite key cases case MemberExpression memberExpression when memberExpression.Expression.TryGetReferencedQuerySource() == _querySource && _querySource.ItemType.IsGrouping() && memberExpression.Member.Name == nameof(IGrouping <int, int> .Key): var groupResultOperator = (GroupResultOperator)((SubQueryExpression)((FromClauseBase)_querySource).FromExpression) .QueryModel.ResultOperators.Last(); var sqlTranslation = _sqlTranslatingExpressionVisitorFactory .Create( QueryModelVisitor, _isGroupAggregate ? _groupAggregateTargetSelectExpression : _targetSelectExpression, inProjection: true) .Visit(expression); if (sqlTranslation == null) { // If the key is composite then we need to visit actual keySelector to construct the type. // Since we are mapping translating actual KeySelector now, we need to re-map QuerySources var querySourceFinder = new QuerySourceFindingExpressionVisitor(); querySourceFinder.Visit(groupResultOperator.KeySelector); foreach (var querySource in querySourceFinder.QuerySources) { QueryModelVisitor.QueryCompilationContext.AddOrUpdateMapping( querySource, QueryModelVisitor.CurrentParameter); } _isGroupAggregate = false; var translatedKey = Visit(groupResultOperator.KeySelector); _isGroupAggregate = true; return(translatedKey); } break; } // Fallback var sqlExpression = _sqlTranslatingExpressionVisitorFactory .Create( QueryModelVisitor, _isGroupAggregate ? _groupAggregateTargetSelectExpression : _targetSelectExpression, inProjection: true) .Visit(expression); if (sqlExpression == null) { QueryModelVisitor.RequiresClientProjection = true; return(base.Visit(expression)); } else if (sqlExpression is ConstantExpression && QueryModelVisitor.ParentQueryModelVisitor == null) { return(base.Visit(expression)); } else { sqlExpression = sqlExpression.UnwrapNullableExpression(); // We bind with ValueBuffer in GroupByAggregate case straight away // Since the expression can be some translation from [g].[Key] which won't bind with MemberAccessBindingEV if (!_isGroupAggregate && sqlExpression is ColumnExpression) { var index = _targetSelectExpression.AddToProjection(sqlExpression); _sourceExpressionProjectionMapping[expression] = _targetSelectExpression.Projection[index]; return(expression); } var targetExpression = QueryModelVisitor.QueryCompilationContext.QuerySourceMapping .GetExpression(_querySource); if (targetExpression.Type == typeof(ValueBuffer)) { var index = _targetSelectExpression.AddToProjection(sqlExpression); _sourceExpressionProjectionMapping[expression] = _targetSelectExpression.Projection[index]; var readValueExpression = _entityMaterializerSource .CreateReadValueExpression( targetExpression, expression.Type.MakeNullable(), index, sqlExpression.FindProperty(expression.Type)); var outputDataInfo = (expression as SubQueryExpression)?.QueryModel .GetOutputDataInfo(); if (outputDataInfo is StreamedScalarValueInfo) { // Compensate for possible nulls readValueExpression = Expression.Coalesce( readValueExpression, Expression.Default(expression.Type)); } return(Expression.Convert(readValueExpression, expression.Type)); } return(expression); } }