/// <summary> /// Makes a copy of this SelectExpression. /// </summary> /// <param name="alias"> The alias. </param> /// <returns> /// A copy of this SelectExpression. /// </returns> public virtual SelectExpression Clone([CanBeNull] string alias = null) { var selectExpression = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext) { _limit = _limit, _offset = _offset, _isDistinct = _isDistinct, _subqueryDepth = _subqueryDepth, IsProjectStar = IsProjectStar, Predicate = Predicate }; if (alias != null) { selectExpression.Alias = _queryCompilationContext.CreateUniqueTableAlias(alias); } selectExpression._projection.AddRange(_projection); selectExpression.AddTables(_tables); selectExpression.AddToOrderBy(_orderBy); return(selectExpression); }
public virtual void AddTable([NotNull] TableExpressionBase tableExpression, bool createUniqueAlias = true) { Check.NotNull(tableExpression, nameof(tableExpression)); if (createUniqueAlias) { tableExpression.Alias = _queryCompilationContext.CreateUniqueTableAlias(tableExpression.Alias); } _tables.Add(tableExpression); }
/// <summary> /// Creates a new instance of SelectExpression. /// </summary> /// <param name="querySqlGeneratorFactory"> The query SQL generator factory. </param> /// <param name="queryCompilationContext"> Context for the query compilation. </param> /// <param name="alias"> The alias. </param> public SelectExpression( [NotNull] IQuerySqlGeneratorFactory querySqlGeneratorFactory, [NotNull] RelationalQueryCompilationContext queryCompilationContext, [NotNull] string alias) : this(querySqlGeneratorFactory, queryCompilationContext) { Check.NotNull(alias, nameof(alias)); // When assigning alias to select expression make it unique Alias = queryCompilationContext.CreateUniqueTableAlias(alias); }
/// <summary> /// Creates a new instance of SelectExpression. /// </summary> /// <param name="dependencies"> Parameter object containing dependencies for this service. </param> /// <param name="queryCompilationContext"> Context for the query compilation. </param> /// <param name="alias"> The alias. </param> public SelectExpression( [NotNull] SelectExpressionDependencies dependencies, [NotNull] RelationalQueryCompilationContext queryCompilationContext, [NotNull] string alias) : this(dependencies, queryCompilationContext) { Check.NotNull(alias, nameof(alias)); // When assigning alias to select expression make it unique Alias = queryCompilationContext.CreateUniqueTableAlias(alias); }
/// <summary> /// Creates a new instance of SelectExpression. /// </summary> /// <param name="dependencies"> Parameter object containing dependencies for this service. </param> /// <param name="queryCompilationContext"> Context for the query compilation. </param> /// <param name="alias"> The alias. </param> public SelectExpression( [NotNull] SelectExpressionDependencies dependencies, [NotNull] RelationalQueryCompilationContext queryCompilationContext, [NotNull] string alias) : this(dependencies, queryCompilationContext) { Check.NotNull(alias, nameof(alias)); // When assigning alias to select expression make it unique // ReSharper disable once VirtualMemberCallInConstructor Alias = queryCompilationContext.CreateUniqueTableAlias(alias); }
private IReadOnlyList <Func <QueryContext, TRelatedEntitiesLoader> > CreateRelatedEntitiesLoaders <TRelatedEntitiesLoader>( IQuerySource querySource, IEnumerable <INavigation> navigationPath) { var relatedEntitiesLoaders = new List <Func <QueryContext, TRelatedEntitiesLoader> >(); var selectExpression = _queryCompilationContext.FindSelectExpression(querySource); var compositePredicateExpressionVisitor = _compositePredicateExpressionVisitorFactory.Create(); var targetTableExpression = selectExpression.GetTableForQuerySource(querySource); var canProduceInnerJoin = true; var navigationCount = 0; foreach (var navigation in navigationPath) { var queryIndex = _queryIndexes[navigationCount]; navigationCount++; var targetEntityType = navigation.GetTargetType(); var targetTableName = _relationalAnnotationProvider.For(targetEntityType).TableName; var targetTableAlias = _queryCompilationContext .CreateUniqueTableAlias(targetTableName[0].ToString().ToLowerInvariant()); if (!navigation.IsCollection()) { var joinedTableExpression = new TableExpression( targetTableName, _relationalAnnotationProvider.For(targetEntityType).Schema, targetTableAlias, querySource); var valueBufferOffset = selectExpression.Projection.Count; canProduceInnerJoin = canProduceInnerJoin && navigation.ForeignKey.IsRequired && navigation.IsDependentToPrincipal(); var joinExpression = canProduceInnerJoin ? selectExpression.AddInnerJoin(joinedTableExpression) : selectExpression.AddLeftOuterJoin(joinedTableExpression); var oldPredicate = selectExpression.Predicate; var materializer = _materializerFactory .CreateMaterializer( targetEntityType, selectExpression, (p, se) => se.AddToProjection( new AliasExpression( new ColumnExpression( _relationalAnnotationProvider.For(p).ColumnName, p, joinedTableExpression))) - valueBufferOffset, querySource: null); if (selectExpression.Predicate != oldPredicate) { selectExpression.Predicate = compositePredicateExpressionVisitor .Visit(selectExpression.Predicate); var newJoinExpression = AdjustJoinExpression(selectExpression, joinExpression); selectExpression.Predicate = oldPredicate; selectExpression.RemoveTable(joinExpression); selectExpression.AddTable(newJoinExpression, createUniqueAlias: false); joinExpression = newJoinExpression; } joinExpression.Predicate = BuildJoinEqualityExpression( navigation, navigation.IsDependentToPrincipal() ? targetTableExpression : joinExpression, navigation.IsDependentToPrincipal() ? joinExpression : targetTableExpression, querySource); targetTableExpression = joinedTableExpression; relatedEntitiesLoaders.Add(qc => (TRelatedEntitiesLoader)_queryCompilationContext.QueryMethodProvider .CreateReferenceRelatedEntitiesLoaderMethod .Invoke( null, new object[] { valueBufferOffset, queryIndex, materializer.Compile() // TODO: Used cached materializer? })); } else { var principalTable = selectExpression.Tables.Count == 1 && selectExpression.Tables .OfType <SelectExpression>() .Any(s => s.Tables.Any(t => t.QuerySource == querySource)) // true when select is wrapped e.g. when RowNumber paging is enabled ? selectExpression.Tables[0] : selectExpression.Tables.Last(t => t.QuerySource == querySource); var canGenerateExists = (selectExpression.Predicate != null || selectExpression.Offset == null) && !IsOrderingOnNonPrincipalKeyProperties( selectExpression.OrderBy, navigation.ForeignKey.PrincipalKey.Properties); foreach (var property in navigation.ForeignKey.PrincipalKey.Properties) { selectExpression .AddToOrderBy( _relationalAnnotationProvider.For(property).ColumnName, property, principalTable, OrderingDirection.Asc); } var targetSelectExpression = _selectExpressionFactory.Create(_queryCompilationContext); targetTableExpression = new TableExpression( targetTableName, _relationalAnnotationProvider.For(targetEntityType).Schema, targetTableAlias, querySource); targetSelectExpression.AddTable(targetTableExpression, createUniqueAlias: false); var materializer = _materializerFactory .CreateMaterializer( targetEntityType, targetSelectExpression, (p, se) => se.AddToProjection( _relationalAnnotationProvider.For(p).ColumnName, p, querySource), querySource: null); if (canGenerateExists) { var subqueryExpression = selectExpression.Clone(); subqueryExpression.ClearProjection(); subqueryExpression.ClearOrderBy(); subqueryExpression.IsProjectStar = false; var subqueryTable = subqueryExpression.Tables.Count == 1 && subqueryExpression.Tables .OfType <SelectExpression>() .Any(s => s.Tables.Any(t => t.QuerySource == querySource)) // true when select is wrapped e.g. when RowNumber paging is enabled ? subqueryExpression.Tables[0] : subqueryExpression.Tables.Last(t => t.QuerySource == querySource); var existsPredicateExpression = new ExistsExpression(subqueryExpression); AddToPredicate(targetSelectExpression, existsPredicateExpression); AddToPredicate(subqueryExpression, BuildJoinEqualityExpression(navigation, targetTableExpression, subqueryTable, querySource)); subqueryExpression.Predicate = compositePredicateExpressionVisitor .Visit(subqueryExpression.Predicate); var pkPropertiesToFkPropertiesMap = navigation.ForeignKey.PrincipalKey.Properties .Zip(navigation.ForeignKey.Properties, (k, v) => new { PkProperty = k, FkProperty = v }) .ToDictionary(x => x.PkProperty, x => x.FkProperty); foreach (var ordering in selectExpression.OrderBy) { // ReSharper disable once PossibleNullReferenceException var principalKeyProperty = ((ordering.Expression as AliasExpression)?.Expression as ColumnExpression).Property; var referencedForeignKeyProperty = pkPropertiesToFkPropertiesMap[principalKeyProperty]; targetSelectExpression .AddToOrderBy( _relationalAnnotationProvider.For(referencedForeignKeyProperty).ColumnName, referencedForeignKeyProperty, targetTableExpression, ordering.OrderingDirection); } } else { var innerJoinSelectExpression = selectExpression.Clone( selectExpression.OrderBy .Select(o => o.Expression) .Last(o => o.IsAliasWithColumnExpression()) .TryGetColumnExpression().TableAlias); innerJoinSelectExpression.ClearProjection(); var innerJoinExpression = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression); LiftOrderBy(innerJoinSelectExpression, targetSelectExpression, innerJoinExpression); innerJoinSelectExpression.IsDistinct = true; innerJoinExpression.Predicate = BuildJoinEqualityExpression( navigation, targetTableExpression, innerJoinExpression, querySource); } targetSelectExpression.Predicate = compositePredicateExpressionVisitor .Visit(targetSelectExpression.Predicate); selectExpression = targetSelectExpression; relatedEntitiesLoaders.Add(qc => (TRelatedEntitiesLoader)_queryCompilationContext.QueryMethodProvider .CreateCollectionRelatedEntitiesLoaderMethod .Invoke( null, new object[] { qc, _shaperCommandContextFactory.Create(() => _querySqlGeneratorFactory.CreateDefault(targetSelectExpression)), queryIndex, materializer.Compile() // TODO: Used cached materializer? })); } } return(relatedEntitiesLoaders); }