private IEnumerable <Expression> CreateIncludeRelatedValuesStrategyFactories( IQuerySource querySource, IEnumerable <INavigation> navigationPath) { var selectExpression = _queryCompilationContext.FindSelectExpression(querySource); var targetTableExpression = selectExpression.FindTableForQuerySource(querySource); var readerIndex = 0; var canProduceInnerJoin = true; 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() ? targetEntityType : navigation.EntityType) .GetPrimaryKey().Properties, navigation.PointsToPrincipal() ? targetTableExpression : joinExpression, navigation.PointsToPrincipal() ? joinExpression : targetTableExpression); targetTableExpression = joinedTableExpression; 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.EntityType.GetPrimaryKey().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(); foreach (var expression in innerJoinSelectExpression.OrderBy .Select(o => o.Expression)) { innerJoinSelectExpression.AddToProjection(expression); } innerJoinSelectExpression.ClearOrderBy(); var primaryKeyProperties = navigation.EntityType.GetPrimaryKey().Properties; var innerJoinExpression = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression); targetSelectExpression.UpdateOrderByColumnBinding(selectExpression.OrderBy, innerJoinExpression); innerJoinExpression.Predicate = BuildJoinEqualityExpression( navigation, primaryKeyProperties, targetTableExpression, innerJoinExpression); selectExpression = targetSelectExpression; readerIndex++; 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))); } } }
private IEnumerable <Expression> CreateIncludeRelatedValuesStrategyFactories( IQuerySource querySource, IEnumerable <INavigation> navigationPath) { var selectExpression = _queryCompilationContext.FindSelectExpression(querySource); var targetTableExpression = selectExpression.FindTableForQuerySource(querySource); var readerIndex = 0; foreach (var navigation in navigationPath) { if (!navigation.IsCollection()) { var targetEntityType = navigation.GetTargetType(); var targetTableName = _queryCompilationContext.GetTableName(targetEntityType); var targetTableAlias = targetTableName.First().ToString().ToLower(); var joinedTableExpression = new TableExpression( targetTableName, _queryCompilationContext.GetSchema(targetEntityType), targetTableAlias, querySource); var readerOffset = selectExpression.Projection.Count; var columnExpressions = targetEntityType.Properties .Select(p => new ColumnExpression( _queryCompilationContext.GetColumnName(p), p, joinedTableExpression)); var joinExpression = navigation.ForeignKey.IsRequired && navigation.PointsToPrincipal ? selectExpression .AddInnerJoin(joinedTableExpression, columnExpressions) : selectExpression .AddOuterJoin(joinedTableExpression, columnExpressions); joinExpression.Predicate = BuildJoinEqualityExpression( navigation, (navigation.PointsToPrincipal ? targetEntityType : navigation.EntityType) .GetPrimaryKey().Properties, navigation.PointsToPrincipal ? targetTableExpression : joinExpression, navigation.PointsToPrincipal ? joinExpression : targetTableExpression); targetTableExpression = joinedTableExpression; yield return (Expression.Lambda( Expression.Call( _queryCompilationContext.QueryMethodProvider .CreateReferenceIncludeRelatedValuesStrategyMethod, Expression.Convert(EntityQueryModelVisitor.QueryContextParameter, typeof(RelationalQueryContext)), Expression.Constant(readerIndex), Expression.Constant(readerOffset)))); } else { var principalTable = selectExpression.Tables.Last(t => t.QuerySource == querySource); foreach (var property in navigation.EntityType.GetPrimaryKey().Properties) { selectExpression .AddToOrderBy( _queryCompilationContext.GetColumnName(property), property, principalTable, OrderingDirection.Asc); } var targetEntityType = navigation.GetTargetType(); var targetTableName = _queryCompilationContext.GetTableName(targetEntityType); var targetTableAlias = targetTableName.First().ToString().ToLower(); var targetSelectExpression = new SelectExpression(); targetTableExpression = new TableExpression( targetTableName, _queryCompilationContext.GetSchema(targetEntityType), targetTableAlias, querySource); targetSelectExpression.AddTable(targetTableExpression); foreach (var property in targetEntityType.Properties) { targetSelectExpression .AddToProjection( _queryCompilationContext.GetColumnName(property), property, querySource); } var innerJoinSelectExpression = selectExpression.Clone( ((ColumnExpression)selectExpression.OrderBy.Last().Expression).TableAlias); innerJoinSelectExpression.IsDistinct = true; innerJoinSelectExpression.ClearProjection(); foreach (var columnExpression in innerJoinSelectExpression.OrderBy .Select(o => o.Expression) .Cast <ColumnExpression>()) { innerJoinSelectExpression.AddToProjection(columnExpression); } innerJoinSelectExpression.ClearOrderBy(); var primaryKeyProperties = navigation.EntityType.GetPrimaryKey().Properties; var innerJoinExpression = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression); foreach (var ordering in selectExpression.OrderBy) { var columnExpression = (ColumnExpression)ordering.Expression; targetSelectExpression .AddToOrderBy( columnExpression.Name, columnExpression.Property, innerJoinExpression, ordering.OrderingDirection); } innerJoinExpression.Predicate = BuildJoinEqualityExpression( navigation, primaryKeyProperties, targetTableExpression, innerJoinExpression); var readerParameter = Expression.Parameter(typeof(DbDataReader)); selectExpression = targetSelectExpression; readerIndex++; yield return (Expression.Lambda( Expression.Call( _queryCompilationContext.QueryMethodProvider .CreateCollectionIncludeRelatedValuesStrategyMethod, Expression.Call( _queryCompilationContext.QueryMethodProvider.QueryMethod .MakeGenericMethod(typeof(IValueReader)), EntityQueryModelVisitor.QueryContextParameter, Expression.Constant(new CommandBuilder(targetSelectExpression, _queryCompilationContext)), Expression.Lambda( Expression.Call( _createValueReaderForIncludeMethodInfo, EntityQueryModelVisitor.QueryContextParameter, readerParameter, Expression.Constant(targetEntityType)), readerParameter))))); } } }