private JoinExpressionBase AdjustJoinExpression(SelectExpression selectExpression, JoinExpressionBase joinExpression) { var subquery = new SelectExpression(_sqlQueryGeneratorFactory, joinExpression.Alias); subquery.AddTable(joinExpression.TableExpression); subquery.IsProjectStar = true; subquery.Predicate = selectExpression.Predicate; var newJoinExpression = joinExpression is LeftOuterJoinExpression ? (JoinExpressionBase)new LeftOuterJoinExpression(subquery) : new InnerJoinExpression(subquery); newJoinExpression.QuerySource = joinExpression.QuerySource; newJoinExpression.Alias = joinExpression.Alias; return newJoinExpression; }
private IEnumerable<Expression> CreateIncludeRelatedValuesStrategyFactories( IQuerySource querySource, IEnumerable<INavigation> navigationPath) { var selectExpression = _queryCompilationContext.FindSelectExpression(querySource); var targetTableExpression = selectExpression.GetTableForQuerySource(querySource); var canProduceInnerJoin = true; var includeReferenceCount = 0; foreach (var navigation in navigationPath) { var targetEntityType = navigation.GetTargetType(); var targetTableName = _queryCompilationContext.GetTableName(targetEntityType); var targetTableAlias = targetTableName[0].ToString().ToLower(); if (!navigation.IsCollection()) { var joinedTableExpression = new TableExpression( targetTableName, _queryCompilationContext.GetSchema(targetEntityType), targetTableAlias, querySource); var valueBufferOffset = selectExpression.Projection.Count; canProduceInnerJoin = canProduceInnerJoin && (navigation.ForeignKey.IsRequired && navigation.PointsToPrincipal()); var joinExpression = canProduceInnerJoin ? selectExpression .AddInnerJoin(joinedTableExpression) : selectExpression .AddOuterJoin(joinedTableExpression); var materializer = new MaterializerFactory( _queryCompilationContext.EntityMaterializerSource) .CreateMaterializer( targetEntityType, selectExpression, projectionAdder: (p, se) => se.AddToProjection( new AliasExpression( new ColumnExpression( _queryCompilationContext.GetColumnName(p), p, joinedTableExpression))) - valueBufferOffset, querySource: null); joinExpression.Predicate = BuildJoinEqualityExpression( navigation, navigation.PointsToPrincipal() ? targetTableExpression : joinExpression, navigation.PointsToPrincipal() ? joinExpression : targetTableExpression, querySource); targetTableExpression = joinedTableExpression; var readerIndex = _readerIndexes[includeReferenceCount]; includeReferenceCount++; yield return Expression.Lambda( Expression.Call( _queryCompilationContext.QueryMethodProvider .CreateReferenceIncludeRelatedValuesStrategyMethod, Expression.Convert( EntityQueryModelVisitor.QueryContextParameter, typeof(RelationalQueryContext)), Expression.Constant(valueBufferOffset), Expression.Constant(readerIndex), materializer)); } else { var principalTable = selectExpression.Tables.Last(t => t.QuerySource == querySource); foreach (var property in navigation.ForeignKey.PrincipalKey.Properties) { selectExpression .AddToOrderBy( _queryCompilationContext.GetColumnName(property), property, principalTable, OrderingDirection.Asc); } var targetSelectExpression = new SelectExpression(); targetTableExpression = new TableExpression( targetTableName, _queryCompilationContext.GetSchema(targetEntityType), targetTableAlias, querySource); targetSelectExpression.AddTable(targetTableExpression); var materializer = new MaterializerFactory( _queryCompilationContext.EntityMaterializerSource) .CreateMaterializer( targetEntityType, targetSelectExpression, (p, se) => se.AddToProjection( _queryCompilationContext.GetColumnName(p), p, querySource), querySource: null); var innerJoinSelectExpression = selectExpression.Clone( selectExpression.OrderBy .Select(o => o.Expression) .Last(o => o.IsAliasWithColumnExpression()) .TryGetColumnExpression().TableAlias); innerJoinSelectExpression.IsDistinct = true; innerJoinSelectExpression.ClearProjection(); var innerJoinExpression = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression); LiftOrderBy(innerJoinSelectExpression, targetSelectExpression, innerJoinExpression); innerJoinExpression.Predicate = BuildJoinEqualityExpression( navigation, targetTableExpression, innerJoinExpression, querySource); selectExpression = targetSelectExpression; yield return Expression.Lambda( Expression.Call( _queryCompilationContext.QueryMethodProvider .CreateCollectionIncludeRelatedValuesStrategyMethod, Expression.Call( _queryCompilationContext.QueryMethodProvider.QueryMethod, EntityQueryModelVisitor.QueryContextParameter, Expression.Constant( new CommandBuilder( () => _queryCompilationContext.CreateSqlQueryGenerator(targetSelectExpression), _queryCompilationContext.ValueBufferFactoryFactory))), materializer)); } } }