diff --git a/src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs b/src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs index cdcae6324f3..27453a50c97 100644 --- a/src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs +++ b/src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs @@ -24,11 +24,8 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal /// public class EntityProjectionExpression : Expression, IPrintableExpression, IAccessExpression { - private readonly IDictionary _propertyExpressionsMap - = new Dictionary(); - - private readonly IDictionary _navigationExpressionsMap - = new Dictionary(); + private readonly Dictionary _propertyExpressionsMap = new(); + private readonly Dictionary _navigationExpressionsMap = new(); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore.InMemory/Query/Internal/EntityProjectionExpression.cs b/src/EFCore.InMemory/Query/Internal/EntityProjectionExpression.cs index 3d308f1dafd..9a458e922b1 100644 --- a/src/EFCore.InMemory/Query/Internal/EntityProjectionExpression.cs +++ b/src/EFCore.InMemory/Query/Internal/EntityProjectionExpression.cs @@ -20,10 +20,8 @@ namespace Microsoft.EntityFrameworkCore.InMemory.Query.Internal /// public class EntityProjectionExpression : Expression, IPrintableExpression { - private readonly IDictionary _readExpressionMap; - - private readonly IDictionary _navigationExpressionsCache - = new Dictionary(); + private readonly IReadOnlyDictionary _readExpressionMap; + private readonly Dictionary _navigationExpressionsCache = new(); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -33,7 +31,7 @@ private readonly IDictionary _navigationExp /// public EntityProjectionExpression( IEntityType entityType, - IDictionary readExpressionMap) + IReadOnlyDictionary readExpressionMap) { EntityType = entityType; _readExpressionMap = readExpressionMap; diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs index 5f98365e3e3..b07de3e2c13 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs @@ -29,9 +29,9 @@ public class InMemoryProjectionBindingExpressionVisitor : ExpressionVisitor private InMemoryQueryExpression _queryExpression; private bool _clientEval; - private readonly IDictionary _projectionMapping - = new Dictionary(); + private Dictionary? _entityProjectionCache; + private readonly Dictionary _projectionMapping = new(); private readonly Stack _projectionMembers = new(); /// @@ -68,6 +68,7 @@ public virtual Expression Translate(InMemoryQueryExpression queryExpression, Exp if (result == QueryCompilationContext.NotTranslatedExpression) { _clientEval = true; + _entityProjectionCache = new(); expandedExpression = _queryableMethodTranslatingExpressionVisitor.ExpandWeakEntities(_queryExpression, expression); result = Visit(expandedExpression); @@ -255,8 +256,14 @@ protected override Expression VisitExtension(Expression extensionExpression) if (_clientEval) { - return entityShaperExpression.Update( - new ProjectionBindingExpression(_queryExpression, _queryExpression.AddToProjection(entityProjectionExpression))); + if (!_entityProjectionCache!.TryGetValue(entityProjectionExpression, out var entityProjectionBinding)) + { + entityProjectionBinding = new ProjectionBindingExpression( + _queryExpression, _queryExpression.AddToProjection(entityProjectionExpression)); + _entityProjectionCache[entityProjectionExpression] = entityProjectionBinding; + } + + return entityShaperExpression.Update(entityProjectionBinding); } _projectionMapping[_projectionMembers.Peek()] = entityProjectionExpression; diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs b/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs index 72a6a0795aa..955b35d6f58 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs @@ -40,9 +40,6 @@ private static readonly PropertyInfo _valueBufferCountMemberInfo private readonly List _clientProjectionExpressions = new(); private readonly List _projectionMappingExpressions = new(); - private readonly IDictionary> _entityProjectionCache - = new Dictionary>(); - private readonly ParameterExpression _valueBufferParameter; private IDictionary _projectionMapping = new Dictionary(); @@ -319,17 +316,12 @@ EntityProjectionExpression UpdateEntityProjection(EntityProjectionExpression ent /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual IDictionary AddToProjection(EntityProjectionExpression entityProjectionExpression) + public virtual IReadOnlyDictionary AddToProjection(EntityProjectionExpression entityProjectionExpression) { - if (!_entityProjectionCache.TryGetValue(entityProjectionExpression, out var indexMap)) + var indexMap = new Dictionary(); + foreach (var property in GetAllPropertiesInHierarchy(entityProjectionExpression.EntityType)) { - indexMap = new Dictionary(); - foreach (var property in GetAllPropertiesInHierarchy(entityProjectionExpression.EntityType)) - { - indexMap[property] = AddToProjection(entityProjectionExpression.BindProperty(property)); - } - - _entityProjectionCache[entityProjectionExpression] = indexMap; + indexMap[property] = AddToProjection(entityProjectionExpression.BindProperty(property)); } return indexMap; @@ -1032,7 +1024,7 @@ public ShaperRemappingExpressionVisitor(IDictionary indexMap + return mappingValue is IReadOnlyDictionary indexMap ? new ProjectionBindingExpression(projectionBindingExpression.QueryExpression, indexMap) : mappingValue is int index ? new ProjectionBindingExpression( diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs index cfdb0b3d42c..f1ecb409555 100644 --- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs +++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs @@ -279,6 +279,12 @@ public static string DerivedTypeTable(object? entityType, object? baseType) GetString("DerivedTypeTable", nameof(entityType), nameof(baseType)), entityType, baseType); + /// + /// Using 'Distinct' operation on a projection containing a collection is not supported. + /// + public static string DistinctOnCollectionNotSupported + => GetString("DistinctOnCollectionNotSupported"); + /// /// The check constraint '{checkConstraint}' cannot be added to the entity type '{entityType}' because another check constraint with the same name already exists. /// @@ -767,28 +773,6 @@ public static string MissingConcurrencyColumn(object? entityType, object? missin GetString("MissingConcurrencyColumn", nameof(entityType), nameof(missingColumn), nameof(table)), entityType, missingColumn, table); - /// - /// Subquery with 'Distinct' can only be translated if projection consists only of entities and their properties, or it contains keys of all entities required to generate results on the client side. Either add '{column}' to the projection, remove complex elements of the projection, or rewrite the query to not use the 'Distinct' operation. - /// - public static string UnableToTranslateSubqueryWithDistinct(object? column) - => string.Format( - GetString("UnableToTranslateSubqueryWithDistinct", nameof(column)), - column); - - /// - /// Subquery with 'GroupBy' can only be translated if grouping key consists only of entities and their properties, or it contains keys of all entities required to generate results on the client side. Either add '{column}' to the grouping key, remove complex elements of the grouping key, or rewrite the query to not use the 'GroupBy' operation. - /// - public static string UnableToTranslateSubqueryWithGroupBy(object? column) - => string.Format( - GetString("UnableToTranslateSubqueryWithGroupBy", nameof(column)), - column); - - /// - /// Using 'Distinct' operation on a projection containing a collection is not supported. - /// - public static string DistinctOnCollectionNotSupported - => GetString("DistinctOnCollectionNotSupported"); - /// /// 'Reverse' could not be translated to the server because there is no ordering on the server side. /// diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx index dc330860c94..c6185e29edf 100644 --- a/src/EFCore.Relational/Properties/RelationalStrings.resx +++ b/src/EFCore.Relational/Properties/RelationalStrings.resx @@ -219,6 +219,9 @@ The entity type '{entityType}' cannot be mapped to a table because it is derived from '{baseType}'. Only base entity types can be mapped to a table. Obsolete + + Using 'Distinct' operation on a projection containing a collection is not supported. + The check constraint '{checkConstraint}' cannot be added to the entity type '{entityType}' because another check constraint with the same name already exists. @@ -621,15 +624,6 @@ Entity type '{entityType}' doesn't contain a property mapped to the store-generated concurrency token column '{missingColumn}' which is used by another entity type sharing the table '{table}'. Add a store-generated property to '{entityType}' which is mapped to the same column; it may be in shadow state. - - Subquery with 'Distinct' can only be translated if projection consists only of entities and their properties, or it contains keys of all entities required to generate results on the client side. Either add '{column}' to the projection, remove complex elements of the projection, or rewrite the query to not use the 'Distinct' operation. - - - Subquery with 'GroupBy' can only be translated if grouping key consists only of entities and their properties, or it contains keys of all entities required to generate results on the client side. Either add '{column}' to the grouping key, remove complex elements of the grouping key, or rewrite the query to not use the 'GroupBy' operation. - - - Using 'Distinct' operation on a projection containing a collection is not supported. - 'Reverse' could not be translated to the server because there is no ordering on the server side. diff --git a/src/EFCore.Relational/Query/EntityProjectionExpression.cs b/src/EFCore.Relational/Query/EntityProjectionExpression.cs index a8353d48f66..3f098ced243 100644 --- a/src/EFCore.Relational/Query/EntityProjectionExpression.cs +++ b/src/EFCore.Relational/Query/EntityProjectionExpression.cs @@ -24,10 +24,8 @@ namespace Microsoft.EntityFrameworkCore.Query /// public class EntityProjectionExpression : Expression { - private readonly IDictionary _propertyExpressionMap = new Dictionary(); - - private readonly IDictionary _ownedNavigationMap - = new Dictionary(); + private readonly IReadOnlyDictionary _propertyExpressionMap; + private readonly Dictionary _ownedNavigationMap = new(); /// /// Creates a new instance of the class. @@ -49,7 +47,7 @@ public EntityProjectionExpression(IEntityType entityType, TableExpressionBase in /// A to generate discriminator for each concrete entity type in hierarchy. public EntityProjectionExpression( IEntityType entityType, - IDictionary propertyExpressionMap, + IReadOnlyDictionary propertyExpressionMap, SqlExpression? discriminatorExpression = null) { Check.NotNull(entityType, nameof(entityType)); diff --git a/src/EFCore.Relational/Query/Internal/EnumHasFlagTranslator.cs b/src/EFCore.Relational/Query/Internal/EnumHasFlagTranslator.cs index 4b215d9a930..1ade5f19b97 100644 --- a/src/EFCore.Relational/Query/Internal/EnumHasFlagTranslator.cs +++ b/src/EFCore.Relational/Query/Internal/EnumHasFlagTranslator.cs @@ -56,6 +56,8 @@ public EnumHasFlagTranslator(ISqlExpressionFactory sqlExpressionFactory) var argument = arguments[0]; return instance.Type != argument.Type ? null + // TODO: If argument is SelectExpression, we need to clone it. + // See issue#24460 : (SqlExpression)_sqlExpressionFactory.Equal(_sqlExpressionFactory.And(instance, argument), argument); } diff --git a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs index 9511c937bb2..0fe1df633c7 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs @@ -35,10 +35,9 @@ private static readonly MethodInfo _getParameterValueMethodInfo private SelectExpression _selectExpression; private SqlExpression[] _existingProjections; private bool _clientEval; + private Dictionary? _entityProjectionCache; - private readonly IDictionary _projectionMapping - = new Dictionary(); - + private readonly Dictionary _projectionMapping = new(); private readonly Stack _projectionMembers = new(); /// @@ -77,6 +76,7 @@ public virtual Expression Translate(SelectExpression selectExpression, Expressio if (result == QueryCompilationContext.NotTranslatedExpression) { _clientEval = true; + _entityProjectionCache = new(); expandedExpression = _queryableMethodTranslatingExpressionVisitor.ExpandWeakEntities(_selectExpression, expression); _existingProjections = _selectExpression.Projection.Select(e => e.Expression).ToArray(); @@ -334,9 +334,14 @@ protected override Expression VisitExtension(Expression extensionExpression) if (_clientEval) { - return entityShaperExpression.Update( - new ProjectionBindingExpression( - _selectExpression, _selectExpression.AddToProjection(entityProjectionExpression))); + if (!_entityProjectionCache!.TryGetValue(entityProjectionExpression, out var entityProjectionBinding)) + { + entityProjectionBinding = new ProjectionBindingExpression( + _selectExpression, _selectExpression.AddToProjection(entityProjectionExpression)); + _entityProjectionCache[entityProjectionExpression] = entityProjectionBinding; + } + + return entityShaperExpression.Update(entityProjectionBinding); } _projectionMapping[_projectionMembers.Peek()] = entityProjectionExpression; diff --git a/src/EFCore.Relational/Query/Internal/TableAliasUniquifyingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/TableAliasUniquifyingExpressionVisitor.cs deleted file mode 100644 index 87d419910f2..00000000000 --- a/src/EFCore.Relational/Query/Internal/TableAliasUniquifyingExpressionVisitor.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq.Expressions; -using Microsoft.EntityFrameworkCore.Internal; -using Microsoft.EntityFrameworkCore.Query.SqlExpressions; - -namespace Microsoft.EntityFrameworkCore.Query.Internal -{ - /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. - /// - public class TableAliasUniquifyingExpressionVisitor : ExpressionVisitor - { - /// - /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to - /// the same compatibility standards as public APIs. It may be changed or removed without notice in - /// any release. You should only use it directly in your code with extreme caution and knowing that - /// doing so can result in application failures when updating to a new Entity Framework Core release. - /// - [return: NotNullIfNotNull("expression")] - public override Expression? Visit(Expression? expression) - { - switch (expression) - { - case ShapedQueryExpression shapedQueryExpression: - return shapedQueryExpression.Update( - UniquifyAliasInSelectExpression((SelectExpression)shapedQueryExpression.QueryExpression), - Visit(shapedQueryExpression.ShaperExpression)); - - case RelationalSplitCollectionShaperExpression relationalSplitCollectionShaperExpression: - return relationalSplitCollectionShaperExpression.Update( - relationalSplitCollectionShaperExpression.ParentIdentifier, - relationalSplitCollectionShaperExpression.ChildIdentifier, - UniquifyAliasInSelectExpression(relationalSplitCollectionShaperExpression.SelectExpression), - Visit(relationalSplitCollectionShaperExpression.InnerShaper)); - - default: - return base.Visit(expression); - } - } - - private SelectExpression UniquifyAliasInSelectExpression(SelectExpression selectExpression) - => (SelectExpression)new ScopedVisitor().Visit(selectExpression); - - private sealed class ScopedVisitor : ExpressionVisitor - { - private readonly ISet _usedAliases = new HashSet(StringComparer.OrdinalIgnoreCase); - - private readonly ISet _visitedTableExpressionBases - = new HashSet(LegacyReferenceEqualityComparer.Instance); - - [return: NotNullIfNotNull("expression")] - public override Expression? Visit(Expression? expression) - { - var visitedExpression = base.Visit(expression); - if (visitedExpression is TableExpressionBase tableExpressionBase - && !_visitedTableExpressionBases.Contains(tableExpressionBase) - && tableExpressionBase.Alias != null) - { - tableExpressionBase.Alias = GenerateUniqueAlias(tableExpressionBase.Alias); - _visitedTableExpressionBases.Add(tableExpressionBase); - } - - return visitedExpression; - } - - private string GenerateUniqueAlias(string currentAlias) - { - if (!_usedAliases.Contains(currentAlias)) - { - _usedAliases.Add(currentAlias); - return currentAlias; - } - - var counter = 0; - var uniqueAlias = currentAlias; - - while (_usedAliases.Contains(uniqueAlias)) - { - uniqueAlias = currentAlias + counter++; - } - - _usedAliases.Add(uniqueAlias); - - return uniqueAlias; - } - } - } -} diff --git a/src/EFCore.Relational/Query/QuerySqlGenerator.cs b/src/EFCore.Relational/Query/QuerySqlGenerator.cs index 36f73049b34..ef43826a241 100644 --- a/src/EFCore.Relational/Query/QuerySqlGenerator.cs +++ b/src/EFCore.Relational/Query/QuerySqlGenerator.cs @@ -145,7 +145,7 @@ private bool IsNonComposedSetOperation(SelectExpression selectExpression) && selectExpression.Projection.Count == setOperation.Source1.Projection.Count && selectExpression.Projection.Select( (pe, index) => pe.Expression is ColumnExpression column - && string.Equals(column.Table.Alias, setOperation.Alias, StringComparison.OrdinalIgnoreCase) + && string.Equals(column.TableAlias, setOperation.Alias, StringComparison.OrdinalIgnoreCase) && string.Equals( column.Name, setOperation.Source1.Projection[index].Alias, StringComparison.OrdinalIgnoreCase)) .All(e => e); @@ -332,7 +332,7 @@ protected override Expression VisitColumn(ColumnExpression columnExpression) Check.NotNull(columnExpression, nameof(columnExpression)); _relationalCommandBuilder - .Append(_sqlGenerationHelper.DelimitIdentifier(columnExpression.Table.Alias!)) + .Append(_sqlGenerationHelper.DelimitIdentifier(columnExpression.TableAlias)) .Append(".") .Append(_sqlGenerationHelper.DelimitIdentifier(columnExpression.Name)); diff --git a/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs b/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs index 1ee10331986..7dfa5916708 100644 --- a/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryTranslationPostprocessor.cs @@ -2,9 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Query.Internal; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query @@ -44,7 +48,10 @@ public override Expression Process(Expression query) query = base.Process(query); query = new SelectExpressionProjectionApplyingExpressionVisitor().Visit(query); query = new CollectionJoinApplyingExpressionVisitor((RelationalQueryCompilationContext)QueryCompilationContext).Visit(query); - query = new TableAliasUniquifyingExpressionVisitor().Visit(query); +#if DEBUG + // TODO: 24460 blocks from enabling this + //query = new TableAliasVerifyingExpressionVisitor().Visit(query); +#endif query = new SelectExpressionPruningExpressionVisitor().Visit(query); query = new SqlExpressionSimplifyingExpressionVisitor(RelationalDependencies.SqlExpressionFactory, _useRelationalNulls).Visit(query); query = new RelationalValueConverterCompensatingExpressionVisitor(RelationalDependencies.SqlExpressionFactory).Visit(query); @@ -67,5 +74,85 @@ public override Expression Process(Expression query) + " instead. If you have a case for optimizations to be performed here, please file an issue on github.com/dotnet/efcore.")] protected virtual Expression OptimizeSqlExpression(Expression query) => query; + + private sealed class TableAliasVerifyingExpressionVisitor : ExpressionVisitor + { + private readonly ScopedVisitor _scopedVisitor = new(); + + // Validates that all aliases are unique inside SelectExpression + // And all aliases are used in without any generated alias being missing + [return: NotNullIfNotNull("expression")] + public override Expression? Visit(Expression? expression) + { + switch (expression) + { + case ShapedQueryExpression shapedQueryExpression: + UniquifyAliasInSelectExpression(shapedQueryExpression.QueryExpression); + Visit(shapedQueryExpression.QueryExpression); + return shapedQueryExpression; + + case RelationalSplitCollectionShaperExpression relationalSplitCollectionShaperExpression: + UniquifyAliasInSelectExpression(relationalSplitCollectionShaperExpression.SelectExpression); + Visit(relationalSplitCollectionShaperExpression.InnerShaper); + return relationalSplitCollectionShaperExpression; + + default: + return base.Visit(expression); + } + } + + private void UniquifyAliasInSelectExpression(Expression selectExpression) + => _scopedVisitor.EntryPoint(selectExpression); + + private sealed class ScopedVisitor : ExpressionVisitor + { + private readonly HashSet _usedAliases = new(StringComparer.OrdinalIgnoreCase); + private readonly HashSet _visitedTableExpressionBases = new(ReferenceEqualityComparer.Instance); + + public Expression EntryPoint(Expression expression) + { + _usedAliases.Clear(); + _visitedTableExpressionBases.Clear(); + + var result = Visit(expression); + + foreach (var group in _usedAliases.GroupBy(e => e[0..1])) + { + if (group.Count() == 1) + { + continue; + } + + var numbers = group.OrderBy(e => e).Skip(1).Select(e => int.Parse(e[1..])).OrderBy(e => e).ToList(); + if (numbers.Count - 1 != numbers[^1]) + { + throw new InvalidOperationException($"Missing alias in the list: {string.Join(",", group.Select(e => e))}"); + } + } + + return result; + } + + [return: NotNullIfNotNull("expression")] + public override Expression? Visit(Expression? expression) + { + var visitedExpression = base.Visit(expression); + if (visitedExpression is TableExpressionBase tableExpressionBase + && !_visitedTableExpressionBases.Contains(tableExpressionBase) + && tableExpressionBase.Alias != null) + { + if (_usedAliases.Contains(tableExpressionBase.Alias)) + { + throw new InvalidOperationException($"Duplicate alias: {tableExpressionBase.Alias}"); + } + _usedAliases.Add(tableExpressionBase.Alias); + + _visitedTableExpressionBases.Add(tableExpressionBase); + } + + return visitedExpression; + } + } + } } } diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index d91df87be09..0094f29d76b 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -1441,13 +1441,8 @@ outerKey is NewArrayExpression newArrayExpression || (entityType.FindDiscriminatorProperty() == null && navigation.DeclaringEntityType.IsStrictlyDerivedFrom(entityShaperExpression.EntityType)); - var propertyExpressions = GetPropertyExpressionFromSameTable( - targetEntityType, table, _selectExpression, identifyingColumn, principalNullable); - if (propertyExpressions != null) - { - innerShaper = new RelationalEntityShaperExpression( - targetEntityType, new EntityProjectionExpression(targetEntityType, propertyExpressions), true); - } + innerShaper = _selectExpression.GenerateWeakEntityShaper( + targetEntityType, table, identifyingColumn.Name, identifyingColumn.Table, principalNullable); } if (innerShaper == null) @@ -1479,10 +1474,9 @@ outerKey is NewArrayExpression newArrayExpression var joinPredicate = _sqlTranslator.Translate(Expression.Equal(outerKey, innerKey))!; _selectExpression.AddLeftJoin(innerSelectExpression, joinPredicate); var leftJoinTable = ((LeftJoinExpression)_selectExpression.Tables.Last()).Table; - var propertyExpressions = GetPropertyExpressionsFromJoinedTable(targetEntityType, table, leftJoinTable); - innerShaper = new RelationalEntityShaperExpression( - targetEntityType, new EntityProjectionExpression(targetEntityType, propertyExpressions), true); + innerShaper = _selectExpression.GenerateWeakEntityShaper( + targetEntityType, table, null, leftJoinTable, makeNullable: true)!; } entityProjectionExpression.AddNavigationBinding(navigation, innerShaper); @@ -1495,80 +1489,6 @@ private static Expression AddConvertToObject(Expression expression) => expression.Type.IsValueType ? Expression.Convert(expression, typeof(object)) : expression; - - private static IDictionary? GetPropertyExpressionFromSameTable( - IEntityType entityType, - ITableBase table, - SelectExpression selectExpression, - ColumnExpression identifyingColumn, - bool nullable) - { - if (identifyingColumn.Table is TableExpression tableExpression) - { - if (!string.Equals(tableExpression.Name, table.Name, StringComparison.OrdinalIgnoreCase)) - { - // Fetch the table for the type which is defining the navigation since dependent would be in that table - tableExpression = selectExpression.Tables - .Select(t => (t as InnerJoinExpression)?.Table ?? (t as LeftJoinExpression)?.Table ?? t) - .Cast() - .First(t => t.Name == table.Name && t.Schema == table.Schema); - } - - var propertyExpressions = new Dictionary(); - foreach (var property in entityType - .GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()) - .SelectMany(t => t.GetDeclaredProperties())) - { - propertyExpressions[property] = new ColumnExpression( - property, table.FindColumn(property)!, tableExpression, nullable || !property.IsPrimaryKey()); - } - - return propertyExpressions; - } - - if (identifyingColumn.Table is SelectExpression subquery) - { - var subqueryIdentifyingColumn = (ColumnExpression)subquery.Projection - .Single(e => string.Equals(e.Alias, identifyingColumn.Name, StringComparison.OrdinalIgnoreCase)) - .Expression; - - var subqueryPropertyExpressions = GetPropertyExpressionFromSameTable( - entityType, table, subquery, subqueryIdentifyingColumn, nullable); - - if (subqueryPropertyExpressions == null) - { - return null; - } - - var newPropertyExpressions = new Dictionary(); - foreach (var item in subqueryPropertyExpressions) - { - newPropertyExpressions[item.Key] = new ColumnExpression( - subquery.Projection[subquery.AddToProjection(item.Value)], subquery); - } - - return newPropertyExpressions; - } - - return null; - } - - private static IDictionary GetPropertyExpressionsFromJoinedTable( - IEntityType entityType, - ITableBase table, - TableExpressionBase tableExpression) - { - var propertyExpressions = new Dictionary(); - foreach (var property in entityType - .GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()) - .SelectMany(t => t.GetDeclaredProperties())) - { - propertyExpressions[property] = new ColumnExpression( - property, table.FindColumn(property)!, tableExpression, nullable: true); - } - - return propertyExpressions; - } } private ShapedQueryExpression TranslateTwoParameterSelector(ShapedQueryExpression source, LambdaExpression resultSelector) diff --git a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs index 0535050707c..ccde34ec354 100644 --- a/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.cs @@ -102,7 +102,7 @@ private static readonly MethodInfo _collectionAccessorAddMethodInfo private readonly ReaderColumn[]? _readerColumns; // States to materialize only once - private readonly IDictionary _variableShaperMapping = new Dictionary(); + private readonly Dictionary _variableShaperMapping = new(ReferenceEqualityComparer.Instance); // There are always entity variables to avoid materializing same entity twice private readonly List _variables = new(); diff --git a/src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs index 75f4dec644b..6a24c5f5f20 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Linq; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; @@ -28,7 +29,9 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions // Class is sealed because there are no public/protected constructors. Can be unsealed if this is changed. public sealed class ColumnExpression : SqlExpression { - internal ColumnExpression(IProperty property, IColumnBase column, TableExpressionBase table, bool nullable) + private readonly TableReferenceExpression _table; + + internal ColumnExpression(IProperty property, IColumnBase column, TableReferenceExpression table, bool nullable) : this( column.Name, table, @@ -38,7 +41,7 @@ internal ColumnExpression(IProperty property, IColumnBase column, TableExpressio { } - internal ColumnExpression(ProjectionExpression subqueryProjection, TableExpressionBase table) + internal ColumnExpression(ProjectionExpression subqueryProjection, TableReferenceExpression table) : this( subqueryProjection.Alias, table, subqueryProjection.Type, subqueryProjection.Expression.TypeMapping!, @@ -54,7 +57,7 @@ private static bool IsNullableProjection(ProjectionExpression projectionExpressi _ => true, }; - private ColumnExpression(string name, TableExpressionBase table, Type type, RelationalTypeMapping typeMapping, bool nullable) + private ColumnExpression(string name, TableReferenceExpression table, Type type, RelationalTypeMapping typeMapping, bool nullable) : base(type, typeMapping) { Check.NotEmpty(name, nameof(name)); @@ -62,7 +65,7 @@ private ColumnExpression(string name, TableExpressionBase table, Type type, Rela Check.NotEmpty(table.Alias, $"{nameof(table)}.{nameof(table.Alias)}"); Name = name; - Table = table; + _table = table; IsNullable = nullable; } @@ -74,7 +77,12 @@ private ColumnExpression(string name, TableExpressionBase table, Type type, Rela /// /// The table from which column is being referenced. /// - public TableExpressionBase Table { get; } + public TableExpressionBase Table => _table.Table; + + /// + /// The alias of the table from which column is being referenced. + /// + public string TableAlias => _table.Alias; /// /// The bool value indicating if this column can have null values. @@ -94,14 +102,24 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) /// /// A new expression which has property set to true. public ColumnExpression MakeNullable() - => new(Name, Table, Type, TypeMapping!, true); + => new(Name, _table, Type, TypeMapping!, true); + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + public void UpdateTableReference(SelectExpression oldSelect, SelectExpression newSelect) + => _table.UpdateTableReference(oldSelect, newSelect); /// protected override void Print(ExpressionPrinter expressionPrinter) { Check.NotNull(expressionPrinter, nameof(expressionPrinter)); - expressionPrinter.Append(Table.Alias!).Append("."); + expressionPrinter.Append(TableAlias).Append("."); expressionPrinter.Append(Name); } @@ -115,14 +133,14 @@ public override bool Equals(object? obj) private bool Equals(ColumnExpression columnExpression) => base.Equals(columnExpression) && Name == columnExpression.Name - && Table.Equals(columnExpression.Table) + && _table.Equals(columnExpression._table) && IsNullable == columnExpression.IsNullable; /// public override int GetHashCode() - => HashCode.Combine(base.GetHashCode(), Name, Table, IsNullable); + => HashCode.Combine(base.GetHashCode(), Name, _table, IsNullable); private string DebuggerDisplay() - => $"{Table.Alias}.{Name}"; + => $"{TableAlias}.{Name}"; } } diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.Helper.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.Helper.cs index 6922d40562d..983f1d81e6e 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.Helper.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.Helper.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; @@ -52,7 +53,7 @@ public bool ContainsOuterReference(SelectExpression selectExpression) } if (expression is ColumnExpression columnExpression - && _outerSelectExpression.ContainsTableReference(columnExpression.Table)) + && _outerSelectExpression.ContainsTableReference(columnExpression)) { _containsOuterReference = true; @@ -149,13 +150,9 @@ private ProjectionBindingExpression Remap(ProjectionBindingExpression projection private ProjectionBindingExpression CreateNewBinding(object binding, Type type) => binding switch { - ProjectionMember projectionMember => new ProjectionBindingExpression( - _queryExpression, projectionMember, type), - + ProjectionMember projectionMember => new ProjectionBindingExpression(_queryExpression, projectionMember, type), int index => new ProjectionBindingExpression(_queryExpression, index, type), - - IDictionary indexMap => new ProjectionBindingExpression(_queryExpression, indexMap), - + IReadOnlyDictionary indexMap => new ProjectionBindingExpression(_queryExpression, indexMap), _ => throw new InvalidOperationException(), }; } @@ -163,11 +160,16 @@ private ProjectionBindingExpression CreateNewBinding(object binding, Type type) private sealed class SqlRemappingVisitor : ExpressionVisitor { private readonly SelectExpression _subquery; - private readonly IDictionary _mappings; + private readonly TableReferenceExpression _tableReferenceExpression; + private readonly Dictionary _mappings; - public SqlRemappingVisitor(IDictionary mappings, SelectExpression subquery) + public SqlRemappingVisitor( + Dictionary mappings, + SelectExpression subquery, + TableReferenceExpression tableReferenceExpression) { _subquery = subquery; + _tableReferenceExpression = tableReferenceExpression; _mappings = mappings; } @@ -189,10 +191,10 @@ when _mappings.TryGetValue(sqlExpression, out var outer): return outer; case ColumnExpression columnExpression - when _subquery.ContainsTableReference(columnExpression.Table): + when _subquery.ContainsTableReference(columnExpression): var index = _subquery.AddToProjection(columnExpression); var projectionExpression = _subquery._projection[index]; - return new ColumnExpression(projectionExpression, _subquery); + return new ColumnExpression(projectionExpression, _tableReferenceExpression); default: return base.Visit(expression); @@ -239,7 +241,7 @@ private sealed class ColumnExpressionFindingExpressionVisitor : ExpressionVisito switch (expression) { case ColumnExpression columnExpression: - var tableAlias = columnExpression.Table.Alias!; + var tableAlias = columnExpression.TableAlias!; if (_columnReferenced!.ContainsKey(tableAlias)) { if (_columnReferenced[tableAlias] == null) @@ -279,5 +281,62 @@ private sealed class ColumnExpressionFindingExpressionVisitor : ExpressionVisito } } } + + private sealed class TableReferenceUpdatingExpressionVisitor : ExpressionVisitor + { + private readonly SelectExpression _oldSelect; + private readonly SelectExpression _newSelect; + + public TableReferenceUpdatingExpressionVisitor(SelectExpression oldSelect, SelectExpression newSelect) + { + _oldSelect = oldSelect; + _newSelect = newSelect; + } + + [return: NotNullIfNotNull("expression")] + public override Expression? Visit(Expression? expression) + { + if (expression is ColumnExpression columnExpression) + { + columnExpression.UpdateTableReference(_oldSelect, _newSelect); + } + + return base.Visit(expression); + } + } + + private sealed class IdentifierComparer : IEqualityComparer<(ColumnExpression Column, ValueComparer Comparer)> + { + public bool Equals((ColumnExpression Column, ValueComparer Comparer) x, (ColumnExpression Column, ValueComparer Comparer) y) + => x.Column.Equals(y.Column); + + public int GetHashCode([DisallowNull] (ColumnExpression Column, ValueComparer Comparer) obj) => obj.Column.GetHashCode(); + } + + private sealed class AliasUniquefier : ExpressionVisitor + { + private readonly HashSet _usedAliases; + + public AliasUniquefier(HashSet usedAliases) + { + _usedAliases = usedAliases; + } + + [return: NotNullIfNotNull("expression")] + public override Expression? Visit(Expression? expression) + { + if (expression is SelectExpression innerSelectExpression) + { + for (var i = 0; i < innerSelectExpression._tableReferences.Count; i++) + { + var newAlias = GenerateUniqueAlias(_usedAliases, innerSelectExpression._tableReferences[i].Alias); + innerSelectExpression._tableReferences[i].Alias = newAlias; + UnwrapJoinExpression(innerSelectExpression._tables[i]).Alias = newAlias; + } + } + + return base.Visit(expression); + } + } } } diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index fb2a6c20c7b..258de2dd521 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -33,7 +32,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions public sealed partial class SelectExpression : TableExpressionBase { private static readonly string _discriminatorColumnAlias = "Discriminator"; - + private static readonly IdentifierComparer _identifierComparer = new(); private static readonly Dictionary _mirroredOperationMap = new() { @@ -45,30 +44,32 @@ public sealed partial class SelectExpression : TableExpressionBase { ExpressionType.GreaterThanOrEqual, ExpressionType.LessThanOrEqual }, }; - private readonly IDictionary> _entityProjectionCache - = new Dictionary>(); - private readonly List _projection = new(); private readonly List _tables = new(); + private readonly List _tableReferences = new(); private readonly List _groupBy = new(); private readonly List _orderings = new(); + private readonly HashSet _usedAliases = new(); + private readonly List<(ColumnExpression Column, ValueComparer Comparer)> _identifier = new(); private readonly List<(ColumnExpression Column, ValueComparer Comparer)> _childIdentifiers = new(); private readonly List _pendingCollections = new(); - private List _tptLeftJoinTables = new(); - private IDictionary _projectionMapping = new Dictionary(); + private readonly List _tptLeftJoinTables = new(); + private Dictionary _projectionMapping = new(); private SelectExpression( string? alias, List projections, List tables, + List tableReferences, List groupBy, List orderings) : base(alias) { _projection = projections; _tables = tables; + _tableReferences = tableReferences; _groupBy = groupBy; _orderings = orderings; } @@ -103,12 +104,13 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre tableExpression = new TableExpression(table); } - _tables.Add(tableExpression); + var tableReferenceExpression = new TableReferenceExpression(this, tableExpression.Alias!); + AddTable(tableExpression, tableReferenceExpression); var propertyExpressions = new Dictionary(); foreach (var property in GetAllPropertiesInHierarchy(entityType)) { - propertyExpressions[property] = CreateColumnExpression(property, table, tableExpression, nullable: false); + propertyExpressions[property] = CreateColumnExpression(property, table, tableReferenceExpression, nullable: false); } var entityProjection = new EntityProjectionExpression(entityType, propertyExpressions); @@ -135,14 +137,16 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre var table = baseType.GetViewOrTableMappings().Single(m => !tables.Contains(m.Table)).Table; tables.Add(table); var tableExpression = new TableExpression(table); + var tableReferenceExpression = new TableReferenceExpression(this, tableExpression.Alias); + foreach (var property in baseType.GetDeclaredProperties()) { - columns[property] = CreateColumnExpression(property, table, tableExpression, nullable: false); + columns[property] = CreateColumnExpression(property, table, tableReferenceExpression, nullable: false); } if (_tables.Count == 0) { - _tables.Add(tableExpression); + AddTable(tableExpression, tableReferenceExpression); joinColumns = new List(); foreach (var property in keyProperties) { @@ -153,13 +157,13 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre } else { - var innerColumns = keyProperties.Select(p => CreateColumnExpression(p, table, tableExpression, nullable: false)); + var innerColumns = keyProperties.Select(p => CreateColumnExpression(p, table, tableReferenceExpression, nullable: false)); var joinPredicate = joinColumns.Zip(innerColumns, (l, r) => sqlExpressionFactory.Equal(l, r)) .Aggregate((l, r) => sqlExpressionFactory.AndAlso(l, r)); var joinExpression = new InnerJoinExpression(tableExpression, joinPredicate); - _tables.Add(joinExpression); + AddTable(joinExpression, tableReferenceExpression); } } @@ -169,12 +173,13 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre var table = derivedType.GetViewOrTableMappings().Single(m => !tables.Contains(m.Table)).Table; tables.Add(table); var tableExpression = new TableExpression(table); + var tableReferenceExpression = new TableReferenceExpression(this, tableExpression.Alias); foreach (var property in derivedType.GetDeclaredProperties()) { - columns[property] = CreateColumnExpression(property, table, tableExpression, nullable: true); + columns[property] = CreateColumnExpression(property, table, tableReferenceExpression, nullable: true); } - var keyColumns = keyProperties.Select(p => CreateColumnExpression(p, table, tableExpression, nullable: true)).ToArray(); + var keyColumns = keyProperties.Select(p => CreateColumnExpression(p, table, tableReferenceExpression, nullable: true)).ToArray(); if (!derivedType.IsAbstract()) { @@ -189,7 +194,7 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre var joinExpression = new LeftJoinExpression(tableExpression, joinPredicate); _tptLeftJoinTables.Add(_tables.Count); - _tables.Add(joinExpression); + AddTable(joinExpression, tableReferenceExpression); } caseWhenClauses.Reverse(); @@ -218,12 +223,13 @@ internal SelectExpression(IEntityType entityType, TableExpressionBase tableExpre _ => entityType.GetDefaultMappings().Single().Table, }; - _tables.Add(tableExpressionBase); + var tableReferenceExpression = new TableReferenceExpression(this, tableExpressionBase.Alias!); + AddTable(tableExpressionBase, tableReferenceExpression); var propertyExpressions = new Dictionary(); foreach (var property in GetAllPropertiesInHierarchy(entityType)) { - propertyExpressions[property] = CreateColumnExpression(property, table, tableExpressionBase, nullable: false); + propertyExpressions[property] = CreateColumnExpression(property, table, tableReferenceExpression, nullable: false); } var entityProjection = new EntityProjectionExpression(entityType, propertyExpressions); @@ -322,6 +328,63 @@ public void ApplyDistinct() IsDistinct = true; + if (_projection.Count > 0) + { + // _childIdentifiers are empty at this point since we are still in translation phase + if (!_identifier.All(e => _projection.Any(p => e.Column.Equals(p.Expression)))) + { + _identifier.Clear(); + // If identifier is not in the list then we add whole current projection as identifier if all column expressions + if (_projection.All(p => p.Expression is ColumnExpression)) + { + _identifier.AddRange(_projection.Select(p => ((ColumnExpression)p.Expression, p.Expression.TypeMapping!.KeyComparer))); + } + } + } + else + { + if (_identifier.Count > 0) + { + var entityProjectionIdentifiers = new List(); + var entityProjectionValueComparers = new List(); + var otherExpressions = new List(); + foreach (var projectionMapping in _projectionMapping) + { + if (projectionMapping.Value is EntityProjectionExpression entityProjection) + { + var primaryKey = entityProjection.EntityType.FindPrimaryKey(); + // If there are any existing identifier then all entity projection must have a key + // else keyless entity would have wiped identifier when generating join. + Check.DebugAssert(primaryKey != null, "primary key is null."); + foreach (var property in primaryKey.Properties) + { + entityProjectionIdentifiers.Add(entityProjection.BindProperty(property)); + entityProjectionValueComparers.Add(property.GetKeyValueComparer()); + } + } + else if (projectionMapping.Value is SqlExpression sqlExpression) + { + otherExpressions.Add(sqlExpression); + } + } + var allOtherExpressions = entityProjectionIdentifiers.Concat(otherExpressions).ToList(); + if (!_identifier.All(e => allOtherExpressions.Contains(e.Column))) + { + _identifier.Clear(); + if (otherExpressions.Count == 0) + { + // If there are no other expressions then we can use all entityProjectionIdentifiers + _identifier.AddRange(entityProjectionIdentifiers.Zip(entityProjectionValueComparers)); + } + else if (otherExpressions.All(e => e is ColumnExpression)) + { + _identifier.AddRange(entityProjectionIdentifiers.Zip(entityProjectionValueComparers)); + _identifier.AddRange(otherExpressions.Select(e => ((ColumnExpression)e, e.TypeMapping!.KeyComparer))); + } + } + } + } + ClearOrdering(); } @@ -336,29 +399,10 @@ public void ApplyProjection() } var result = new Dictionary(); - foreach (var keyValuePair in _projectionMapping) + var mapping = ApplyProjectionMapping(_projectionMapping); + foreach (var keyValuePair in mapping) { - if (keyValuePair.Value is EntityProjectionExpression entityProjection) - { - var map = new Dictionary(); - foreach (var property in GetAllPropertiesInHierarchy(entityProjection.EntityType)) - { - map[property] = AddToProjection(entityProjection.BindProperty(property)); - } - - if (entityProjection.DiscriminatorExpression != null) - { - AddToProjection(entityProjection.DiscriminatorExpression, _discriminatorColumnAlias); - } - - result[keyValuePair.Key] = Constant(map); - } - else - { - result[keyValuePair.Key] = Constant( - AddToProjection( - (SqlExpression)keyValuePair.Value, keyValuePair.Key.Last?.Name)); - } + result[keyValuePair.Key] = Constant(mapping[keyValuePair.Key]); } _projectionMapping = result; @@ -404,24 +448,19 @@ public Expression GetMappedProjection(ProjectionMember projectionMember) /// /// An entity projection to add. /// A dictionary of to int indicating properties and their corresponding indexes in the projection list. - public IDictionary AddToProjection(EntityProjectionExpression entityProjection) + public IReadOnlyDictionary AddToProjection(EntityProjectionExpression entityProjection) { Check.NotNull(entityProjection, nameof(entityProjection)); - if (!_entityProjectionCache.TryGetValue(entityProjection, out var dictionary)) + var dictionary = new Dictionary(); + foreach (var property in GetAllPropertiesInHierarchy(entityProjection.EntityType)) { - dictionary = new Dictionary(); - foreach (var property in GetAllPropertiesInHierarchy(entityProjection.EntityType)) - { - dictionary[property] = AddToProjection(entityProjection.BindProperty(property)); - } - - if (entityProjection.DiscriminatorExpression != null) - { - AddToProjection(entityProjection.DiscriminatorExpression, _discriminatorColumnAlias); - } + dictionary[property] = AddToProjection(entityProjection.BindProperty(property)); + } - _entityProjectionCache[entityProjection] = dictionary; + if (entityProjection.DiscriminatorExpression != null) + { + AddToProjection(entityProjection.DiscriminatorExpression, _discriminatorColumnAlias); } return dictionary; @@ -449,11 +488,11 @@ private int AddToProjection(SqlExpression sqlExpression, string? alias) var baseAlias = !string.IsNullOrEmpty(alias) ? alias - : (sqlExpression as ColumnExpression)?.Name ?? (Alias != null ? "c" : null); + : (sqlExpression as ColumnExpression)?.Name; if (Alias != null) { + baseAlias ??= "c"; var counter = 0; - Check.DebugAssert(baseAlias != null, "baseAlias should be non-null since this is a subquery."); var currentAlias = baseAlias; while (_projection.Any(pe => string.Equals(pe.Alias, currentAlias, StringComparison.OrdinalIgnoreCase))) @@ -464,6 +503,7 @@ private int AddToProjection(SqlExpression sqlExpression, string? alias) baseAlias = currentAlias; } + sqlExpression = AssignUniqueAliases(sqlExpression); _projection.Add(new ProjectionExpression(sqlExpression, baseAlias ?? "")); return _projection.Count - 1; @@ -489,14 +529,12 @@ public Expression AddSingleProjection(ShapedQueryExpression shapedQueryExpressio if (innerSelectExpression.Projection.Any()) { var index = innerSelectExpression.AddToProjection(sentinelExpression); - dummyProjection = new ProjectionBindingExpression( - innerSelectExpression, index, sentinelNullableType); + dummyProjection = new ProjectionBindingExpression(innerSelectExpression, index, sentinelNullableType); } else { innerSelectExpression._projectionMapping[new ProjectionMember()] = sentinelExpression; - dummyProjection = new ProjectionBindingExpression( - innerSelectExpression, new ProjectionMember(), sentinelNullableType); + dummyProjection = new ProjectionBindingExpression(innerSelectExpression, new ProjectionMember(), sentinelNullableType); } var defaultResult = shapedQueryExpression.ResultCardinality == ResultCardinality.SingleOrDefault @@ -504,7 +542,12 @@ public Expression AddSingleProjection(ShapedQueryExpression shapedQueryExpressio : Block( Throw( New( - typeof(InvalidOperationException).GetConstructors().Single(ci => ci.GetParameters().Count() == 1), + typeof(InvalidOperationException).GetConstructors() + .Single(ci => + { + var parameters = ci.GetParameters(); + return parameters.Length == 1 && parameters[0].ParameterType == typeof(string); + }), Constant(CoreStrings.SequenceContainsNoElements))), Default(shaperExpression.Type)); @@ -515,6 +558,8 @@ public Expression AddSingleProjection(ShapedQueryExpression shapedQueryExpressio } var remapper = new ProjectionBindingExpressionRemappingExpressionVisitor(this); + // Pending collections from inner are lifted to outer when adding join + // So we need to update offsets in shaper var pendingCollectionOffset = _pendingCollections.Count; AddJoin(JoinType.OuterApply, ref innerSelectExpression); var projectionCount = innerSelectExpression.Projection.Count; @@ -525,11 +570,7 @@ public Expression AddSingleProjection(ShapedQueryExpression shapedQueryExpressio for (var i = 0; i < projectionCount; i++) { var projectionToAdd = innerSelectExpression.Projection[i].Expression; - if (projectionToAdd is ColumnExpression column) - { - projectionToAdd = column.MakeNullable(); - } - + projectionToAdd = MakeNullable(projectionToAdd, nullable: true); indexMap[i] = AddToProjection(projectionToAdd); } @@ -537,27 +578,7 @@ public Expression AddSingleProjection(ShapedQueryExpression shapedQueryExpressio } else { - var mapping = new Dictionary(); - foreach (var projection in innerSelectExpression._projectionMapping) - { - var projectionMember = projection.Key; - var projectionToAdd = projection.Value; - - if (projectionToAdd is EntityProjectionExpression entityProjection) - { - mapping[projectionMember] = AddToProjection(entityProjection.MakeNullable()); - } - else - { - if (projectionToAdd is ColumnExpression column) - { - projectionToAdd = column.MakeNullable(); - } - - mapping[projectionMember] = AddToProjection((SqlExpression)projectionToAdd); - } - } - + var mapping = ApplyProjectionMapping(innerSelectExpression._projectionMapping, makeNullable: true); shaperExpression = remapper.RemapProjectionMember(shaperExpression, mapping, pendingCollectionOffset); } @@ -648,10 +669,9 @@ public CollectionShaperExpression AddCollectionProjection( } var parentIdentifier = GetIdentifierAccessor(this, identifierFromParent).Item1; + // We apply projection here because the outer level visitor does not visit this. innerSelectExpression.ApplyProjection(); - RemapIdentifiers(innerSelectExpression); - for (var i = 0; i < identifierFromParent.Count; i++) { AppendOrdering(new OrderingExpression(identifierFromParent[i].Column, ascending: true)); @@ -659,8 +679,9 @@ public CollectionShaperExpression AddCollectionProjection( // Copy over ordering from previous collections var innerOrderingExpressions = new List(); - foreach (var table in innerSelectExpression.Tables) + for (var i = 0; i < innerSelectExpression.Tables.Count; i++) { + var table = innerSelectExpression.Tables[i]; if (table is InnerJoinExpression collectionJoinExpression && collectionJoinExpression.Table is SelectExpression collectionSelectExpression && collectionSelectExpression.Predicate != null @@ -669,11 +690,15 @@ public CollectionShaperExpression AddCollectionProjection( && rowNumberSubquery.Projection.Select(pe => pe.Expression) .OfType().SingleOrDefault() is RowNumberExpression rowNumberExpression) { + var collectionSelectExpressionTableReference = innerSelectExpression._tableReferences[i]; + var rowNumberSubqueryTableReference = collectionSelectExpression._tableReferences.Single(); foreach (var partition in rowNumberExpression.Partitions) { innerOrderingExpressions.Add( new OrderingExpression( - collectionSelectExpression.GenerateOuterColumn(rowNumberSubquery.GenerateOuterColumn(partition)), + collectionSelectExpression.GenerateOuterColumn( + collectionSelectExpressionTableReference, + rowNumberSubquery.GenerateOuterColumn(rowNumberSubqueryTableReference, partition)), ascending: true)); } @@ -682,7 +707,8 @@ public CollectionShaperExpression AddCollectionProjection( innerOrderingExpressions.Add( new OrderingExpression( collectionSelectExpression.GenerateOuterColumn( - rowNumberSubquery.GenerateOuterColumn(ordering.Expression)), + collectionSelectExpressionTableReference, + rowNumberSubquery.GenerateOuterColumn(rowNumberSubqueryTableReference, ordering.Expression)), ordering.IsAscending)); } } @@ -691,6 +717,7 @@ public CollectionShaperExpression AddCollectionProjection( && collectionApplyExpression.Table is SelectExpression collectionSelectExpression2 && collectionSelectExpression2.Orderings.Count > 0) { + var collectionSelectExpressionTableReference = innerSelectExpression._tableReferences[i]; foreach (var ordering in collectionSelectExpression2.Orderings) { if (innerSelectExpression._identifier.Any(e => e.Column.Equals(ordering.Expression))) @@ -700,7 +727,7 @@ public CollectionShaperExpression AddCollectionProjection( innerOrderingExpressions.Add( new OrderingExpression( - collectionSelectExpression2.GenerateOuterColumn(ordering.Expression), + collectionSelectExpression2.GenerateOuterColumn(collectionSelectExpressionTableReference, ordering.Expression), ordering.IsAscending)); } } @@ -745,18 +772,14 @@ public CollectionShaperExpression AddCollectionProjection( } else { - var parentIdentifierList = _identifier.Except(_childIdentifiers).ToList(); + var parentIdentifierList = _identifier.Except(_childIdentifiers, _identifierComparer).ToList(); var (parentIdentifier, parentIdentifierValueComparers) = GetIdentifierAccessor(this, parentIdentifierList); var (outerIdentifier, outerIdentifierValueComparers) = GetIdentifierAccessor(this, _identifier); - var innerClientEval = innerSelectExpression.Projection.Count > 0; - innerSelectExpression.ApplyProjection(); - - RemapIdentifiers(innerSelectExpression); if (collectionIndex == 0) { - foreach (var identifier in parentIdentifierList) + foreach (var identifier in _identifier) { AppendOrdering(new OrderingExpression(identifier.Column, ascending: true)); } @@ -772,11 +795,15 @@ public CollectionShaperExpression AddCollectionProjection( && rowNumberSubquery.Projection.Select(pe => pe.Expression) .OfType().SingleOrDefault() is RowNumberExpression rowNumberExpression) { + var collectionSelectExpressionTableReference = innerSelectExpression._tableReferences.Single(); + var rowNumberSubqueryTableReference = collectionSelectExpression._tableReferences.Single(); foreach (var partition in rowNumberExpression.Partitions) { innerOrderingExpressions.Add( new OrderingExpression( - collectionSelectExpression.GenerateOuterColumn(rowNumberSubquery.GenerateOuterColumn(partition)), + collectionSelectExpression.GenerateOuterColumn( + collectionSelectExpressionTableReference, + rowNumberSubquery.GenerateOuterColumn(rowNumberSubqueryTableReference, partition)), ascending: true)); } @@ -784,13 +811,16 @@ public CollectionShaperExpression AddCollectionProjection( { innerOrderingExpressions.Add( new OrderingExpression( - collectionSelectExpression.GenerateOuterColumn(rowNumberSubquery.GenerateOuterColumn(ordering.Expression)), + collectionSelectExpression.GenerateOuterColumn( + collectionSelectExpressionTableReference, + rowNumberSubquery.GenerateOuterColumn(rowNumberSubqueryTableReference, ordering.Expression)), ordering.IsAscending)); } } else if (joinedTable is SelectExpression collectionSelectExpression2 && collectionSelectExpression2.Orderings.Count > 0) { + var collectionSelectExpressionTableReference = innerSelectExpression._tableReferences.Single(); foreach (var ordering in collectionSelectExpression2.Orderings) { if (innerSelectExpression._identifier.Any(e => e.Column.Equals(ordering.Expression))) @@ -800,7 +830,7 @@ public CollectionShaperExpression AddCollectionProjection( innerOrderingExpressions.Add( new OrderingExpression( - collectionSelectExpression2.GenerateOuterColumn(ordering.Expression), + collectionSelectExpression2.GenerateOuterColumn(collectionSelectExpressionTableReference, ordering.Expression), ordering.IsAscending)); } } @@ -811,47 +841,29 @@ public CollectionShaperExpression AddCollectionProjection( foreach (var ordering in innerOrderingExpressions) { - AppendOrdering(ordering.Update(MakeNullable(ordering.Expression))); + AppendOrdering(ordering.Update(MakeNullable(ordering.Expression, nullable: true))); } var remapper = new ProjectionBindingExpressionRemappingExpressionVisitor(this); - var innerProjectionCount = innerSelectExpression.Projection.Count; - var indexMap = new int[innerProjectionCount]; - for (var i = 0; i < innerProjectionCount; i++) + // Outer projection are already populated + if (innerSelectExpression.Projection.Count > 0) { - indexMap[i] = AddToProjection(MakeNullable(innerSelectExpression.Projection[i].Expression)); - } + // Add inner to projection and update indexes + var indexMap = new int[innerSelectExpression.Projection.Count]; + for (var i = 0; i < innerSelectExpression.Projection.Count; i++) + { + var projectionToAdd = innerSelectExpression.Projection[i].Expression; + projectionToAdd = MakeNullable(projectionToAdd, nullable: true); + indexMap[i] = AddToProjection(projectionToAdd); + } - if (innerClientEval) - { - innerShaper = remapper.RemapIndex(innerShaper, indexMap, pendingCollectionOffset: 0); + innerShaper = remapper.RemapIndex(innerShaper, indexMap); } else { - var mapping = new Dictionary(); - foreach (var projection in innerSelectExpression._projectionMapping) - { - var value = ((ConstantExpression)projection.Value).Value; - object? mappedValue = null; - if (value is int index) - { - mappedValue = indexMap[index]; - } - else if (value is IDictionary entityIndexMap) - { - var newEntityIndexMap = new Dictionary(); - foreach (var item in entityIndexMap) - { - newEntityIndexMap[item.Key] = indexMap[item.Value]; - } - - mappedValue = newEntityIndexMap; - } - - mapping[projection.Key] = mappedValue!; - } - - innerShaper = remapper.RemapProjectionMember(innerShaper, mapping, pendingCollectionOffset: 0); + // Apply inner projection mapping and convert projection member binding to indexes + var mapping = ApplyProjectionMapping(innerSelectExpression._projectionMapping, makeNullable: true); + innerShaper = remapper.RemapProjectionMember(innerShaper, mapping); } innerShaper = new EntityShaperNullableMarkingExpressionVisitor().Visit(innerShaper); @@ -859,7 +871,7 @@ public CollectionShaperExpression AddCollectionProjection( var (selfIdentifier, selfIdentifierValueComparers) = GetIdentifierAccessor( this, innerSelectExpression._identifier - .Except(innerSelectExpression._childIdentifiers) + .Except(innerSelectExpression._childIdentifiers, _identifierComparer) .Select(e => (e.Column.MakeNullable(), e.Comparer))); foreach (var identifier in innerSelectExpression._identifier) @@ -877,81 +889,6 @@ public CollectionShaperExpression AddCollectionProjection( return result; } - static SqlExpression MakeNullable(SqlExpression sqlExpression) - => sqlExpression is ColumnExpression column ? column.MakeNullable() : sqlExpression; - - static void RemapIdentifiers(SelectExpression innerSelectExpression) - { - if (innerSelectExpression.IsDistinct - || innerSelectExpression.GroupBy.Count > 0) - { - if (!IdentifiersInProjection(innerSelectExpression, out var missingIdentifier)) - { - // we can safely clear identifiers here - child identifiers will always be empty at this point - // - nested collection scenarios where distinct is applied after projection are blocked - // since we can't translate them in any meaningful way - // - if distinct is applied before the projection, pushdown happens which guarantees child identifiers to be empty - // - for groupby we only support aggregate scenarios so collection can never happen in the projection - if (innerSelectExpression.IsDistinct) - { - if (innerSelectExpression._projection.All(p => p.Expression is ColumnExpression)) - { - innerSelectExpression._identifier.Clear(); - foreach (var projection in innerSelectExpression._projection) - { - innerSelectExpression._identifier.Add(((ColumnExpression)projection.Expression, projection.Expression.TypeMapping!.Comparer)); - } - } - else - { - throw new InvalidOperationException( - RelationalStrings.UnableToTranslateSubqueryWithDistinct( - missingIdentifier.Table.Alias + "." + missingIdentifier.Name)); - } - } - else - { - if (innerSelectExpression.GroupBy.All(g => g is ColumnExpression)) - { - innerSelectExpression._identifier.Clear(); - foreach (var grouping in innerSelectExpression.GroupBy) - { - innerSelectExpression._identifier.Add(((ColumnExpression)grouping, grouping.TypeMapping!.Comparer)); - } - } - else - { - throw new InvalidOperationException( - RelationalStrings.UnableToTranslateSubqueryWithGroupBy( - missingIdentifier.Table.Alias + "." + missingIdentifier.Name)); - } - } - } - } - } - - static bool IdentifiersInProjection( - SelectExpression selectExpression, - [NotNullWhen(false)] out ColumnExpression? missingIdentifier) - { - var innerSelectProjectionExpressions = selectExpression._projection.Select(p => p.Expression).ToList(); - foreach (var innerSelectIdentifier in selectExpression._identifier) - { - if (!innerSelectProjectionExpressions.Contains(innerSelectIdentifier.Column) - && (selectExpression.GroupBy.Count == 0 - || !selectExpression.GroupBy.Contains(innerSelectIdentifier.Column))) - { - missingIdentifier = innerSelectIdentifier.Column; - - return false; - } - } - - missingIdentifier = null; - - return true; - } - static (Expression, IReadOnlyList) GetIdentifierAccessor( SelectExpression selectExpression, IEnumerable<(ColumnExpression Column, ValueComparer Comparer)> identifyingProjection) @@ -993,9 +930,11 @@ public void ApplyPredicate(SqlExpression expression) if (Limit != null || Offset != null) { - expression = new SqlRemappingVisitor(PushdownIntoSubquery(), (SelectExpression)Tables[0]).Remap(expression); + expression = PushdownIntoSubqueryInternal().Remap(expression); } + expression = AssignUniqueAliases(expression); + if (_groupBy.Count > 0) { Having = Having == null @@ -1031,6 +970,15 @@ public void ApplyGrouping(Expression keySelector) ClearOrdering(); AppendGroupBy(keySelector); + + if (!_identifier.All(e => _groupBy.Contains(e.Column))) + { + _identifier.Clear(); + if (_groupBy.All(e => e is ColumnExpression)) + { + _identifier.AddRange(_groupBy.Select(e => ((ColumnExpression)e, e.TypeMapping!.KeyComparer))); + } + } } private void AppendGroupBy(Expression keySelector) @@ -1088,13 +1036,11 @@ public void ApplyOrdering(OrderingExpression orderingExpression) || Limit != null || Offset != null) { - orderingExpression = orderingExpression.Update( - new SqlRemappingVisitor(PushdownIntoSubquery(), (SelectExpression)Tables[0]) - .Remap(orderingExpression.Expression)); + orderingExpression = orderingExpression.Update(PushdownIntoSubqueryInternal().Remap(orderingExpression.Expression)); } _orderings.Clear(); - _orderings.Add(orderingExpression); + _orderings.Add(orderingExpression.Update(AssignUniqueAliases(orderingExpression.Expression))); } /// @@ -1107,7 +1053,7 @@ public void AppendOrdering(OrderingExpression orderingExpression) if (_orderings.FirstOrDefault(o => o.Expression.Equals(orderingExpression.Expression)) == null) { - _orderings.Add(orderingExpression); + _orderings.Add(orderingExpression.Update(AssignUniqueAliases(orderingExpression.Expression))); } } @@ -1222,11 +1168,9 @@ public void ApplyUnion(SelectExpression source2, bool distinct) private void ApplySetOperation(SetOperationType setOperationType, SelectExpression select2, bool distinct) { - // TODO: throw if there are pending collection joins - // TODO: What happens when applying set operations on 2 queries with one of them being grouping - + // TODO: Introduce clone method? See issue#24460 var select1 = new SelectExpression( - null, new List(), _tables.ToList(), _groupBy.ToList(), _orderings.ToList()) + null, new List(), _tables.ToList(), _tableReferences.ToList(), _groupBy.ToList(), _orderings.ToList()) { IsDistinct = IsDistinct, Predicate = Predicate, @@ -1234,18 +1178,33 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi Offset = Offset, Limit = Limit }; - + Offset = null; + Limit = null; + IsDistinct = false; + Predicate = null; + Having = null; + _groupBy.Clear(); + _orderings.Clear(); + _tables.Clear(); + _tableReferences.Clear(); select1._projectionMapping = new Dictionary(_projectionMapping); _projectionMapping.Clear(); select1._identifier.AddRange(_identifier); _identifier.Clear(); + var outerIdentifiers = select1._identifier.Count == select2._identifier.Count + ? new ColumnExpression?[select1._identifier.Count] + : Array.Empty(); if (select1.Orderings.Count != 0 || select1.Limit != null || select1.Offset != null) { + // If we are pushing down here, we need to make sure to assign unique alias to subquery also. + var subqueryAlias = GenerateUniqueAlias(_usedAliases, "t"); select1.PushdownIntoSubquery(); + select1._tables[0].Alias = subqueryAlias; + select1._tableReferences[0].Alias = subqueryAlias; select1.ClearOrdering(); } @@ -1256,17 +1215,25 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi select2.PushdownIntoSubquery(); select2.ClearOrdering(); } + // select1 already has unique aliases. We unique-fy select2 and set operation alias. + select2 = (SelectExpression)new AliasUniquefier(_usedAliases).Visit(select2); + var setOperationAlias = GenerateUniqueAlias(_usedAliases, "t"); var setExpression = setOperationType switch { - SetOperationType.Except => (SetOperationBase)new ExceptExpression("t", select1, select2, distinct), - SetOperationType.Intersect => new IntersectExpression("t", select1, select2, distinct), - SetOperationType.Union => new UnionExpression("t", select1, select2, distinct), + SetOperationType.Except => (SetOperationBase)new ExceptExpression(setOperationAlias, select1, select2, distinct), + SetOperationType.Intersect => new IntersectExpression(setOperationAlias, select1, select2, distinct), + SetOperationType.Union => new UnionExpression(setOperationAlias, select1, select2, distinct), _ => throw new InvalidOperationException(CoreStrings.InvalidSwitch(nameof(setOperationType), setOperationType)) }; + var tableReferenceExpression = new TableReferenceExpression(this, setExpression.Alias); + _tables.Add(setExpression); + _tableReferences.Add(tableReferenceExpression); if (_projection.Any() - || select2._projection.Any()) + || select2._projection.Any() + || _pendingCollections.Any() + || select2._pendingCollections.Any()) { throw new InvalidOperationException(RelationalStrings.SetOperationsNotAllowedAfterClientEvaluation); } @@ -1278,6 +1245,7 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi throw new InvalidOperationException(RelationalStrings.ProjectionMappingCountMismatch); } + var aliasUniquefier = new AliasUniquefier(_usedAliases); foreach (var joinedMapping in select1._projectionMapping.Join( select2._projectionMapping, kv => kv.Key, @@ -1290,7 +1258,10 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi HandleEntityProjection(joinedMapping.Key, select1, entityProjection1, select2, entityProjection2); continue; } - var innerColumn1 = (SqlExpression)joinedMapping.Value1; + + // We have to unique-fy left side since those projections were never uniquefied + // Right side is unique already when we did it when running select2 through it. + var innerColumn1 = (SqlExpression)aliasUniquefier.Visit(joinedMapping.Value1); var innerColumn2 = (SqlExpression)joinedMapping.Value2; // For now, make sure that both sides output the same store type, otherwise the query may fail. // TODO: with #15586 we'll be able to also allow different store types which are implicitly convertible to one another. @@ -1299,7 +1270,7 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi throw new InvalidOperationException(RelationalStrings.SetOperationsOnDifferentStoreTypes); } - var alias = GenerateUniqueAlias( + var alias = GenerateUniqueColumnAlias( joinedMapping.Key.Last?.Name ?? (innerColumn1 as ColumnExpression)?.Name ?? "c"); @@ -1308,7 +1279,7 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi var innerProjection2 = new ProjectionExpression(innerColumn2, alias); select1._projection.Add(innerProjection1); select2._projection.Add(innerProjection2); - var outerProjection = new ColumnExpression(innerProjection1, setExpression); + var outerProjection = new ColumnExpression(innerProjection1, tableReferenceExpression); if (IsNullableProjection(innerProjection1) || IsNullableProjection(innerProjection2)) @@ -1317,17 +1288,33 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi } _projectionMapping[joinedMapping.Key] = outerProjection; + + if (outerIdentifiers.Length > 0) + { + var index = select1._identifier.FindIndex(e => e.Column.Equals(joinedMapping.Value1)); + if (index != -1) + { + if (select2._identifier[index].Column.Equals(joinedMapping.Value2)) + { + outerIdentifiers[index] = outerProjection; + } + else + { + // If select1 matched but select2 did not then we erase all identifiers + // TODO: We could make this little more robust by allow the indexes to be different. See issue#24475 + // i.e. Identifier ordering being different. + outerIdentifiers = Array.Empty(); + } + } + } } - Offset = null; - Limit = null; - IsDistinct = false; - Predicate = null; - Having = null; - _groupBy.Clear(); - _orderings.Clear(); - _tables.Clear(); - _tables.Add(setExpression); + if (distinct + && outerIdentifiers.Length > 0 + && outerIdentifiers.All(e => e != null)) + { + _identifier.AddRange(outerIdentifiers.Zip(select1._identifier, (c, i) => (c!, i.Comparer))); + } void HandleEntityProjection( ProjectionMember projectionMember, @@ -1344,70 +1331,59 @@ void HandleEntityProjection( var propertyExpressions = new Dictionary(); foreach (var property in GetAllPropertiesInHierarchy(projection1.EntityType)) { - propertyExpressions[property] = GenerateColumnProjection( - select1, projection1.BindProperty(property), - select2, projection2.BindProperty(property)); + var column1 = projection1.BindProperty(property); + var column2 = projection2.BindProperty(property); + var alias = GenerateUniqueColumnAlias(column1.Name); + var innerProjection = new ProjectionExpression(column1, alias); + select1._projection.Add(innerProjection); + select2._projection.Add(new ProjectionExpression(column2, alias)); + var outerExpression = new ColumnExpression(innerProjection, tableReferenceExpression); + if (column1.IsNullable + || column2.IsNullable) + { + outerExpression = outerExpression.MakeNullable(); + } + + propertyExpressions[property] = outerExpression; + + if (outerIdentifiers.Length > 0) + { + var index = select1._identifier.FindIndex(e => e.Column.Equals(column1)); + if (index != -1) + { + if (select2._identifier[index].Column.Equals(column2)) + { + outerIdentifiers[index] = outerExpression; + } + else + { + // If select1 matched but select2 did not then we erase all identifiers + // TODO: We could make this little more robust by allow the indexes to be different. See issue#24475 + // i.e. Identifier ordering being different. + outerIdentifiers = Array.Empty(); + } + } + } } var discriminatorExpression = projection1.DiscriminatorExpression; if (projection1.DiscriminatorExpression != null && projection2.DiscriminatorExpression != null) { - discriminatorExpression = GenerateDiscriminatorExpression( - select1, projection1.DiscriminatorExpression, - select2, projection2.DiscriminatorExpression, - _discriminatorColumnAlias); + var alias = GenerateUniqueColumnAlias(_discriminatorColumnAlias); + var innerProjection = new ProjectionExpression(projection1.DiscriminatorExpression, alias); + select1._projection.Add(innerProjection); + select2._projection.Add(new ProjectionExpression(projection2.DiscriminatorExpression, alias)); + discriminatorExpression = new ColumnExpression(innerProjection, tableReferenceExpression); } _projectionMapping[projectionMember] = new EntityProjectionExpression( projection1.EntityType, propertyExpressions, discriminatorExpression); } - ColumnExpression GenerateDiscriminatorExpression( - SelectExpression select1, - SqlExpression expression1, - SelectExpression select2, - SqlExpression expression2, - string alias) + string GenerateUniqueColumnAlias(string baseAlias) { - var innerProjection1 = new ProjectionExpression(expression1, alias); - var innerProjection2 = new ProjectionExpression(expression2, alias); - select1._projection.Add(innerProjection1); - select2._projection.Add(innerProjection2); - - return new ColumnExpression(innerProjection1, setExpression); - } - - ColumnExpression GenerateColumnProjection( - SelectExpression select1, - ColumnExpression column1, - SelectExpression select2, - ColumnExpression column2) - { - var alias = GenerateUniqueAlias(column1.Name); - var innerProjection1 = new ProjectionExpression(column1, alias); - var innerProjection2 = new ProjectionExpression(column2, alias); - select1._projection.Add(innerProjection1); - select2._projection.Add(innerProjection2); - var outerProjection = new ColumnExpression(innerProjection1, setExpression); - if (IsNullableProjection(innerProjection1) - || IsNullableProjection(innerProjection2)) - { - outerProjection = outerProjection.MakeNullable(); - } - - var existingIdentifier = select1._identifier.FirstOrDefault(t => t.Column == column1); - if (existingIdentifier != default) - { - _identifier.Add((outerProjection, existingIdentifier.Comparer)); - } - - return outerProjection; - } - - string GenerateUniqueAlias(string baseAlias) - { - var currentAlias = baseAlias ?? ""; + var currentAlias = baseAlias; var counter = 0; while (select1._projection.Any(pe => string.Equals(pe.Alias, currentAlias, StringComparison.OrdinalIgnoreCase))) { @@ -1438,9 +1414,10 @@ public void ApplyDefaultIfEmpty(ISqlExpressionFactory sqlExpressionFactory) new SqlConstantExpression(Constant(null, typeof(string)), null)); var dummySelectExpression = new SelectExpression( - alias: "empty", + alias: "e", new List { new(nullSqlExpression, "empty") }, new List(), + new List(), new List(), new List()); @@ -1457,9 +1434,13 @@ public void ApplyDefaultIfEmpty(ISqlExpressionFactory sqlExpressionFactory) var joinPredicate = sqlExpressionFactory.Equal(sqlExpressionFactory.Constant(1), sqlExpressionFactory.Constant(1)); var joinTable = new LeftJoinExpression(Tables.Single(), joinPredicate); + var joinTableReferenceExpression = _tableReferences.Single(); _tables.Clear(); - _tables.Add(dummySelectExpression); + _tableReferences.Clear(); + AddTable(dummySelectExpression, new TableReferenceExpression(this, dummySelectExpression.Alias!)); + // Do NOT use AddTable here since we are adding the same table which was current as join table we don't need to traverse it. _tables.Add(joinTable); + _tableReferences.Add(joinTableReferenceExpression); var projectionMapping = new Dictionary(); foreach (var projection in _projectionMapping) @@ -1477,6 +1458,7 @@ public void ApplyDefaultIfEmpty(ISqlExpressionFactory sqlExpressionFactory) projectionMapping[projection.Key] = projectionToAdd; } + // ChildIdentifiers shouldn't be required to be updated since during translation they should be empty. for (var i = 0; i < _identifier.Count; i++) { if (_identifier[i].Column is ColumnExpression column) @@ -1485,17 +1467,123 @@ public void ApplyDefaultIfEmpty(ISqlExpressionFactory sqlExpressionFactory) } } - for (var i = 0; i < _childIdentifiers.Count; i++) + _projectionMapping = projectionMapping; + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + internal RelationalEntityShaperExpression? GenerateWeakEntityShaper( + IEntityType entityType, ITableBase table, string? columnName, TableExpressionBase tableExpressionBase, bool makeNullable = true) + { + if (columnName == null) + { + // This is when projections are coming from a joined table. + var propertyExpressions = GetPropertyExpressionsFromJoinedTable( + entityType, table, FindTableReference(this, tableExpressionBase)); + + return new RelationalEntityShaperExpression( + entityType, new EntityProjectionExpression(entityType, propertyExpressions), makeNullable); + } + else { - if (_childIdentifiers[i].Column is ColumnExpression column) + var propertyExpressions = GetPropertyExpressionFromSameTable( + entityType, table, this, tableExpressionBase, columnName, makeNullable); + + return propertyExpressions == null + ? null + : new RelationalEntityShaperExpression( + entityType, new EntityProjectionExpression(entityType, propertyExpressions), makeNullable); + } + + static TableReferenceExpression FindTableReference(SelectExpression selectExpression, TableExpressionBase tableExpression) + { + var tableIndex = selectExpression._tables.FindIndex(e => ReferenceEquals(UnwrapJoinExpression(e), tableExpression)); + return selectExpression._tableReferences[tableIndex]; + } + + static IReadOnlyDictionary? GetPropertyExpressionFromSameTable( + IEntityType entityType, + ITableBase table, + SelectExpression selectExpression, + TableExpressionBase tableExpressionBase, + string columnName, + bool nullable) + { + if (tableExpressionBase is TableExpression tableExpression) { - _childIdentifiers[i] = (column.MakeNullable(), _childIdentifiers[i].Comparer); + if (!string.Equals(tableExpression.Name, table.Name, StringComparison.OrdinalIgnoreCase)) + { + // Fetch the table for the type which is defining the navigation since dependent would be in that table + tableExpression = selectExpression.Tables + .Select(t => (t as JoinExpressionBase)?.Table ?? t) + .Cast() + .First(t => t.Name == table.Name && t.Schema == table.Schema); + } + + var propertyExpressions = new Dictionary(); + var tableReferenceExpression = FindTableReference(selectExpression, tableExpression); + foreach (var property in entityType + .GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()) + .SelectMany(t => t.GetDeclaredProperties())) + { + propertyExpressions[property] = new ColumnExpression( + property, table.FindColumn(property)!, tableReferenceExpression, nullable || !property.IsPrimaryKey()); + } + + return propertyExpressions; + } + + if (tableExpressionBase is SelectExpression subquery) + { + var subqueryIdentifyingColumn = (ColumnExpression)subquery.Projection + .Single(e => string.Equals(e.Alias, columnName, StringComparison.OrdinalIgnoreCase)) + .Expression; + + var subqueryPropertyExpressions = GetPropertyExpressionFromSameTable( + entityType, table, subquery, subqueryIdentifyingColumn.Table, subqueryIdentifyingColumn.Name, nullable); + if (subqueryPropertyExpressions == null) + { + return null; + } + + var newPropertyExpressions = new Dictionary(); + var tableReferenceExpression = FindTableReference(selectExpression, subquery); + foreach (var item in subqueryPropertyExpressions) + { + newPropertyExpressions[item.Key] = new ColumnExpression( + subquery.Projection[subquery.AddToProjection(item.Value)], tableReferenceExpression); + } + + return newPropertyExpressions; } + + return null; } - _projectionMapping = projectionMapping; + static IReadOnlyDictionary GetPropertyExpressionsFromJoinedTable( + IEntityType entityType, + ITableBase table, + TableReferenceExpression tableReferenceExpression) + { + var propertyExpressions = new Dictionary(); + foreach (var property in entityType + .GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()) + .SelectMany(t => t.GetDeclaredProperties())) + { + propertyExpressions[property] = new ColumnExpression( + property, table.FindColumn(property)!, tableReferenceExpression, nullable: true); + } + + return propertyExpressions; + } } + private enum JoinType { InnerJoin, @@ -1525,80 +1613,45 @@ private Expression AddJoin( if (outerClientEval) { - if (innerClientEval) - { - var indexMap = new int[innerSelectExpression.Projection.Count]; - for (var i = 0; i < innerSelectExpression.Projection.Count; i++) - { - var projectionToAdd = innerSelectExpression.Projection[i].Expression; - if (projectionToAdd is ColumnExpression column) - { - projectionToAdd = column.MakeNullable(); - } - - indexMap[i] = AddToProjection(projectionToAdd); - } - - innerShaper = remapper.RemapIndex(innerShaper, indexMap, pendingCollectionOffset); - _projectionMapping.Clear(); - } - else - { - var mapping = new Dictionary(); - foreach (var projection in innerSelectExpression._projectionMapping) - { - var projectionMember = projection.Key; - var projectionToAdd = projection.Value; - - if (projectionToAdd is EntityProjectionExpression entityProjection) - { - mapping[projectionMember] = AddToProjection(entityProjection.MakeNullable()); - } - else - { - if (projectionToAdd is ColumnExpression column) - { - projectionToAdd = column.MakeNullable(); - } - - mapping[projectionMember] = AddToProjection((SqlExpression)projectionToAdd); - } + // Outer projection are already populated + if (innerClientEval) + { + // Add inner to projection and update indexes + var indexMap = new int[innerSelectExpression.Projection.Count]; + for (var i = 0; i < innerSelectExpression.Projection.Count; i++) + { + var projectionToAdd = innerSelectExpression.Projection[i].Expression; + projectionToAdd = MakeNullable(projectionToAdd, innerNullable); + indexMap[i] = AddToProjection(projectionToAdd); } + innerShaper = remapper.RemapIndex(innerShaper, indexMap, pendingCollectionOffset); + } + else + { + // Apply inner projection mapping and convert projection member binding to indexes + var mapping = ApplyProjectionMapping(innerSelectExpression._projectionMapping, innerNullable); innerShaper = remapper.RemapProjectionMember(innerShaper, mapping, pendingCollectionOffset); - _projectionMapping.Clear(); } } else { + // Depending on inner, we may either need to populate outer projection or update projection members if (innerClientEval) { - var mapping = new Dictionary(); - foreach (var projection in _projectionMapping) - { - var projectionToAdd = projection.Value; - - mapping[projection.Key] = projectionToAdd is EntityProjectionExpression entityProjection - ? AddToProjection(entityProjection) - : (object)AddToProjection((SqlExpression)projectionToAdd); - } - + // Since inner proojections are populated, we need to populate outer also + var mapping = ApplyProjectionMapping(_projectionMapping); outerShaper = remapper.RemapProjectionMember(outerShaper, mapping); var indexMap = new int[innerSelectExpression.Projection.Count]; for (var i = 0; i < innerSelectExpression.Projection.Count; i++) { var projectionToAdd = innerSelectExpression.Projection[i].Expression; - if (projectionToAdd is ColumnExpression column) - { - projectionToAdd = column.MakeNullable(); - } - + projectionToAdd = MakeNullable(projectionToAdd, innerNullable); indexMap[i] = AddToProjection(projectionToAdd); } innerShaper = remapper.RemapIndex(innerShaper, indexMap, pendingCollectionOffset); - _projectionMapping.Clear(); } else { @@ -1622,23 +1675,13 @@ private Expression AddJoin( var remappedProjectionMember = projection.Key.Prepend(innerMemberInfo); mapping[projectionMember] = remappedProjectionMember; var projectionToAdd = projection.Value; - if (innerNullable) - { - if (projectionToAdd is EntityProjectionExpression entityProjection) - { - projectionToAdd = entityProjection.MakeNullable(); - } - else if (projectionToAdd is ColumnExpression column) - { - projectionToAdd = column.MakeNullable(); - } - } - + projectionToAdd = MakeNullable(projectionToAdd, innerNullable); projectionMapping[remappedProjectionMember] = projectionToAdd; } innerShaper = remapper.RemapProjectionMember(innerShaper, mapping, pendingCollectionOffset); _projectionMapping = projectionMapping; + innerSelectExpression._projectionMapping.Clear(); } } @@ -1663,88 +1706,82 @@ private void AddJoin( { var limit = innerSelectExpression.Limit; var offset = innerSelectExpression.Offset; - innerSelectExpression.Limit = null; - innerSelectExpression.Offset = null; - - joinPredicate = TryExtractJoinKey(this, innerSelectExpression, allowNonEquality: limit == null && offset == null); - if (joinPredicate != null) + if (!innerSelectExpression.IsDistinct + || (limit == null && offset == null)) { - var containsOuterReference = new SelectExpressionCorrelationFindingExpressionVisitor(this) - .ContainsOuterReference(innerSelectExpression); - if (containsOuterReference) - { - innerSelectExpression.ApplyPredicate(joinPredicate); - joinPredicate = null; - if (limit != null) - { - innerSelectExpression.ApplyLimit(limit); - } + innerSelectExpression.Limit = null; + innerSelectExpression.Offset = null; - if (offset != null) - { - innerSelectExpression.ApplyOffset(offset); - } - } - else + joinPredicate = TryExtractJoinKey(this, innerSelectExpression, allowNonEquality: limit == null && offset == null); + if (joinPredicate != null) { - if (limit != null || offset != null) + var containsOuterReference = new SelectExpressionCorrelationFindingExpressionVisitor(this) + .ContainsOuterReference(innerSelectExpression); + if (!containsOuterReference) { - var partitions = new List(); - GetPartitions(joinPredicate, partitions); - var orderings = innerSelectExpression.Orderings.Count > 0 - ? innerSelectExpression.Orderings - : innerSelectExpression._identifier.Count > 0 - ? innerSelectExpression._identifier.Select(e => new OrderingExpression(e.Column, true)) - : new[] { new OrderingExpression(new SqlFragmentExpression("(SELECT 1)"), true) }; - - var rowNumberExpression = new RowNumberExpression( - partitions, orderings.ToList(), (limit ?? offset)!.TypeMapping); - innerSelectExpression.ClearOrdering(); - - var projectionMappings = innerSelectExpression.PushdownIntoSubquery(); - var subquery = (SelectExpression)innerSelectExpression.Tables[0]; - - joinPredicate = new SqlRemappingVisitor(projectionMappings, subquery).Remap(joinPredicate); - - var outerColumn = subquery.GenerateOuterColumn(rowNumberExpression, "row"); - SqlExpression? offsetPredicate = null; - SqlExpression? limitPredicate = null; - if (offset != null) - { - offsetPredicate = new SqlBinaryExpression( - ExpressionType.LessThan, offset, outerColumn, typeof(bool), joinPredicate.TypeMapping); - } - - if (limit != null) + if (limit != null || offset != null) { + var partitions = new List(); + GetPartitions(innerSelectExpression, joinPredicate, partitions); + var orderings = innerSelectExpression.Orderings.Count > 0 + ? innerSelectExpression.Orderings + : innerSelectExpression._identifier.Count > 0 + ? innerSelectExpression._identifier.Select(e => new OrderingExpression(e.Column, true)) + : new[] { new OrderingExpression(new SqlFragmentExpression("(SELECT 1)"), true) }; + + var rowNumberExpression = new RowNumberExpression( + partitions, orderings.ToList(), (limit ?? offset)!.TypeMapping); + innerSelectExpression.ClearOrdering(); + + joinPredicate = innerSelectExpression.PushdownIntoSubqueryInternal().Remap(joinPredicate); + + var subqueryTableReference = innerSelectExpression._tableReferences.Single(); + var outerColumn = ((SelectExpression)innerSelectExpression.Tables[0]).GenerateOuterColumn( + subqueryTableReference, rowNumberExpression, "row"); + SqlExpression? offsetPredicate = null; + SqlExpression? limitPredicate = null; if (offset != null) { - limit = offset is SqlConstantExpression offsetConstant - && limit is SqlConstantExpression limitConstant - ? (SqlExpression)new SqlConstantExpression( - Constant((int)offsetConstant.Value! + (int)limitConstant.Value!), - limit.TypeMapping) - : new SqlBinaryExpression(ExpressionType.Add, offset, limit, limit.Type, limit.TypeMapping); + offsetPredicate = new SqlBinaryExpression( + ExpressionType.LessThan, offset, outerColumn, typeof(bool), joinPredicate.TypeMapping); + } + + if (limit != null) + { + if (offset != null) + { + limit = offset is SqlConstantExpression offsetConstant + && limit is SqlConstantExpression limitConstant + ? new SqlConstantExpression( + Constant((int)offsetConstant.Value! + (int)limitConstant.Value!), + limit.TypeMapping) + : new SqlBinaryExpression(ExpressionType.Add, offset, limit, limit.Type, limit.TypeMapping); + } + + limitPredicate = new SqlBinaryExpression( + ExpressionType.LessThanOrEqual, outerColumn, limit, typeof(bool), joinPredicate.TypeMapping); } - limitPredicate = new SqlBinaryExpression( - ExpressionType.LessThanOrEqual, outerColumn, limit, typeof(bool), joinPredicate.TypeMapping); + var predicate = offsetPredicate != null + ? limitPredicate != null + ? new SqlBinaryExpression( + ExpressionType.AndAlso, offsetPredicate, limitPredicate, typeof(bool), joinPredicate.TypeMapping) + : offsetPredicate + : limitPredicate; + innerSelectExpression.ApplyPredicate(predicate!); } - var predicate = offsetPredicate != null - ? limitPredicate != null - ? new SqlBinaryExpression( - ExpressionType.AndAlso, offsetPredicate, limitPredicate, typeof(bool), joinPredicate.TypeMapping) - : offsetPredicate - : limitPredicate; - innerSelectExpression.ApplyPredicate(predicate!); + + AddJoin(joinType == JoinType.CrossApply ? JoinType.InnerJoin : JoinType.LeftJoin, + ref innerSelectExpression, joinPredicate); + + return; } - joinType = joinType == JoinType.CrossApply ? JoinType.InnerJoin : JoinType.LeftJoin; + innerSelectExpression.ApplyPredicate(joinPredicate); + joinPredicate = null; } - } - else - { + // Order matters Apply Offset before Limit if (offset != null) { @@ -1758,18 +1795,17 @@ private void AddJoin( } } - // Verify what are the cases of pushdown for inner & outer both sides if (Limit != null || Offset != null || IsDistinct || GroupBy.Count > 0) { - var sqlRemappingVisitor = new SqlRemappingVisitor(PushdownIntoSubquery(), (SelectExpression)Tables[0]); + var sqlRemappingVisitor = PushdownIntoSubqueryInternal(); innerSelectExpression = sqlRemappingVisitor.Remap(innerSelectExpression); joinPredicate = sqlRemappingVisitor.Remap(joinPredicate); } - if (innerSelectExpression.Orderings.Any() + if (innerSelectExpression.Orderings.Count > 0 || innerSelectExpression.Limit != null || innerSelectExpression.Offset != null || innerSelectExpression.IsDistinct @@ -1777,9 +1813,7 @@ private void AddJoin( || innerSelectExpression.Tables.Count > 1 || innerSelectExpression.GroupBy.Count > 0) { - joinPredicate = new SqlRemappingVisitor( - innerSelectExpression.PushdownIntoSubquery(), (SelectExpression)innerSelectExpression.Tables[0]) - .Remap(joinPredicate); + joinPredicate = innerSelectExpression.PushdownIntoSubqueryInternal().Remap(joinPredicate); } if (_identifier.Count > 0 @@ -1795,17 +1829,19 @@ private void AddJoin( _identifier.AddRange(innerSelectExpression._identifier); } } - else if (innerSelectExpression._identifier.Count == 0) + else { // if the subquery that is joined to can't be uniquely identified // then the entire join should also not be marked as non-identifiable _identifier.Clear(); + innerSelectExpression._identifier.Clear(); } var innerTable = innerSelectExpression.Tables.Single(); // Copy over pending collection if in join else that info would be lost. // The calling method is supposed to take care of remapping the shaper so that copied over collection indexes match. _pendingCollections.AddRange(innerSelectExpression._pendingCollections); + innerSelectExpression._pendingCollections.Clear(); var joinTable = joinType switch { @@ -1817,20 +1853,28 @@ private void AddJoin( _ => throw new InvalidOperationException(CoreStrings.InvalidSwitch(nameof(joinType), joinType)) }; - _tables.Add(joinTable); + AddTable(joinTable, innerSelectExpression._tableReferences.Single()); - static void GetPartitions(SqlExpression sqlExpression, List partitions) + static void GetPartitions(SelectExpression selectExpression, SqlExpression sqlExpression, List partitions) { if (sqlExpression is SqlBinaryExpression sqlBinaryExpression) { if (sqlBinaryExpression.OperatorType == ExpressionType.Equal) { - partitions.Add(sqlBinaryExpression.Right); + if (sqlBinaryExpression.Left is ColumnExpression columnExpression + && selectExpression.ContainsTableReference(columnExpression)) + { + partitions.Add(sqlBinaryExpression.Left); + } + else + { + partitions.Add(sqlBinaryExpression.Right); + } } else if (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso) { - GetPartitions(sqlBinaryExpression.Left, partitions); - GetPartitions(sqlBinaryExpression.Right, partitions); + GetPartitions(selectExpression, sqlBinaryExpression.Left, partitions); + GetPartitions(selectExpression, sqlBinaryExpression.Right, partitions); } } } @@ -1854,6 +1898,8 @@ static void GetPartitions(SqlExpression sqlExpression, List parti { joinPredicate = RemoveRedundantNullChecks(joinPredicate, columnExpressions); } + // TODO: verify the case for GroupBy. See issue#24474 + // We extract join predicate from Predicate part but GroupBy would have last Having. Changing predicate can change groupings // we can't convert apply to join in case of distinct and groupby, if the projection doesn't already contain the join keys // since we can't add the missing keys to the projection - only convert to join if all the keys are already there @@ -1941,16 +1987,16 @@ static void GetPartitions(SqlExpression sqlExpression, List parti if (sqlBinaryExpression.Left is ColumnExpression leftColumn && sqlBinaryExpression.Right is ColumnExpression rightColumn) { - if (outer.ContainsTableReference(leftColumn.Table) - && inner.ContainsTableReference(rightColumn.Table)) + if (outer.ContainsTableReference(leftColumn) + && inner.ContainsTableReference(rightColumn)) { columnExpressions.Add(leftColumn); return sqlBinaryExpression; } - if (outer.ContainsTableReference(rightColumn.Table) - && inner.ContainsTableReference(leftColumn.Table)) + if (outer.ContainsTableReference(rightColumn) + && inner.ContainsTableReference(leftColumn)) { columnExpressions.Add(rightColumn); @@ -1968,7 +2014,7 @@ static void GetPartitions(SqlExpression sqlExpression, List parti if (sqlBinaryExpression.OperatorType == ExpressionType.NotEqual) { if (sqlBinaryExpression.Left is ColumnExpression leftNullCheckColumn - && outer.ContainsTableReference(leftNullCheckColumn.Table) + && outer.ContainsTableReference(leftNullCheckColumn) && sqlBinaryExpression.Right is SqlConstantExpression rightConstant && rightConstant.Value == null) { @@ -1976,7 +2022,7 @@ static void GetPartitions(SqlExpression sqlExpression, List parti } if (sqlBinaryExpression.Right is ColumnExpression rightNullCheckColumn - && outer.ContainsTableReference(rightNullCheckColumn.Table) + && outer.ContainsTableReference(rightNullCheckColumn) && sqlBinaryExpression.Left is SqlConstantExpression leftConstant && leftConstant.Value == null) { @@ -2336,31 +2382,50 @@ public void AddOuterApply(SelectExpression innerSelectExpression, Type? transpar /// /// Pushes down the into a subquery. /// - /// A mapping of projections before pushdown to s after pushdown. - public IDictionary PushdownIntoSubquery() + public void PushdownIntoSubquery() + { + PushdownIntoSubqueryInternal(); + } + + private SqlRemappingVisitor PushdownIntoSubqueryInternal() { + var subqueryAlias = GenerateUniqueAlias(_usedAliases, "t"); var subquery = new SelectExpression( - "t", new List(), _tables.ToList(), _groupBy.ToList(), _orderings.ToList()) + subqueryAlias, new List(), _tables.ToList(), _tableReferences.ToList(), _groupBy.ToList(), _orderings.ToList()) { IsDistinct = IsDistinct, Predicate = Predicate, Having = Having, Offset = Offset, - Limit = Limit, - _tptLeftJoinTables = _tptLeftJoinTables + Limit = Limit }; + _tables.Clear(); + _tableReferences.Clear(); + _groupBy.Clear(); + _orderings.Clear(); + IsDistinct = false; + Predicate = null; + Having = null; + Offset = null; + Limit = null; + subquery._tptLeftJoinTables.AddRange(_tptLeftJoinTables); + _tptLeftJoinTables.Clear(); + + var subqueryTableReferenceExpression = new TableReferenceExpression(this, subquery.Alias!); + // Do NOT use AddTable here. The subquery already have unique aliases we don't need to traverse it again to make it unique. + _tables.Add(subquery); + _tableReferences.Add(subqueryTableReferenceExpression); - _tptLeftJoinTables = new List(); - var projectionMap = new Dictionary(); + var projectionMap = new Dictionary(ReferenceEqualityComparer.Instance); - // Projections may be present if added by lifting SingleResult/Enumerable in projection through join + // Projection would be present for client eval. if (_projection.Any()) { var projections = _projection.ToList(); _projection.Clear(); foreach (var projection in projections) { - var outerColumn = subquery.GenerateOuterColumn(projection.Expression, projection.Alias); + var outerColumn = subquery.GenerateOuterColumn(subqueryTableReferenceExpression, projection.Expression, projection.Alias); AddToProjection(outerColumn); projectionMap[projection.Expression] = outerColumn; } @@ -2382,113 +2447,89 @@ public IDictionary PushdownIntoSubquery() else { var innerColumn = (SqlExpression)mapping.Value; - var outerColumn = subquery.GenerateOuterColumn(innerColumn, mapping.Key.Last?.Name); + var outerColumn = subquery.GenerateOuterColumn(subqueryTableReferenceExpression, innerColumn, mapping.Key.Last?.Name); projectionMap[innerColumn] = outerColumn; _projectionMapping[mapping.Key] = outerColumn; } } + if (subquery._groupBy.Count > 0) + { + foreach (var key in subquery._groupBy) + { + projectionMap[key] = subquery.GenerateOuterColumn(subqueryTableReferenceExpression, key); + } + } + var identifiers = _identifier.ToList(); _identifier.Clear(); - - var projectionMapValues = projectionMap.Select(p => p.Value); foreach (var identifier in identifiers) { - if (projectionMap.TryGetValue(identifier.Column, out var outerColumn)) - { - _identifier.Add((outerColumn, identifier.Comparer)); - } - else if (!IsDistinct - && GroupBy.Count == 0 - || (GroupBy.Contains(identifier.Column))) + // Invariant, identifier should not contain term which cannot be projected out. + if (!projectionMap.TryGetValue(identifier.Column, out var outerColumn)) { - outerColumn = subquery.GenerateOuterColumn(identifier.Column); - _identifier.Add((outerColumn, identifier.Comparer)); - } - else - { - // if we can't propagate any identifier - clear them all instead - // when adding collection join we detect this and throw appropriate exception - _identifier.Clear(); - - if (IsDistinct - && projectionMapValues.All(x => x is ColumnExpression)) - { - // for distinct try to use entire projection as identifiers - _identifier.AddRange(projectionMapValues.Select(x => ((ColumnExpression)x, x.TypeMapping!.Comparer))); - } - else if (GroupBy.Count > 0 - && GroupBy.All(x => x is ColumnExpression)) - { - // for group by try to use grouping key as identifiers - _identifier.AddRange(GroupBy.Select(x => ((ColumnExpression)x, x.TypeMapping!.Comparer))); - } - - break; + outerColumn = subquery.GenerateOuterColumn(subqueryTableReferenceExpression, identifier.Column); } + _identifier.Add((outerColumn, identifier.Comparer)); } var childIdentifiers = _childIdentifiers.ToList(); _childIdentifiers.Clear(); - foreach (var identifier in childIdentifiers) { - if (projectionMap.TryGetValue(identifier.Column, out var outerColumn)) + // Invariant, identifier should not contain term which cannot be projected out. + if (!projectionMap.TryGetValue(identifier.Column, out var outerColumn)) { - _childIdentifiers.Add((outerColumn, identifier.Comparer)); + outerColumn = subquery.GenerateOuterColumn(subqueryTableReferenceExpression, identifier.Column); + } + _childIdentifiers.Add((outerColumn, identifier.Comparer)); + } + + foreach (var ordering in subquery._orderings) + { + var orderingExpression = ordering.Expression; + if (projectionMap.TryGetValue(orderingExpression, out var outerColumn)) + { + _orderings.Add(ordering.Update(outerColumn)); } else if (!IsDistinct - && GroupBy.Count == 0 - || (GroupBy.Contains(identifier.Column))) + && GroupBy.Count == 0 || GroupBy.Contains(orderingExpression)) { - outerColumn = subquery.GenerateOuterColumn(identifier.Column); - _childIdentifiers.Add((outerColumn, identifier.Comparer)); + _orderings.Add(ordering.Update(subquery.GenerateOuterColumn(subqueryTableReferenceExpression, orderingExpression))); } else { - // if we can't propagate any identifier - clear them all instead - // when adding collection join we detect this and throw appropriate exception - _childIdentifiers.Clear(); + _orderings.Clear(); break; } } - var pendingCollections = _pendingCollections.ToList(); - _pendingCollections.Clear(); - _pendingCollections.AddRange(pendingCollections.Select(new SqlRemappingVisitor(projectionMap, subquery).Remap)); - - _orderings.Clear(); - // Only lift order by to outer if subquery does not have distinct - if (!subquery.IsDistinct) - { - foreach (var ordering in subquery._orderings) - { - var orderingExpression = ordering.Expression; - if (!projectionMap.TryGetValue(orderingExpression, out var outerColumn)) - { - outerColumn = subquery.GenerateOuterColumn(orderingExpression); - } - - _orderings.Add(ordering.Update(outerColumn)); - } - } - if (subquery.Offset == null && subquery.Limit == null) { subquery.ClearOrdering(); } - Offset = null; - Limit = null; - IsDistinct = false; - Predicate = null; - Having = null; - _tables.Clear(); - _tables.Add(subquery); - _groupBy.Clear(); + // Remap tableReferences in inner + foreach (var tableReference in subquery._tableReferences) + { + tableReference.UpdateTableReference(this, subquery); + } + + var tableReferenceUpdatingExpressionVisitor = new TableReferenceUpdatingExpressionVisitor(this, subquery); + var sqlRemappingVisitor = new SqlRemappingVisitor(projectionMap, subquery, subqueryTableReferenceExpression); + tableReferenceUpdatingExpressionVisitor.Visit(subquery); + + var pendingCollections = _pendingCollections.ToList(); + _pendingCollections.Clear(); + foreach (var collection in pendingCollections) + { + // We need to update tableReferences first in case the collection has correlated element to this select expression + _pendingCollections.Add(sqlRemappingVisitor.Remap( + (SelectExpression)tableReferenceUpdatingExpressionVisitor.Visit(collection)!)); + } - return projectionMap; + return sqlRemappingVisitor; EntityProjectionExpression LiftEntityProjectionFromSubquery(EntityProjectionExpression entityProjection) { @@ -2496,7 +2537,7 @@ EntityProjectionExpression LiftEntityProjectionFromSubquery(EntityProjectionExpr foreach (var property in GetAllPropertiesInHierarchy(entityProjection.EntityType)) { var innerColumn = entityProjection.BindProperty(property); - var outerColumn = subquery.GenerateOuterColumn(innerColumn); + var outerColumn = subquery.GenerateOuterColumn(subqueryTableReferenceExpression, innerColumn); projectionMap[innerColumn] = outerColumn; propertyExpressions[property] = outerColumn; } @@ -2505,7 +2546,7 @@ EntityProjectionExpression LiftEntityProjectionFromSubquery(EntityProjectionExpr if (entityProjection.DiscriminatorExpression != null) { discriminatorExpression = subquery.GenerateOuterColumn( - entityProjection.DiscriminatorExpression, _discriminatorColumnAlias); + subqueryTableReferenceExpression, entityProjection.DiscriminatorExpression, _discriminatorColumnAlias); projectionMap[entityProjection.DiscriminatorExpression] = discriminatorExpression; } @@ -2547,7 +2588,7 @@ public bool IsNonComposedFromSql() && Tables[0] is FromSqlExpression fromSql && Projection.All( pe => pe.Expression is ColumnExpression column - && string.Equals(fromSql.Alias, column.Table.Alias, StringComparison.OrdinalIgnoreCase)) + && string.Equals(fromSql.Alias, column.TableAlias, StringComparison.OrdinalIgnoreCase)) && _projectionMapping.TryGetValue(new ProjectionMember(), out var mapping) && mapping.Type == typeof(Dictionary); @@ -2579,19 +2620,13 @@ private SelectExpression Prune(IReadOnlyCollection? referencedColumns = if (referencedColumns != null && !IsDistinct) { - var indexesToRemove = new List(); for (var i = _projection.Count - 1; i >= 0; i--) { if (!referencedColumns.Contains(_projection[i].Alias)) { - indexesToRemove.Add(i); + _projection.RemoveAt(i); } } - - foreach (var index in indexesToRemove) - { - _projection.RemoveAt(index); - } } var columnExpressionFindingExpressionVisitor = new ColumnExpressionFindingExpressionVisitor(); @@ -2600,25 +2635,21 @@ private SelectExpression Prune(IReadOnlyCollection? referencedColumns = for (var i = 0; i < _tables.Count; i++) { var table = _tables[i]; - var tableAlias = table is JoinExpressionBase joinExpressionBase - ? joinExpressionBase.Table.Alias! - : table.Alias!; + var tableAlias = GetAliasFromTableExpressionBase(table); if (columnsMap[tableAlias] == null && (table is LeftJoinExpression || table is OuterApplyExpression) && _tptLeftJoinTables?.Contains(i + removedTableCount) == true) { _tables.RemoveAt(i); + _tableReferences.RemoveAt(i); removedTableCount++; i--; continue; } - var innerSelectExpression = (table as SelectExpression) - ?? ((table as JoinExpressionBase)?.Table as SelectExpression); - - if (innerSelectExpression != null) + if (UnwrapJoinExpression(table) is SelectExpression innerSelectExpression) { innerSelectExpression.Prune(columnsMap[tableAlias]); } @@ -2627,34 +2658,134 @@ private SelectExpression Prune(IReadOnlyCollection? referencedColumns = return this; } + private Dictionary ApplyProjectionMapping( + Dictionary projectionMapping, + bool makeNullable = false) + { + var mapping = new Dictionary(); + var entityProjectionCache = new Dictionary>(ReferenceEqualityComparer.Instance); + foreach (var projection in projectionMapping) + { + var projectionMember = projection.Key; + var projectionToAdd = projection.Value; + + if (projectionToAdd is EntityProjectionExpression entityProjection) + { + if (!entityProjectionCache.TryGetValue(entityProjection, out var value)) + { + var entityProjectionToCache = entityProjection; + if (makeNullable) + { + entityProjection = entityProjection.MakeNullable(); + } + value = AddToProjection(entityProjection); + entityProjectionCache[entityProjectionToCache] = value; + } + + mapping[projectionMember] = value; + } + else + { + projectionToAdd = MakeNullable(projectionToAdd, makeNullable); + mapping[projectionMember] = AddToProjection((SqlExpression)projectionToAdd, projectionMember.Last?.Name); + } + } + + projectionMapping.Clear(); + + return mapping; + } + + private static SqlExpression MakeNullable(SqlExpression expression, bool nullable) + => nullable && expression is ColumnExpression column ? column.MakeNullable() : expression; + + private static Expression MakeNullable(Expression expression, bool nullable) + { + if (nullable) + { + if (expression is EntityProjectionExpression entityProjection) + { + return entityProjection.MakeNullable(); + } + + if (expression is ColumnExpression column) + { + return column.MakeNullable(); + } + } + + return expression; + } + + private static string GetAliasFromTableExpressionBase(TableExpressionBase tableExpressionBase) + => UnwrapJoinExpression(tableExpressionBase).Alias!; + + private static TableExpressionBase UnwrapJoinExpression(TableExpressionBase tableExpressionBase) + => (tableExpressionBase as JoinExpressionBase)?.Table ?? tableExpressionBase; + private static IEnumerable GetAllPropertiesInHierarchy(IEntityType entityType) => entityType.GetAllBaseTypes().Concat(entityType.GetDerivedTypesInclusive()) .SelectMany(t => t.GetDeclaredProperties()); private static ColumnExpression CreateColumnExpression( - IProperty property, - ITableBase table, - TableExpressionBase tableExpression, - bool nullable) + IProperty property, ITableBase table, TableReferenceExpression tableExpression, bool nullable) => new(property, table.FindColumn(property)!, tableExpression, nullable); - private ColumnExpression GenerateOuterColumn(SqlExpression projection, string? alias = null) + private ColumnExpression GenerateOuterColumn( + TableReferenceExpression tableReferenceExpression, SqlExpression projection, string? alias = null) { var index = AddToProjection(projection, alias); - return new ColumnExpression(_projection[index], this); + return new ColumnExpression(_projection[index], tableReferenceExpression); + } + + private bool ContainsTableReference(ColumnExpression column) + // This method is used when evaluating join correlations. + // At that point aliases are not unique-fied across so we need to match tables + // TODO: Avoid need of using UnwrapJoinExpression on both. See issue#24473 + => Tables.Any(e => ReferenceEquals(UnwrapJoinExpression(e), UnwrapJoinExpression(column.Table))); + + + private void AddTable(TableExpressionBase tableExpressionBase, TableReferenceExpression tableReferenceExpression) + { + Check.DebugAssert(_tables.Count == _tableReferences.Count, "All the tables should have their associated TableReferences."); + Check.DebugAssert( + string.Equals(GetAliasFromTableExpressionBase(tableExpressionBase), tableReferenceExpression.Alias), + "Alias of table and table reference should be the same."); + + var uniqueAlias = GenerateUniqueAlias(_usedAliases, tableReferenceExpression.Alias); + UnwrapJoinExpression(tableExpressionBase).Alias = uniqueAlias; + tableReferenceExpression.Alias = uniqueAlias; + + tableExpressionBase = (TableExpressionBase)new AliasUniquefier(_usedAliases).Visit(tableExpressionBase); + _tables.Add(tableExpressionBase); + _tableReferences.Add(tableReferenceExpression); } - private bool ContainsTableReference(TableExpressionBase table) - => Tables.Any(te => ReferenceEquals(te is JoinExpressionBase jeb ? jeb.Table : te, table)); + private SqlExpression AssignUniqueAliases(SqlExpression expression) + => (SqlExpression)new AliasUniquefier(_usedAliases).Visit(expression); + + private static string GenerateUniqueAlias(HashSet usedAliases, string currentAlias) + { + var counter = 0; + var baseAlias = currentAlias[0..1]; + + while (usedAliases.Contains(currentAlias)) + { + currentAlias = baseAlias + counter++; + } + + usedAliases.Add(currentAlias); + return currentAlias; + } /// protected override Expression VisitChildren(ExpressionVisitor visitor) { Check.NotNull(visitor, nameof(visitor)); - // We have to do in-place mutation till we have applied pending collections because of shaper references - // This is pseudo finalization phase for select expression. + // If there are pending collections, then do in-place mutation. + // Post translation we want not in place mutation so that cached SelectExpression inside relational command doesn't get mutated. if (_pendingCollections.Any(e => e != null)) { if (Projection.Any()) @@ -2676,9 +2807,14 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) _projectionMapping = projectionMapping; } - var tables = _tables.ToList(); + // We cannot erase _tables before visiting all because joinPredicate may reference them which breaks referential integrity + var visitedTables = new List(); + visitedTables.AddRange(_tables.Select(e => (TableExpressionBase)visitor.Visit(e))); + Check.DebugAssert( + visitedTables.Select(e => GetAliasFromTableExpressionBase(e)).SequenceEqual(_tableReferences.Select(e => e.Alias)), + "Aliases of Table/TableReferences must match after visit."); _tables.Clear(); - _tables.AddRange(tables.Select(e => (TableExpressionBase)visitor.Visit(e))); + _tables.AddRange(visitedTables); Predicate = (SqlExpression?)visitor.Visit(Predicate); @@ -2699,7 +2835,6 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) return this; } - var changed = false; var newProjections = _projection; @@ -2752,6 +2887,8 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) { var table = _tables[i]; var newTable = (TableExpressionBase)visitor.Visit(table); + Check.DebugAssert(GetAliasFromTableExpressionBase(newTable) == _tableReferences[i].Alias, + "Alias of updated table must match the old table."); if (newTable != table && newTables == _tables) { @@ -2836,7 +2973,8 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) if (changed) { - var newSelectExpression = new SelectExpression(Alias, newProjections, newTables, newGroupBy, newOrderings) + var newTableReferences = _tableReferences.ToList(); + var newSelectExpression = new SelectExpression(Alias, newProjections, newTables, newTableReferences, newGroupBy, newOrderings) { _projectionMapping = newProjectionMapping, Predicate = predicate, @@ -2850,25 +2988,36 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) newSelectExpression._identifier.AddRange(_identifier); newSelectExpression._identifier.AddRange(_childIdentifiers); + // Remap tableReferences in new select expression + foreach (var tableReference in newTableReferences) + { + tableReference.UpdateTableReference(this, newSelectExpression); + } + + var tableReferenceUpdatingExpressionVisitor = new TableReferenceUpdatingExpressionVisitor(this, newSelectExpression); + tableReferenceUpdatingExpressionVisitor.Visit(newSelectExpression); + return newSelectExpression; } return this; - }/// - /// Creates a new expression that is like this one, but using the supplied children. If all of the children are the same, it will - /// return this expression. - /// - /// The property of the result. - /// The property of the result. - /// The property of the result. - /// The property of the result. - /// The property of the result. - /// The property of the result. - /// The property of the result. - /// The property of the result. - /// The property of the result. - /// The property of the result. - /// This expression if no children changed, or an expression with the updated children. + } + + /// + /// Creates a new expression that is like this one, but using the supplied children. If all of the children are the same, it will + /// return this expression. + /// + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// The property of the result. + /// This expression if no children changed, or an expression with the updated children. // This does not take internal states since when using this method SelectExpression should be finalized [Obsolete("Use the overload which does not require distinct & alias parameter.")] public SelectExpression Update( @@ -2894,7 +3043,7 @@ public SelectExpression Update( projectionMapping[kvp.Key] = kvp.Value; } - return new SelectExpression(alias, projections.ToList(), tables.ToList(), groupBy.ToList(), orderings.ToList()) + return new SelectExpression(alias, projections.ToList(), tables.ToList(), _tableReferences.ToList(), groupBy.ToList(), orderings.ToList()) { _projectionMapping = projectionMapping, Predicate = predicate, @@ -2941,7 +3090,7 @@ public SelectExpression Update( projectionMapping[kvp.Key] = kvp.Value; } - return new SelectExpression(Alias, projections.ToList(), tables.ToList(), groupBy.ToList(), orderings.ToList()) + return new SelectExpression(Alias, projections.ToList(), tables.ToList(), _tableReferences.ToList(), groupBy.ToList(), orderings.ToList()) { _projectionMapping = projectionMapping, Predicate = predicate, @@ -3073,94 +3222,18 @@ public override bool Equals(object? obj) private bool Equals(SelectExpression selectExpression) { - if (!base.Equals(selectExpression)) - { - return false; - } - - if (_projection.Count != selectExpression._projection.Count) - { - return false; - } - - for (var i = 0; i < _projection.Count; i++) - { - if (!_projection[i].Equals(selectExpression._projection[i])) - { - return false; - } - } - - if (_projectionMapping.Count != selectExpression._projectionMapping.Count) - { - return false; - } - - foreach (var projectionMapping in _projectionMapping) - { - if (!selectExpression._projectionMapping.TryGetValue(projectionMapping.Key, out var projection)) - { - return false; - } - - if (!projectionMapping.Value.Equals(projection)) - { - return false; - } - } - - if (!Tags.SequenceEqual(selectExpression.Tags)) - { - return false; - } - - if (!_tables.SequenceEqual(selectExpression._tables)) - { - return false; - } - - if (!(Predicate == null && selectExpression.Predicate == null - || Predicate != null && Predicate.Equals(selectExpression.Predicate))) - { - return false; - } - - if (!_pendingCollections.SequenceEqual(selectExpression._pendingCollections)) - { - return false; - } - - if (!_groupBy.SequenceEqual(selectExpression._groupBy)) - { - return false; - } - - if (!(Having == null && selectExpression.Having == null - || Having != null && Having.Equals(selectExpression.Having))) - { - return false; - } - - if (!_orderings.SequenceEqual(selectExpression._orderings)) - { - return false; - } - - if (!(Offset == null && selectExpression.Offset == null - || Offset != null && Offset.Equals(selectExpression.Offset))) - { - return false; - } - -#pragma warning disable IDE0046 // Convert to conditional expression - if (!(Limit == null && selectExpression.Limit == null - || Limit != null && Limit.Equals(selectExpression.Limit))) - { - return false; - } - - return IsDistinct == selectExpression.IsDistinct; -#pragma warning restore IDE0046 // Convert to conditional expression + /* + * This is intentionally reference equals. + * SelectExpression can appear at 2 levels, + * 1. Top most level which is always same reference when translation phase, post-translation it can change in + * ShapedQueryExpression where it would cause reconstruction. Reconstruction is cheaper than computing whole Equals + * 2. Nested level component inside top level SelectExpression where it could change the reference and reconstruct SQL tree. + * Since we assign unique aliases to components, 2 different SelectExpression would never match. And only positive case could + * happen when it is reference equal. + * If inner changed with in-place mutation then reference would be same, if inner changed with no mutation then it will cause + * reconstruction causing different reference. + */ + return ReferenceEquals(this, selectExpression); } /// @@ -3169,11 +3242,10 @@ public override int GetHashCode() var hash = new HashCode(); hash.Add(base.GetHashCode()); - // TODO: See issue#21700 & #18923 - //foreach (var projection in _projection) - //{ - // hash.Add(projection); - //} + foreach (var projection in _projection) + { + hash.Add(projection); + } foreach (var projectionMapping in _projectionMapping) { diff --git a/src/EFCore.Relational/Query/SqlExpressions/TableReferenceExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/TableReferenceExpression.cs new file mode 100644 index 00000000000..022f3785a2b --- /dev/null +++ b/src/EFCore.Relational/Query/SqlExpressions/TableReferenceExpression.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Linq.Expressions; + +namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions +{ +#pragma warning disable CS1591 + // TODO: Make this nested inside SelectExpression and same for ColumnExpression + public class TableReferenceExpression : Expression + { + private SelectExpression _selectExpression; + + public TableReferenceExpression(SelectExpression selectExpression, string alias) + { + _selectExpression = selectExpression; + Alias = alias; + } + + public virtual TableExpressionBase Table + => _selectExpression.Tables.Single( + e => string.Equals((e as JoinExpressionBase)?.Table.Alias ?? e.Alias, Alias, StringComparison.OrdinalIgnoreCase)); + + public virtual string Alias { get; internal set; } + + public override Type Type => typeof(object); + + public override ExpressionType NodeType => ExpressionType.Extension; + public virtual void UpdateTableReference(SelectExpression oldSelect, SelectExpression newSelect) + { + if (ReferenceEquals(oldSelect, _selectExpression)) + { + _selectExpression = newSelect; + } + } + + /// + public override bool Equals(object? obj) + => obj != null + && (ReferenceEquals(this, obj) + || obj is TableReferenceExpression tableReferenceExpression + && Equals(tableReferenceExpression)); + + // Since table reference is owned by SelectExpression, the select expression should be the same reference if they are matching. + // That means we also don't need to compute the hashcode for it. + // This allows us to break the cycle in computation when traversing this graph. + private bool Equals(TableReferenceExpression tableReferenceExpression) + => string.Equals(Alias, tableReferenceExpression.Alias, StringComparison.OrdinalIgnoreCase) + && ReferenceEquals(_selectExpression, tableReferenceExpression._selectExpression); + + /// + public override int GetHashCode() + => Alias.GetHashCode(); + } +} diff --git a/src/EFCore/Query/ProjectionBindingExpression.cs b/src/EFCore/Query/ProjectionBindingExpression.cs index 9e594c63157..e63b76bf4a6 100644 --- a/src/EFCore/Query/ProjectionBindingExpression.cs +++ b/src/EFCore/Query/ProjectionBindingExpression.cs @@ -68,7 +68,7 @@ public ProjectionBindingExpression( /// The index map to bind with query expression projection for ValueBuffer. public ProjectionBindingExpression( Expression queryExpression, - IDictionary indexMap) + IReadOnlyDictionary indexMap) { Check.NotNull(queryExpression, nameof(queryExpression)); Check.NotNull(indexMap, nameof(indexMap)); @@ -96,7 +96,7 @@ public ProjectionBindingExpression( /// /// The projection member to bind if binding is via index map for a value buffer. /// - public virtual IDictionary? IndexMap { get; } + public virtual IReadOnlyDictionary? IndexMap { get; } /// public override Type Type { get; } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs index 2338d77a1a1..6389b8da12f 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs @@ -4227,7 +4227,7 @@ public override Task Select_nested_collection_with_distinct(bool async) { return base.Select_nested_collection_with_distinct(async); } - + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] public override Task Correlated_collection_with_distinct_without_default_identifiers_projecting_columns(bool async) { @@ -4240,6 +4240,12 @@ public override Task Correlated_collection_with_distinct_without_default_identif return base.Correlated_collection_with_distinct_without_default_identifiers_projecting_columns_with_navigation(async); } + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Collection_projection_after_DefaultIfEmpty(bool async) + { + return base.Collection_projection_after_DefaultIfEmpty(async); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs index 1a13d67d4fd..14bb309cb72 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs @@ -1278,6 +1278,12 @@ FROM root c ORDER BY c[""OrderID""]"); } + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Collection_include_over_result_of_single_non_scalar(bool async) + { + return base.Collection_include_over_result_of_single_non_scalar(async); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Relational.Specification.Tests/Query/GearsOfWarQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/GearsOfWarQueryRelationalTestBase.cs index 733f68c5662..58509668da3 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/GearsOfWarQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/GearsOfWarQueryRelationalTestBase.cs @@ -26,7 +26,7 @@ public override async Task Correlated_collection_with_groupby_with_complex_group var message = (await Assert.ThrowsAsync( () => base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async))).Message; - Assert.Equal(RelationalStrings.UnableToTranslateSubqueryWithGroupBy("w.Id"), message); + Assert.Equal(RelationalStrings.InsufficientInformationToIdentifyOuterElementOfCollectionJoin, message); } [ConditionalTheory] @@ -36,7 +36,7 @@ public override async Task Correlated_collection_with_distinct_not_projecting_id var message = (await Assert.ThrowsAsync( () => base.Correlated_collection_with_distinct_not_projecting_identifier_column_also_projecting_complex_expressions(async))).Message; - Assert.Equal(RelationalStrings.UnableToTranslateSubqueryWithDistinct("w.Id"), message); + Assert.Equal(RelationalStrings.InsufficientInformationToIdentifyOuterElementOfCollectionJoin, message); } public override async Task Client_eval_followed_by_aggregate_operation(bool async) diff --git a/test/EFCore.Relational.Specification.Tests/Query/NorthwindGroupByQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/NorthwindGroupByQueryRelationalTestBase.cs index 7c5a48e0042..bb07f8d91fa 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/NorthwindGroupByQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/NorthwindGroupByQueryRelationalTestBase.cs @@ -24,7 +24,7 @@ public override async Task Complex_query_with_groupBy_in_subquery4(bool async) var message = (await Assert.ThrowsAsync( () => base.Complex_query_with_groupBy_in_subquery4(async))).Message; - Assert.Equal(RelationalStrings.UnableToTranslateSubqueryWithGroupBy("o.OrderID"), message); + Assert.Equal(RelationalStrings.InsufficientInformationToIdentifyOuterElementOfCollectionJoin, message); } protected virtual bool CanExecuteQueryString diff --git a/test/EFCore.Relational.Specification.Tests/Query/NorthwindSetOperationsQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/NorthwindSetOperationsQueryRelationalTestBase.cs index 21c3ff6face..100f2a1cbe5 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/NorthwindSetOperationsQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/NorthwindSetOperationsQueryRelationalTestBase.cs @@ -1,7 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; namespace Microsoft.EntityFrameworkCore.Query { @@ -13,6 +17,22 @@ protected NorthwindSetOperationsQueryRelationalTestBase(TFixture fixture) { } + public override async Task Collection_projection_after_set_operation_fails_if_distinct(bool async) + { + var message = (await Assert.ThrowsAsync( + () => base.Collection_projection_after_set_operation_fails_if_distinct(async))).Message; + + Assert.Equal(RelationalStrings.InsufficientInformationToIdentifyOuterElementOfCollectionJoin, message); + } + + public override async Task Collection_projection_before_set_operation_fails(bool async) + { + var message = (await Assert.ThrowsAsync( + () => base.Collection_projection_before_set_operation_fails(async))).Message; + + Assert.Equal(RelationalStrings.SetOperationsNotAllowedAfterClientEvaluation, message); + } + protected virtual bool CanExecuteQueryString => false; diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index 81ca1a99c22..9985d137ad1 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -8728,7 +8728,7 @@ public virtual Task Correlated_collection_after_distinct_3_levels(bool async) }); } - [ConditionalTheory] + [ConditionalTheory(Skip = "Issue#24440")] [MemberData(nameof(IsAsyncData))] public virtual Task Correlated_collection_after_distinct_3_levels_without_original_identifiers(bool async) { diff --git a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs index 5477dd4129e..25ab14570fa 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs @@ -6529,5 +6529,24 @@ public virtual Task Select_nested_collection_with_distinct(bool async) assertOrder: true, elementAsserter: (e, a) => AssertCollection(e, a)); } + + + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Collection_projection_after_DefaultIfEmpty(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(c => c.City == "Seattle").DefaultIfEmpty() + .OrderBy(c => c.CustomerID) + .Select(e => new + { + e.Orders + }), + assertOrder: true, + elementAsserter: (e, a) => AssertCollection(e.Orders, a.Orders), + entryCount: 14); + } } } diff --git a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs index f0d18f9f395..8cece5c2fa2 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs @@ -656,20 +656,20 @@ public virtual Task Select_nested_collection_deep_distinct_no_identifiers(bool a async, ss => (from c in ss.Set() - where c.City == "London" - orderby c.CustomerID - select new { c.City }).Distinct().Select(x => - - ((from o1 in ss.Set() - where o1.CustomerID == x.City - && o1.OrderDate.Value.Year == 1997 - orderby o1.OrderID - select o1).Distinct().Select(xx => - - (from o2 in ss.Set() - where xx.CustomerID == x.City - orderby o2.OrderID - select xx.OrderID).ToList()).ToList())), + where c.City == "London" + orderby c.CustomerID + select new { c.City }).Distinct().Select(x => + + ((from o1 in ss.Set() + where o1.CustomerID == x.City + && o1.OrderDate.Value.Year == 1997 + orderby o1.OrderID + select o1).Distinct().Select(xx => + + (from o2 in ss.Set() + where xx.CustomerID == x.City + orderby o2.OrderID + select xx.OrderID).ToList()).ToList())), elementSorter: e => e.Count, elementAsserter: (e, a) => AssertCollection( e, @@ -1911,7 +1911,7 @@ public virtual Task Correlated_collection_after_distinct_not_containing_original }); } - [ConditionalTheory] + [ConditionalTheory(Skip = "Issue#24440")] [MemberData(nameof(IsAsyncData))] public virtual Task Correlated_collection_after_distinct_with_complex_projection_not_containing_original_identifier(bool async) { @@ -2221,6 +2221,31 @@ public virtual Task Correlated_collection_after_groupby_with_complex_projection_ }); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Collection_include_over_result_of_single_non_scalar(bool async) + { + return AssertQuery( + async, + ss => + ss.Set().Include(c => c.Orders).ThenInclude(o => o.OrderDetails) + .Where(c => c.CustomerID.StartsWith("F")) + .Select(c => new + { + c, + SingleOrder = c.Orders.OrderBy(o => o.OrderDate).FirstOrDefault() + }), + elementSorter: e => e.c.CustomerID, + elementAsserter: (e, a) => + { + AssertInclude(e, a, + new ExpectedInclude(c => c.Orders), + new ExpectedInclude(o => o.OrderDetails, "Orders")); + AssertInclude(e.SingleOrder, a.SingleOrder, new ExpectedInclude(o => o.OrderDetails)); + }, + entryCount: 235); + } + private static string ClientMethod(string s) => s; } } diff --git a/test/EFCore.Specification.Tests/Query/NorthwindSetOperationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindSetOperationsQueryTestBase.cs index 128bdd59b68..688d08541c9 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindSetOperationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindSetOperationsQueryTestBase.cs @@ -569,5 +569,96 @@ public virtual Task OrderBy_Take_Union(bool async) entryCount: 1, assertOrder: true); } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Collection_projection_after_set_operation(bool async) + { + return AssertQuery( + async, ss => ss.Set().Where(c => c.City == "Seatte") + .Union(ss.Set().Where(c => c.CustomerID.StartsWith("F"))) + .Select(c => new + { + c.CustomerID, + c.Orders + }), + elementSorter: c => c.CustomerID, + elementAsserter: (e, a) => + { + AssertEqual(e.CustomerID, a.CustomerID); + AssertCollection(e.Orders, a.Orders); + }, + entryCount: 63); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Collection_projection_after_set_operation_fails_if_distinct(bool async) + { + return AssertQuery( + async, ss => ss.Set().Where(c => c.City == "Seatte") + .Concat(ss.Set().Where(c => c.CustomerID.StartsWith("F"))) + .Select(c => new + { + c.CustomerID, + c.Orders + }), + elementSorter: c => c.CustomerID, + elementAsserter: (e, a) => + { + AssertEqual(e.CustomerID, a.CustomerID); + AssertCollection(e.Orders, a.Orders); + }, + entryCount: 63); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Collection_projection_before_set_operation_fails(bool async) + { + return AssertQuery( + async, ss => ss.Set() + .Where(c => c.City == "Seatte") + .Select(c => new + { + c.Orders + }) + .Union(ss.Set() + .Where(c => c.CustomerID.StartsWith("F")) + .Select(c => new + { + c.Orders + })), + elementSorter: a => a.Orders.FirstOrDefault().Maybe(e => e.CustomerID), + elementAsserter: (e, a) => + { + AssertCollection(e.Orders, a.Orders); + }, + entryCount: 63); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Concat_with_one_side_being_GroupBy_aggregate(bool async) + { + return AssertQuery( + async, ss => ss.Set() + .Where(c => c.Customer.City == "Seatte") + .Select(c => new + { + c.OrderDate + }) + .Union(ss.Set() + .GroupBy(e => e.CustomerID) + .Select(g => new + { + OrderDate = g.Max(e => e.OrderDate) + })), + elementSorter: a => a.OrderDate, + elementAsserter: (e, a) => + { + AssertEqual(e.OrderDate, a.OrderDate); + }); + } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/ManyToManyLoadSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/ManyToManyLoadSqlServerTest.cs index d330f3a2828..b1d72494846 100644 --- a/test/EFCore.SqlServer.FunctionalTests/ManyToManyLoadSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ManyToManyLoadSqlServerTest.cs @@ -74,7 +74,7 @@ public override async Task Load_collection_using_Query_with_Include_for_same_col AssertSql( @"@__p_0='3' -SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [e].[Id], [t].[EntityOneId], [t].[EntityTwoId], [t1].[EntityOneId], [t1].[EntityTwoId], [t1].[Id], [t1].[Name], [t1].[EntityOneId0], [t1].[EntityTwoId0], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name0], [t1].[ReferenceInverseId] +SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [e].[Id], [t].[EntityOneId], [t].[EntityTwoId], [t0].[EntityOneId], [t0].[EntityTwoId], [t0].[Id], [t0].[Name], [t0].[EntityOneId0], [t0].[EntityTwoId0], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name0], [t0].[ReferenceInverseId] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], [e0].[EntityOneId], [e0].[EntityTwoId] @@ -82,18 +82,18 @@ FROM [EntityOneEntityTwo] AS [e0] INNER JOIN [EntityTwos] AS [e1] ON [e0].[EntityTwoId] = [e1].[Id] ) AS [t] ON [e].[Id] = [t].[EntityOneId] LEFT JOIN ( - SELECT [e2].[EntityOneId], [e2].[EntityTwoId], [e3].[Id], [e3].[Name], [t0].[EntityOneId] AS [EntityOneId0], [t0].[EntityTwoId] AS [EntityTwoId0], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId] + SELECT [e2].[EntityOneId], [e2].[EntityTwoId], [e3].[Id], [e3].[Name], [t1].[EntityOneId] AS [EntityOneId0], [t1].[EntityTwoId] AS [EntityTwoId0], [t1].[Id] AS [Id0], [t1].[CollectionInverseId], [t1].[Name] AS [Name0], [t1].[ReferenceInverseId] FROM [EntityOneEntityTwo] AS [e2] INNER JOIN [EntityOnes] AS [e3] ON [e2].[EntityOneId] = [e3].[Id] LEFT JOIN ( SELECT [e4].[EntityOneId], [e4].[EntityTwoId], [e5].[Id], [e5].[CollectionInverseId], [e5].[Name], [e5].[ReferenceInverseId] FROM [EntityOneEntityTwo] AS [e4] INNER JOIN [EntityTwos] AS [e5] ON [e4].[EntityTwoId] = [e5].[Id] - ) AS [t0] ON [e3].[Id] = [t0].[EntityOneId] + ) AS [t1] ON [e3].[Id] = [t1].[EntityOneId] WHERE [e3].[Id] = @__p_0 -) AS [t1] ON [t].[Id] = [t1].[EntityTwoId] +) AS [t0] ON [t].[Id] = [t0].[EntityTwoId] WHERE [e].[Id] = @__p_0 -ORDER BY [e].[Id], [t].[EntityOneId], [t].[EntityTwoId], [t].[Id], [t1].[EntityOneId], [t1].[EntityTwoId], [t1].[Id], [t1].[EntityOneId0], [t1].[EntityTwoId0], [t1].[Id0]"); +ORDER BY [e].[Id], [t].[EntityOneId], [t].[EntityTwoId], [t].[Id], [t0].[EntityOneId], [t0].[EntityTwoId], [t0].[Id], [t0].[EntityOneId0], [t0].[EntityTwoId0], [t0].[Id0]"); } public override async Task Load_collection_using_Query_with_Include(bool async) @@ -164,20 +164,20 @@ public override async Task Load_collection_using_Query_with_filtered_Include_and SELECT [t].[Id], [t].[Name], ( SELECT COUNT(*) - FROM [EntityOneEntityTwo] AS [e] - INNER JOIN [EntityOnes] AS [e0] ON [e].[EntityOneId] = [e0].[Id] - WHERE [t].[Id] = [e].[EntityTwoId]) AS [Count1], ( + FROM [EntityOneEntityTwo] AS [e2] + INNER JOIN [EntityOnes] AS [e3] ON [e2].[EntityOneId] = [e3].[Id] + WHERE [t].[Id] = [e2].[EntityTwoId]) AS [Count1], ( SELECT COUNT(*) FROM [JoinTwoToThree] AS [j] - INNER JOIN [EntityThrees] AS [e1] ON [j].[ThreeId] = [e1].[Id] + INNER JOIN [EntityThrees] AS [e4] ON [j].[ThreeId] = [e4].[Id] WHERE [t].[Id] = [j].[TwoId]) AS [Count3] -FROM [EntityOnes] AS [e2] +FROM [EntityOnes] AS [e] INNER JOIN ( - SELECT [e4].[Id], [e4].[Name], [e3].[EntityOneId] - FROM [EntityOneEntityTwo] AS [e3] - INNER JOIN [EntityTwos] AS [e4] ON [e3].[EntityTwoId] = [e4].[Id] -) AS [t] ON [e2].[Id] = [t].[EntityOneId] -WHERE [e2].[Id] = @__p_0 + SELECT [e1].[Id], [e1].[Name], [e0].[EntityOneId] + FROM [EntityOneEntityTwo] AS [e0] + INNER JOIN [EntityTwos] AS [e1] ON [e0].[EntityTwoId] = [e1].[Id] +) AS [t] ON [e].[Id] = [t].[EntityOneId] +WHERE [e].[Id] = @__p_0 ORDER BY [t].[Id]"); } @@ -188,7 +188,7 @@ public override async Task Load_collection_using_Query_with_join(bool async) AssertSql( @"@__p_0='3' -SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name0], [t1].[ReferenceInverseId], [e].[Id], [t].[EntityOneId], [t].[EntityTwoId], [t1].[Id], [t1].[EntityOneId], [t1].[EntityTwoId], [t2].[EntityOneId], [t2].[EntityTwoId], [t2].[Id], [t2].[Name] +SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name0], [t0].[ReferenceInverseId], [e].[Id], [t].[EntityOneId], [t].[EntityTwoId], [t0].[Id], [t0].[EntityOneId], [t0].[EntityTwoId], [t2].[EntityOneId], [t2].[EntityTwoId], [t2].[Id], [t2].[Name] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], [e0].[EntityOneId], [e0].[EntityTwoId] @@ -196,14 +196,14 @@ FROM [EntityOneEntityTwo] AS [e0] INNER JOIN [EntityTwos] AS [e1] ON [e0].[EntityTwoId] = [e1].[Id] ) AS [t] ON [e].[Id] = [t].[EntityOneId] INNER JOIN ( - SELECT [e2].[Id], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t0].[EntityOneId], [t0].[EntityTwoId] + SELECT [e2].[Id], [t1].[Id] AS [Id0], [t1].[CollectionInverseId], [t1].[Name] AS [Name0], [t1].[ReferenceInverseId], [t1].[EntityOneId], [t1].[EntityTwoId] FROM [EntityOnes] AS [e2] INNER JOIN ( SELECT [e4].[Id], [e4].[CollectionInverseId], [e4].[Name], [e4].[ReferenceInverseId], [e3].[EntityOneId], [e3].[EntityTwoId] FROM [EntityOneEntityTwo] AS [e3] INNER JOIN [EntityTwos] AS [e4] ON [e3].[EntityTwoId] = [e4].[Id] - ) AS [t0] ON [e2].[Id] = [t0].[EntityOneId] -) AS [t1] ON [t].[Id] = [t1].[Id0] + ) AS [t1] ON [e2].[Id] = [t1].[EntityOneId] +) AS [t0] ON [t].[Id] = [t0].[Id0] LEFT JOIN ( SELECT [e5].[EntityOneId], [e5].[EntityTwoId], [e6].[Id], [e6].[Name] FROM [EntityOneEntityTwo] AS [e5] @@ -211,7 +211,7 @@ FROM [EntityOneEntityTwo] AS [e5] WHERE [e6].[Id] = @__p_0 ) AS [t2] ON [t].[Id] = [t2].[EntityTwoId] WHERE [e].[Id] = @__p_0 -ORDER BY [e].[Id], [t].[EntityOneId], [t].[EntityTwoId], [t].[Id], [t1].[Id], [t1].[EntityOneId], [t1].[EntityTwoId], [t1].[Id0], [t2].[EntityOneId], [t2].[EntityTwoId], [t2].[Id]"); +ORDER BY [e].[Id], [t].[EntityOneId], [t].[EntityTwoId], [t].[Id], [t0].[Id], [t0].[EntityOneId], [t0].[EntityTwoId], [t0].[Id0], [t2].[EntityOneId], [t2].[EntityTwoId], [t2].[Id]"); } protected override void ClearLog() @@ -238,9 +238,11 @@ private void AssertSql(string expected) new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)[2].Substring(6); - var testName = methodCallLine.Substring(0, methodCallLine.IndexOf(')') + 1); - var lineIndex = methodCallLine.LastIndexOf("line", StringComparison.Ordinal); - var lineNumber = lineIndex > 0 ? methodCallLine.Substring(lineIndex) : ""; + var indexMethodEnding = methodCallLine.IndexOf(')') + 1; + var testName = methodCallLine.Substring(0, indexMethodEnding); + var parts = methodCallLine[indexMethodEnding..].Split(" ", StringSplitOptions.RemoveEmptyEntries); + var fileName = parts[1][..^5]; + var lineNumber = int.Parse(parts[2]); var currentDirectory = Directory.GetCurrentDirectory(); var logFile = currentDirectory.Substring( @@ -255,7 +257,7 @@ private void AssertSql(string expected) "; - var contents = testInfo + newBaseLine + FileNewLine + FileNewLine; + var contents = testInfo + newBaseLine + FileNewLine + "--------------------" + FileNewLine; File.AppendAllText(logFile, contents); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index 193ca3bd3ca..b2b5fe34e05 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -2300,12 +2300,12 @@ public override async Task Required_navigation_on_a_subquery_with_First_in_proje AssertSql( @"SELECT ( - SELECT TOP(1) [l0].[Name] - FROM [LevelTwo] AS [l] - INNER JOIN [LevelOne] AS [l0] ON [l].[Level1_Required_Id] = [l0].[Id] - ORDER BY [l].[Id]) -FROM [LevelTwo] AS [l1] -WHERE [l1].[Id] = 7"); + SELECT TOP(1) [l1].[Name] + FROM [LevelTwo] AS [l0] + INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] + ORDER BY [l0].[Id]) +FROM [LevelTwo] AS [l] +WHERE [l].[Id] = 7"); } public override async Task Required_navigation_on_a_subquery_with_complex_projection_and_First(bool async) @@ -2314,13 +2314,13 @@ public override async Task Required_navigation_on_a_subquery_with_complex_projec AssertSql( @"SELECT ( - SELECT TOP(1) [l1].[Name] - FROM [LevelTwo] AS [l] - INNER JOIN [LevelOne] AS [l0] ON [l].[Level1_Required_Id] = [l0].[Id] - INNER JOIN [LevelOne] AS [l1] ON [l].[Level1_Required_Id] = [l1].[Id] - ORDER BY [l].[Id]) -FROM [LevelTwo] AS [l2] -WHERE [l2].[Id] = 7"); + SELECT TOP(1) [l2].[Name] + FROM [LevelTwo] AS [l0] + INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] + INNER JOIN [LevelOne] AS [l2] ON [l0].[Level1_Required_Id] = [l2].[Id] + ORDER BY [l0].[Id]) +FROM [LevelTwo] AS [l] +WHERE [l].[Id] = 7"); } public override async Task Required_navigation_on_a_subquery_with_First_in_predicate(bool async) @@ -2977,11 +2977,11 @@ public override async Task Select_subquery_with_client_eval_and_navigation1(bool AssertSql( @"SELECT ( - SELECT TOP(1) [l0].[Name] - FROM [LevelTwo] AS [l] - INNER JOIN [LevelOne] AS [l0] ON [l].[Level1_Required_Id] = [l0].[Id] - ORDER BY [l].[Id]) -FROM [LevelTwo] AS [l1]"); + SELECT TOP(1) [l1].[Name] + FROM [LevelTwo] AS [l0] + INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] + ORDER BY [l0].[Id]) +FROM [LevelTwo] AS [l]"); } public override async Task Select_subquery_with_client_eval_and_navigation2(bool async) @@ -2991,17 +2991,17 @@ public override async Task Select_subquery_with_client_eval_and_navigation2(bool AssertSql( @"SELECT CASE WHEN (( - SELECT TOP(1) [l0].[Name] - FROM [LevelTwo] AS [l] - INNER JOIN [LevelOne] AS [l0] ON [l].[Level1_Required_Id] = [l0].[Id] - ORDER BY [l].[Id]) = N'L1 02') AND ( - SELECT TOP(1) [l0].[Name] - FROM [LevelTwo] AS [l] - INNER JOIN [LevelOne] AS [l0] ON [l].[Level1_Required_Id] = [l0].[Id] - ORDER BY [l].[Id]) IS NOT NULL THEN CAST(1 AS bit) + SELECT TOP(1) [l1].[Name] + FROM [LevelTwo] AS [l0] + INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] + ORDER BY [l0].[Id]) = N'L1 02') AND ( + SELECT TOP(1) [l1].[Name] + FROM [LevelTwo] AS [l0] + INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] + ORDER BY [l0].[Id]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END -FROM [LevelTwo] AS [l1]"); +FROM [LevelTwo] AS [l]"); } public override async Task Select_subquery_with_client_eval_and_multi_level_navigation(bool async) @@ -3010,12 +3010,12 @@ public override async Task Select_subquery_with_client_eval_and_multi_level_navi AssertSql( @"SELECT ( - SELECT TOP(1) [l1].[Name] - FROM [LevelThree] AS [l] - INNER JOIN [LevelTwo] AS [l0] ON [l].[Level2_Required_Id] = [l0].[Id] - INNER JOIN [LevelOne] AS [l1] ON [l0].[Level1_Required_Id] = [l1].[Id] - ORDER BY [l].[Id]) -FROM [LevelThree] AS [l2]"); + SELECT TOP(1) [l2].[Name] + FROM [LevelThree] AS [l0] + INNER JOIN [LevelTwo] AS [l1] ON [l0].[Level2_Required_Id] = [l1].[Id] + INNER JOIN [LevelOne] AS [l2] ON [l1].[Level1_Required_Id] = [l2].[Id] + ORDER BY [l0].[Id]) +FROM [LevelThree] AS [l]"); } public override async Task Member_doesnt_get_pushed_down_into_subquery_with_result_operator(bool async) @@ -3026,13 +3026,13 @@ public override async Task Member_doesnt_get_pushed_down_into_subquery_with_resu @"SELECT ( SELECT [t].[Name] FROM ( - SELECT DISTINCT [l].[Id], [l].[Level2_Optional_Id], [l].[Level2_Required_Id], [l].[Name], [l].[OneToMany_Optional_Inverse3Id], [l].[OneToMany_Optional_Self_Inverse3Id], [l].[OneToMany_Required_Inverse3Id], [l].[OneToMany_Required_Self_Inverse3Id], [l].[OneToOne_Optional_PK_Inverse3Id], [l].[OneToOne_Optional_Self3Id] - FROM [LevelThree] AS [l] + SELECT DISTINCT [l0].[Id], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id] + FROM [LevelThree] AS [l0] ) AS [t] ORDER BY [t].[Id] OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY) -FROM [LevelOne] AS [l0] -WHERE [l0].[Id] < 3"); +FROM [LevelOne] AS [l] +WHERE [l].[Id] < 3"); } public override async Task Subquery_with_Distinct_Skip_FirstOrDefault_without_OrderBy(bool async) @@ -3095,12 +3095,12 @@ public override async Task Project_collection_navigation_count(bool async) await base.Project_collection_navigation_count(async); AssertSql( - @"SELECT [l0].[Id], ( + @"SELECT [l].[Id], ( SELECT COUNT(*) - FROM [LevelThree] AS [l] - WHERE [l1].[Id] IS NOT NULL AND ([l1].[Id] = [l].[OneToMany_Optional_Inverse3Id])) AS [Count] -FROM [LevelOne] AS [l0] -LEFT JOIN [LevelTwo] AS [l1] ON [l0].[Id] = [l1].[Level1_Optional_Id]"); + FROM [LevelThree] AS [l1] + WHERE [l0].[Id] IS NOT NULL AND ([l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id])) AS [Count] +FROM [LevelOne] AS [l] +LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id]"); } public override async Task Project_collection_navigation_composed(bool async) @@ -4079,16 +4079,16 @@ public override async Task IncludeCollection8(bool async) @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [t].[Id0], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name0], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [t].[Id1], [t].[Level3_Optional_Id], [t].[Level3_Required_Id], [t].[Name1], [t].[OneToMany_Optional_Inverse4Id], [t].[OneToMany_Optional_Self_Inverse4Id], [t].[OneToMany_Required_Inverse4Id], [t].[OneToMany_Required_Self_Inverse4Id], [t].[OneToOne_Optional_PK_Inverse4Id], [t].[OneToOne_Optional_Self4Id] FROM [LevelOne] AS [l] LEFT JOIN ( - SELECT [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id], [l1].[Id] AS [Id0], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], [l2].[Id] AS [Id1], [l2].[Level3_Optional_Id], [l2].[Level3_Required_Id], [l2].[Name] AS [Name1], [l2].[OneToMany_Optional_Inverse4Id], [l2].[OneToMany_Optional_Self_Inverse4Id], [l2].[OneToMany_Required_Inverse4Id], [l2].[OneToMany_Required_Self_Inverse4Id], [l2].[OneToOne_Optional_PK_Inverse4Id], [l2].[OneToOne_Optional_Self4Id] - FROM [LevelTwo] AS [l0] - LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[OneToOne_Optional_PK_Inverse3Id] - LEFT JOIN [LevelFour] AS [l2] ON [l1].[Id] = [l2].[Level3_Optional_Id] + SELECT [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Optional_Self_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToMany_Required_Self_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[OneToOne_Optional_Self2Id], [l3].[Id] AS [Id0], [l3].[Level2_Optional_Id], [l3].[Level2_Required_Id], [l3].[Name] AS [Name0], [l3].[OneToMany_Optional_Inverse3Id], [l3].[OneToMany_Optional_Self_Inverse3Id], [l3].[OneToMany_Required_Inverse3Id], [l3].[OneToMany_Required_Self_Inverse3Id], [l3].[OneToOne_Optional_PK_Inverse3Id], [l3].[OneToOne_Optional_Self3Id], [l4].[Id] AS [Id1], [l4].[Level3_Optional_Id], [l4].[Level3_Required_Id], [l4].[Name] AS [Name1], [l4].[OneToMany_Optional_Inverse4Id], [l4].[OneToMany_Optional_Self_Inverse4Id], [l4].[OneToMany_Required_Inverse4Id], [l4].[OneToMany_Required_Self_Inverse4Id], [l4].[OneToOne_Optional_PK_Inverse4Id], [l4].[OneToOne_Optional_Self4Id] + FROM [LevelTwo] AS [l2] + LEFT JOIN [LevelThree] AS [l3] ON [l2].[Id] = [l3].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN [LevelFour] AS [l4] ON [l3].[Id] = [l4].[Level3_Optional_Id] ) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] WHERE ( SELECT COUNT(*) - FROM [LevelTwo] AS [l3] - LEFT JOIN [LevelThree] AS [l4] ON [l3].[Id] = [l4].[OneToOne_Optional_PK_Inverse3Id] - WHERE ([l].[Id] = [l3].[OneToMany_Optional_Inverse2Id]) AND (([l4].[Name] <> N'Foo') OR [l4].[Name] IS NULL)) > 0 + FROM [LevelTwo] AS [l0] + LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[OneToOne_Optional_PK_Inverse3Id] + WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL)) > 0 ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t].[Id1]"); } @@ -4148,28 +4148,28 @@ FROM [LevelOne] AS [l] WHERE (( SELECT TOP(1) ( SELECT TOP(1) ( - SELECT TOP(1) [l0].[Name] - FROM [LevelFour] AS [l0] - WHERE [l0].[Level3_Required_Id] = [l1].[Id] - ORDER BY [l0].[Id]) + SELECT TOP(1) [l2].[Name] + FROM [LevelFour] AS [l2] + WHERE [l2].[Level3_Required_Id] = [l1].[Id] + ORDER BY [l2].[Id]) FROM [LevelThree] AS [l1] - WHERE [l1].[Level2_Required_Id] = [l2].[Id] + WHERE [l1].[Level2_Required_Id] = [l0].[Id] ORDER BY [l1].[Id]) - FROM [LevelTwo] AS [l2] - WHERE [l2].[Level1_Optional_Id] = [l].[Id] - ORDER BY [l2].[Id]) <> N'Foo') OR ( + FROM [LevelTwo] AS [l0] + WHERE [l0].[Level1_Optional_Id] = [l].[Id] + ORDER BY [l0].[Id]) <> N'Foo') OR ( SELECT TOP(1) ( SELECT TOP(1) ( - SELECT TOP(1) [l0].[Name] - FROM [LevelFour] AS [l0] - WHERE [l0].[Level3_Required_Id] = [l1].[Id] - ORDER BY [l0].[Id]) + SELECT TOP(1) [l2].[Name] + FROM [LevelFour] AS [l2] + WHERE [l2].[Level3_Required_Id] = [l1].[Id] + ORDER BY [l2].[Id]) FROM [LevelThree] AS [l1] - WHERE [l1].[Level2_Required_Id] = [l2].[Id] + WHERE [l1].[Level2_Required_Id] = [l0].[Id] ORDER BY [l1].[Id]) - FROM [LevelTwo] AS [l2] - WHERE [l2].[Level1_Optional_Id] = [l].[Id] - ORDER BY [l2].[Id]) IS NULL + FROM [LevelTwo] AS [l0] + WHERE [l0].[Level1_Optional_Id] = [l].[Id] + ORDER BY [l0].[Id]) IS NULL ORDER BY [l].[Id]"); } @@ -4215,17 +4215,17 @@ public override void Member_pushdown_with_collection_navigation_in_the_middle() @"SELECT ( SELECT TOP(1) ( SELECT TOP(1) ( - SELECT TOP(1) [l].[Name] - FROM [LevelFour] AS [l] - WHERE [l].[Level3_Required_Id] = [l0].[Id] - ORDER BY [l].[Id]) - FROM [LevelThree] AS [l0] - WHERE [l1].[Id] = [l0].[OneToMany_Optional_Inverse3Id]) - FROM [LevelTwo] AS [l1] - WHERE [l1].[Level1_Required_Id] = [l2].[Id] - ORDER BY [l1].[Id]) -FROM [LevelOne] AS [l2] -ORDER BY [l2].[Id]"); + SELECT TOP(1) [l2].[Name] + FROM [LevelFour] AS [l2] + WHERE [l2].[Level3_Required_Id] = [l1].[Id] + ORDER BY [l2].[Id]) + FROM [LevelThree] AS [l1] + WHERE [l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id]) + FROM [LevelTwo] AS [l0] + WHERE [l0].[Level1_Required_Id] = [l].[Id] + ORDER BY [l0].[Id]) +FROM [LevelOne] AS [l] +ORDER BY [l].[Id]"); } public override async Task Member_pushdown_with_multiple_collections(bool async) @@ -4234,23 +4234,23 @@ public override async Task Member_pushdown_with_multiple_collections(bool async) AssertSql( @"SELECT ( - SELECT TOP(1) [l].[Name] - FROM [LevelThree] AS [l] + SELECT TOP(1) [l0].[Name] + FROM [LevelThree] AS [l0] WHERE ( - SELECT TOP(1) [l0].[Id] - FROM [LevelTwo] AS [l0] - WHERE [l2].[Id] = [l0].[OneToMany_Optional_Inverse2Id] - ORDER BY [l0].[Id]) IS NOT NULL AND ((( - SELECT TOP(1) [l1].[Id] - FROM [LevelTwo] AS [l1] - WHERE [l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id] - ORDER BY [l1].[Id]) = [l].[OneToMany_Optional_Inverse3Id]) OR (( SELECT TOP(1) [l1].[Id] FROM [LevelTwo] AS [l1] - WHERE [l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id] - ORDER BY [l1].[Id]) IS NULL AND [l].[OneToMany_Optional_Inverse3Id] IS NULL)) - ORDER BY [l].[Id]) -FROM [LevelOne] AS [l2]"); + WHERE [l].[Id] = [l1].[OneToMany_Optional_Inverse2Id] + ORDER BY [l1].[Id]) IS NOT NULL AND ((( + SELECT TOP(1) [l2].[Id] + FROM [LevelTwo] AS [l2] + WHERE [l].[Id] = [l2].[OneToMany_Optional_Inverse2Id] + ORDER BY [l2].[Id]) = [l0].[OneToMany_Optional_Inverse3Id]) OR (( + SELECT TOP(1) [l2].[Id] + FROM [LevelTwo] AS [l2] + WHERE [l].[Id] = [l2].[OneToMany_Optional_Inverse2Id] + ORDER BY [l2].[Id]) IS NULL AND [l0].[OneToMany_Optional_Inverse3Id] IS NULL)) + ORDER BY [l0].[Id]) +FROM [LevelOne] AS [l]"); } public override async Task Null_check_removal_applied_recursively(bool async) @@ -4308,21 +4308,21 @@ public override async Task Lift_projection_mapping_when_pushing_down_subquery(bo AssertSql( @"@__p_0='25' -SELECT [t].[Id], [t1].[Id], [t1].[c], [l1].[Id] +SELECT [t].[Id], [t0].[Id], [t0].[c], [l1].[Id] FROM ( SELECT TOP(@__p_0) [l].[Id] FROM [LevelOne] AS [l] ) AS [t] LEFT JOIN ( - SELECT [t0].[Id], [t0].[c], [t0].[OneToMany_Required_Inverse2Id] + SELECT [t1].[Id], [t1].[c], [t1].[OneToMany_Required_Inverse2Id] FROM ( SELECT [l0].[Id], 1 AS [c], [l0].[OneToMany_Required_Inverse2Id], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Required_Inverse2Id] ORDER BY [l0].[Id]) AS [row] FROM [LevelTwo] AS [l0] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[Id] = [t1].[OneToMany_Required_Inverse2Id] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[Id] = [t0].[OneToMany_Required_Inverse2Id] LEFT JOIN [LevelTwo] AS [l1] ON [t].[Id] = [l1].[OneToMany_Required_Inverse2Id] -ORDER BY [t].[Id], [t1].[Id], [l1].[Id]"); +ORDER BY [t].[Id], [t0].[Id], [l1].[Id]"); } public override async Task Including_reference_navigation_and_projecting_collection_navigation(bool async) @@ -4539,16 +4539,16 @@ public override async Task Contains_over_optional_navigation_with_null_column(bo await base.Contains_over_optional_navigation_with_null_column(async); AssertSql( - @"SELECT [l1].[Name], [l2].[Name] AS [OptionalName], CASE + @"SELECT [l].[Name], [l0].[Name] AS [OptionalName], CASE WHEN EXISTS ( SELECT 1 - FROM [LevelOne] AS [l] - LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] - WHERE ([l0].[Name] = [l2].[Name]) OR ([l0].[Name] IS NULL AND [l2].[Name] IS NULL)) THEN CAST(1 AS bit) + FROM [LevelOne] AS [l1] + LEFT JOIN [LevelTwo] AS [l2] ON [l1].[Id] = [l2].[Level1_Optional_Id] + WHERE ([l2].[Name] = [l0].[Name]) OR ([l2].[Name] IS NULL AND [l0].[Name] IS NULL)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [Contains] -FROM [LevelOne] AS [l1] -LEFT JOIN [LevelTwo] AS [l2] ON [l1].[Id] = [l2].[Level1_Optional_Id]"); +FROM [LevelOne] AS [l] +LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id]"); } public override async Task Contains_over_optional_navigation_with_null_entity_reference(bool async) @@ -4556,17 +4556,17 @@ public override async Task Contains_over_optional_navigation_with_null_entity_re await base.Contains_over_optional_navigation_with_null_entity_reference(async); AssertSql( - @"SELECT [l1].[Name], [l2].[Name] AS [OptionalName], CASE + @"SELECT [l].[Name], [l0].[Name] AS [OptionalName], CASE WHEN EXISTS ( SELECT 1 - FROM [LevelOne] AS [l] - LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] - WHERE ([l0].[Id] = [l3].[Id]) OR ([l0].[Id] IS NULL AND [l3].[Id] IS NULL)) THEN CAST(1 AS bit) + FROM [LevelOne] AS [l2] + LEFT JOIN [LevelTwo] AS [l3] ON [l2].[Id] = [l3].[Level1_Optional_Id] + WHERE ([l3].[Id] = [l1].[Id]) OR ([l3].[Id] IS NULL AND [l1].[Id] IS NULL)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [Contains] -FROM [LevelOne] AS [l1] -LEFT JOIN [LevelTwo] AS [l2] ON [l1].[Id] = [l2].[Level1_Optional_Id] -LEFT JOIN [LevelTwo] AS [l3] ON [l1].[Id] = [l3].[OneToOne_Optional_PK_Inverse2Id]"); +FROM [LevelOne] AS [l] +LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] +LEFT JOIN [LevelTwo] AS [l1] ON [l].[Id] = [l1].[OneToOne_Optional_PK_Inverse2Id]"); } public override async Task Filtered_include_basic_Where(bool async) @@ -4769,7 +4769,7 @@ public override async Task Filtered_include_after_different_filtered_include_sam await base.Filtered_include_after_different_filtered_include_same_level(async); AssertSql( - @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [t0].[Id], [t0].[Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Optional_Self_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToMany_Required_Self_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[OneToOne_Optional_Self2Id], [t2].[Id], [t2].[Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Optional_Self_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToMany_Required_Self_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[OneToOne_Optional_Self2Id] + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [t0].[Id], [t0].[Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Optional_Self_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToMany_Required_Self_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[OneToOne_Optional_Self2Id], [t1].[Id], [t1].[Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Optional_Self_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToMany_Required_Self_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[OneToOne_Optional_Self2Id] FROM [LevelOne] AS [l] LEFT JOIN ( SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id] @@ -4781,15 +4781,15 @@ FROM [LevelTwo] AS [l0] WHERE [t].[row] <= 3 ) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] LEFT JOIN ( - SELECT [t1].[Id], [t1].[Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Optional_Self_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToMany_Required_Self_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[OneToOne_Optional_Self2Id] + SELECT [t2].[Id], [t2].[Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Optional_Self_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToMany_Required_Self_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[OneToOne_Optional_Self2Id] FROM ( SELECT [l1].[Id], [l1].[Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Optional_Self_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToMany_Required_Self_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[OneToOne_Optional_Self2Id], ROW_NUMBER() OVER(PARTITION BY [l1].[OneToMany_Required_Inverse2Id] ORDER BY [l1].[Name] DESC) AS [row] FROM [LevelTwo] AS [l1] WHERE ([l1].[Name] <> N'Bar') OR [l1].[Name] IS NULL - ) AS [t1] - WHERE 1 < [t1].[row] -) AS [t2] ON [l].[Id] = [t2].[OneToMany_Required_Inverse2Id] -ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Name], [t0].[Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[Name] DESC, [t2].[Id]"); + ) AS [t2] + WHERE 1 < [t2].[row] +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Required_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Name], [t0].[Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[Name] DESC, [t1].[Id]"); } public override async Task Filtered_include_after_different_filtered_include_different_level(bool async) @@ -4800,7 +4800,7 @@ public override async Task Filtered_include_after_different_filtered_include_dif @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [t2].[Id], [t2].[Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Optional_Self_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToMany_Required_Self_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[OneToOne_Optional_Self2Id], [t2].[Id0], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Name0], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Optional_Self_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToMany_Required_Self_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[OneToOne_Optional_Self3Id] FROM [LevelOne] AS [l] OUTER APPLY ( - SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [t1].[Id] AS [Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name] AS [Name0], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id] + SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name] AS [Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id] FROM ( SELECT TOP(3) [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id] FROM [LevelTwo] AS [l0] @@ -4808,14 +4808,14 @@ FROM [LevelTwo] AS [l0] ORDER BY [l0].[Name] ) AS [t] LEFT JOIN ( - SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id] + SELECT [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id] FROM ( SELECT [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], ROW_NUMBER() OVER(PARTITION BY [l1].[OneToMany_Required_Inverse3Id] ORDER BY [l1].[Name] DESC) AS [row] FROM [LevelThree] AS [l1] WHERE ([l1].[Name] <> N'Bar') OR [l1].[Name] IS NULL - ) AS [t0] - WHERE 1 < [t0].[row] - ) AS [t1] ON [t].[Id] = [t1].[OneToMany_Required_Inverse3Id] + ) AS [t1] + WHERE 1 < [t1].[row] + ) AS [t0] ON [t].[Id] = [t0].[OneToMany_Required_Inverse3Id] ) AS [t2] ORDER BY [l].[Id], [t2].[Name], [t2].[Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[Name0] DESC, [t2].[Id0]"); } @@ -4847,15 +4847,15 @@ public override async Task Filtered_include_same_filter_set_on_same_navigation_t @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [t0].[Id], [t0].[Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Optional_Self_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToMany_Required_Self_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[OneToOne_Optional_Self2Id], [t0].[Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id], [t0].[Id1], [t0].[Level2_Optional_Id0], [t0].[Level2_Required_Id0], [t0].[Name1], [t0].[OneToMany_Optional_Inverse3Id0], [t0].[OneToMany_Optional_Self_Inverse3Id0], [t0].[OneToMany_Required_Inverse3Id0], [t0].[OneToMany_Required_Self_Inverse3Id0], [t0].[OneToOne_Optional_PK_Inverse3Id0], [t0].[OneToOne_Optional_Self3Id0] FROM [LevelOne] AS [l] OUTER APPLY ( - SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l1].[Id] AS [Id0], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], [l2].[Id] AS [Id1], [l2].[Level2_Optional_Id] AS [Level2_Optional_Id0], [l2].[Level2_Required_Id] AS [Level2_Required_Id0], [l2].[Name] AS [Name1], [l2].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [l2].[OneToMany_Optional_Self_Inverse3Id] AS [OneToMany_Optional_Self_Inverse3Id0], [l2].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [l2].[OneToMany_Required_Self_Inverse3Id] AS [OneToMany_Required_Self_Inverse3Id0], [l2].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [l2].[OneToOne_Optional_Self3Id] AS [OneToOne_Optional_Self3Id0] + SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l0].[Id] AS [Id0], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name] AS [Name0], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id], [l1].[Id] AS [Id1], [l1].[Level2_Optional_Id] AS [Level2_Optional_Id0], [l1].[Level2_Required_Id] AS [Level2_Required_Id0], [l1].[Name] AS [Name1], [l1].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [l1].[OneToMany_Optional_Self_Inverse3Id] AS [OneToMany_Optional_Self_Inverse3Id0], [l1].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [l1].[OneToMany_Required_Self_Inverse3Id] AS [OneToMany_Required_Self_Inverse3Id0], [l1].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [l1].[OneToOne_Optional_Self3Id] AS [OneToOne_Optional_Self3Id0] FROM ( - SELECT TOP(2) [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(2) [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Optional_Self_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToMany_Required_Self_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[OneToOne_Optional_Self2Id] + FROM [LevelTwo] AS [l2] + WHERE ([l].[Id] = [l2].[OneToMany_Optional_Inverse2Id]) AND (([l2].[Name] <> N'Foo') OR [l2].[Name] IS NULL) + ORDER BY [l2].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[Level2_Required_Id] - LEFT JOIN [LevelThree] AS [l2] ON [t].[Id] = [l2].[OneToMany_Optional_Inverse3Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[Level2_Required_Id] + LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[OneToMany_Optional_Inverse3Id] ) AS [t0] ORDER BY [l].[Id], [t0].[Id], [t0].[Id0], [t0].[Id1]"); } @@ -4870,15 +4870,15 @@ await base @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [t0].[Id], [t0].[Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Optional_Self_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToMany_Required_Self_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[OneToOne_Optional_Self2Id], [t0].[Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id], [t0].[Id1], [t0].[Level2_Optional_Id0], [t0].[Level2_Required_Id0], [t0].[Name1], [t0].[OneToMany_Optional_Inverse3Id0], [t0].[OneToMany_Optional_Self_Inverse3Id0], [t0].[OneToMany_Required_Inverse3Id0], [t0].[OneToMany_Required_Self_Inverse3Id0], [t0].[OneToOne_Optional_PK_Inverse3Id0], [t0].[OneToOne_Optional_Self3Id0] FROM [LevelOne] AS [l] OUTER APPLY ( - SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l1].[Id] AS [Id0], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], [l2].[Id] AS [Id1], [l2].[Level2_Optional_Id] AS [Level2_Optional_Id0], [l2].[Level2_Required_Id] AS [Level2_Required_Id0], [l2].[Name] AS [Name1], [l2].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [l2].[OneToMany_Optional_Self_Inverse3Id] AS [OneToMany_Optional_Self_Inverse3Id0], [l2].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [l2].[OneToMany_Required_Self_Inverse3Id] AS [OneToMany_Required_Self_Inverse3Id0], [l2].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [l2].[OneToOne_Optional_Self3Id] AS [OneToOne_Optional_Self3Id0] + SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l0].[Id] AS [Id0], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name] AS [Name0], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id], [l1].[Id] AS [Id1], [l1].[Level2_Optional_Id] AS [Level2_Optional_Id0], [l1].[Level2_Required_Id] AS [Level2_Required_Id0], [l1].[Name] AS [Name1], [l1].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [l1].[OneToMany_Optional_Self_Inverse3Id] AS [OneToMany_Optional_Self_Inverse3Id0], [l1].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [l1].[OneToMany_Required_Self_Inverse3Id] AS [OneToMany_Required_Self_Inverse3Id0], [l1].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [l1].[OneToOne_Optional_Self3Id] AS [OneToOne_Optional_Self3Id0] FROM ( - SELECT TOP(2) [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(2) [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Optional_Self_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToMany_Required_Self_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[OneToOne_Optional_Self2Id] + FROM [LevelTwo] AS [l2] + WHERE ([l].[Id] = [l2].[OneToMany_Optional_Inverse2Id]) AND (([l2].[Name] <> N'Foo') OR [l2].[Name] IS NULL) + ORDER BY [l2].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[Level2_Required_Id] - LEFT JOIN [LevelThree] AS [l2] ON [t].[Id] = [l2].[OneToMany_Optional_Inverse3Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[Level2_Required_Id] + LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[OneToMany_Optional_Inverse3Id] ) AS [t0] ORDER BY [l].[Id], [t0].[Id], [t0].[Id0], [t0].[Id1]"); } @@ -4929,19 +4929,19 @@ public override async Task Filtered_include_and_non_filtered_include_followed_by @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id], [t1].[Id], [t1].[Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Optional_Self_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToMany_Required_Self_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[OneToOne_Optional_Self2Id], [t1].[Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name0], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id], [t1].[Id1], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Name1], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Optional_Self_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToMany_Required_Self_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[OneToOne_Optional_Self4Id] FROM [LevelOne] AS [l] OUTER APPLY ( - SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l1].[Id] AS [Id0], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], [t0].[Id] AS [Id1], [t0].[Level3_Optional_Id], [t0].[Level3_Required_Id], [t0].[Name] AS [Name1], [t0].[OneToMany_Optional_Inverse4Id], [t0].[OneToMany_Optional_Self_Inverse4Id], [t0].[OneToMany_Required_Inverse4Id], [t0].[OneToMany_Required_Self_Inverse4Id], [t0].[OneToOne_Optional_PK_Inverse4Id], [t0].[OneToOne_Optional_Self4Id] + SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l0].[Id] AS [Id0], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name] AS [Name0], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id], [t0].[Id] AS [Id1], [t0].[Level3_Optional_Id], [t0].[Level3_Required_Id], [t0].[Name] AS [Name1], [t0].[OneToMany_Optional_Inverse4Id], [t0].[OneToMany_Optional_Self_Inverse4Id], [t0].[OneToMany_Required_Inverse4Id], [t0].[OneToMany_Required_Self_Inverse4Id], [t0].[OneToOne_Optional_PK_Inverse4Id], [t0].[OneToOne_Optional_Self4Id] FROM ( - SELECT TOP(1) [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(1) [l1].[Id], [l1].[Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Optional_Self_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToMany_Required_Self_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[OneToOne_Optional_Self2Id] + FROM [LevelTwo] AS [l1] + WHERE ([l].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) + ORDER BY [l1].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[OneToOne_Optional_PK_Inverse3Id] LEFT JOIN ( SELECT [l2].[Id], [l2].[Level3_Optional_Id], [l2].[Level3_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse4Id], [l2].[OneToMany_Optional_Self_Inverse4Id], [l2].[OneToMany_Required_Inverse4Id], [l2].[OneToMany_Required_Self_Inverse4Id], [l2].[OneToOne_Optional_PK_Inverse4Id], [l2].[OneToOne_Optional_Self4Id] FROM [LevelFour] AS [l2] WHERE [l2].[Id] > 1 - ) AS [t0] ON [l1].[Id] = [t0].[OneToMany_Optional_Inverse4Id] + ) AS [t0] ON [l0].[Id] = [t0].[OneToMany_Optional_Inverse4Id] ) AS [t1] ORDER BY [l].[Id], [t1].[Id], [t1].[Id0], [t1].[Id1]"); } @@ -4957,15 +4957,15 @@ LEFT JOIN ( SELECT [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name] AS [Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id], [t0].[Id0] AS [Id00], [t0].[Level3_Optional_Id], [t0].[Level3_Required_Id], [t0].[Name0] AS [Name00], [t0].[OneToMany_Optional_Inverse4Id], [t0].[OneToMany_Optional_Self_Inverse4Id], [t0].[OneToMany_Required_Inverse4Id], [t0].[OneToMany_Required_Self_Inverse4Id], [t0].[OneToOne_Optional_PK_Inverse4Id], [t0].[OneToOne_Optional_Self4Id], [t0].[Id1], [t0].[Level3_Optional_Id0], [t0].[Level3_Required_Id0], [t0].[Name1], [t0].[OneToMany_Optional_Inverse4Id0], [t0].[OneToMany_Optional_Self_Inverse4Id0], [t0].[OneToMany_Required_Inverse4Id0], [t0].[OneToMany_Required_Self_Inverse4Id0], [t0].[OneToOne_Optional_PK_Inverse4Id0], [t0].[OneToOne_Optional_Self4Id0] FROM [LevelTwo] AS [l0] OUTER APPLY ( - SELECT [t].[Id], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [l2].[Id] AS [Id0], [l2].[Level3_Optional_Id], [l2].[Level3_Required_Id], [l2].[Name] AS [Name0], [l2].[OneToMany_Optional_Inverse4Id], [l2].[OneToMany_Optional_Self_Inverse4Id], [l2].[OneToMany_Required_Inverse4Id], [l2].[OneToMany_Required_Self_Inverse4Id], [l2].[OneToOne_Optional_PK_Inverse4Id], [l2].[OneToOne_Optional_Self4Id], [l3].[Id] AS [Id1], [l3].[Level3_Optional_Id] AS [Level3_Optional_Id0], [l3].[Level3_Required_Id] AS [Level3_Required_Id0], [l3].[Name] AS [Name1], [l3].[OneToMany_Optional_Inverse4Id] AS [OneToMany_Optional_Inverse4Id0], [l3].[OneToMany_Optional_Self_Inverse4Id] AS [OneToMany_Optional_Self_Inverse4Id0], [l3].[OneToMany_Required_Inverse4Id] AS [OneToMany_Required_Inverse4Id0], [l3].[OneToMany_Required_Self_Inverse4Id] AS [OneToMany_Required_Self_Inverse4Id0], [l3].[OneToOne_Optional_PK_Inverse4Id] AS [OneToOne_Optional_PK_Inverse4Id0], [l3].[OneToOne_Optional_Self4Id] AS [OneToOne_Optional_Self4Id0] + SELECT [t].[Id], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [l1].[Id] AS [Id0], [l1].[Level3_Optional_Id], [l1].[Level3_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse4Id], [l1].[OneToMany_Optional_Self_Inverse4Id], [l1].[OneToMany_Required_Inverse4Id], [l1].[OneToMany_Required_Self_Inverse4Id], [l1].[OneToOne_Optional_PK_Inverse4Id], [l1].[OneToOne_Optional_Self4Id], [l2].[Id] AS [Id1], [l2].[Level3_Optional_Id] AS [Level3_Optional_Id0], [l2].[Level3_Required_Id] AS [Level3_Required_Id0], [l2].[Name] AS [Name1], [l2].[OneToMany_Optional_Inverse4Id] AS [OneToMany_Optional_Inverse4Id0], [l2].[OneToMany_Optional_Self_Inverse4Id] AS [OneToMany_Optional_Self_Inverse4Id0], [l2].[OneToMany_Required_Inverse4Id] AS [OneToMany_Required_Inverse4Id0], [l2].[OneToMany_Required_Self_Inverse4Id] AS [OneToMany_Required_Self_Inverse4Id0], [l2].[OneToOne_Optional_PK_Inverse4Id] AS [OneToOne_Optional_PK_Inverse4Id0], [l2].[OneToOne_Optional_Self4Id] AS [OneToOne_Optional_Self4Id0] FROM ( - SELECT TOP(1) [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id] - FROM [LevelThree] AS [l1] - WHERE ([l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) - ORDER BY [l1].[Id] + SELECT TOP(1) [l3].[Id], [l3].[Level2_Optional_Id], [l3].[Level2_Required_Id], [l3].[Name], [l3].[OneToMany_Optional_Inverse3Id], [l3].[OneToMany_Optional_Self_Inverse3Id], [l3].[OneToMany_Required_Inverse3Id], [l3].[OneToMany_Required_Self_Inverse3Id], [l3].[OneToOne_Optional_PK_Inverse3Id], [l3].[OneToOne_Optional_Self3Id] + FROM [LevelThree] AS [l3] + WHERE ([l0].[Id] = [l3].[OneToMany_Optional_Inverse3Id]) AND (([l3].[Name] <> N'Foo') OR [l3].[Name] IS NULL) + ORDER BY [l3].[Id] ) AS [t] - LEFT JOIN [LevelFour] AS [l2] ON [t].[Id] = [l2].[OneToMany_Optional_Inverse4Id] - LEFT JOIN [LevelFour] AS [l3] ON [t].[Id] = [l3].[OneToMany_Required_Inverse4Id] + LEFT JOIN [LevelFour] AS [l1] ON [t].[Id] = [l1].[OneToMany_Optional_Inverse4Id] + LEFT JOIN [LevelFour] AS [l2] ON [t].[Id] = [l2].[OneToMany_Required_Inverse4Id] ) AS [t0] ) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] ORDER BY [l].[Id], [t1].[Id], [t1].[Id0], [t1].[Id00], [t1].[Id1]"); @@ -4982,15 +4982,15 @@ LEFT JOIN ( SELECT [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name] AS [Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id], [t0].[Id0] AS [Id00], [t0].[Level3_Optional_Id], [t0].[Level3_Required_Id], [t0].[Name0] AS [Name00], [t0].[OneToMany_Optional_Inverse4Id], [t0].[OneToMany_Optional_Self_Inverse4Id], [t0].[OneToMany_Required_Inverse4Id], [t0].[OneToMany_Required_Self_Inverse4Id], [t0].[OneToOne_Optional_PK_Inverse4Id], [t0].[OneToOne_Optional_Self4Id], [t0].[Id1], [t0].[Level3_Optional_Id0], [t0].[Level3_Required_Id0], [t0].[Name1], [t0].[OneToMany_Optional_Inverse4Id0], [t0].[OneToMany_Optional_Self_Inverse4Id0], [t0].[OneToMany_Required_Inverse4Id0], [t0].[OneToMany_Required_Self_Inverse4Id0], [t0].[OneToOne_Optional_PK_Inverse4Id0], [t0].[OneToOne_Optional_Self4Id0] FROM [LevelTwo] AS [l0] OUTER APPLY ( - SELECT [t].[Id], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [l2].[Id] AS [Id0], [l2].[Level3_Optional_Id], [l2].[Level3_Required_Id], [l2].[Name] AS [Name0], [l2].[OneToMany_Optional_Inverse4Id], [l2].[OneToMany_Optional_Self_Inverse4Id], [l2].[OneToMany_Required_Inverse4Id], [l2].[OneToMany_Required_Self_Inverse4Id], [l2].[OneToOne_Optional_PK_Inverse4Id], [l2].[OneToOne_Optional_Self4Id], [l3].[Id] AS [Id1], [l3].[Level3_Optional_Id] AS [Level3_Optional_Id0], [l3].[Level3_Required_Id] AS [Level3_Required_Id0], [l3].[Name] AS [Name1], [l3].[OneToMany_Optional_Inverse4Id] AS [OneToMany_Optional_Inverse4Id0], [l3].[OneToMany_Optional_Self_Inverse4Id] AS [OneToMany_Optional_Self_Inverse4Id0], [l3].[OneToMany_Required_Inverse4Id] AS [OneToMany_Required_Inverse4Id0], [l3].[OneToMany_Required_Self_Inverse4Id] AS [OneToMany_Required_Self_Inverse4Id0], [l3].[OneToOne_Optional_PK_Inverse4Id] AS [OneToOne_Optional_PK_Inverse4Id0], [l3].[OneToOne_Optional_Self4Id] AS [OneToOne_Optional_Self4Id0] + SELECT [t].[Id], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [l1].[Id] AS [Id0], [l1].[Level3_Optional_Id], [l1].[Level3_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse4Id], [l1].[OneToMany_Optional_Self_Inverse4Id], [l1].[OneToMany_Required_Inverse4Id], [l1].[OneToMany_Required_Self_Inverse4Id], [l1].[OneToOne_Optional_PK_Inverse4Id], [l1].[OneToOne_Optional_Self4Id], [l2].[Id] AS [Id1], [l2].[Level3_Optional_Id] AS [Level3_Optional_Id0], [l2].[Level3_Required_Id] AS [Level3_Required_Id0], [l2].[Name] AS [Name1], [l2].[OneToMany_Optional_Inverse4Id] AS [OneToMany_Optional_Inverse4Id0], [l2].[OneToMany_Optional_Self_Inverse4Id] AS [OneToMany_Optional_Self_Inverse4Id0], [l2].[OneToMany_Required_Inverse4Id] AS [OneToMany_Required_Inverse4Id0], [l2].[OneToMany_Required_Self_Inverse4Id] AS [OneToMany_Required_Self_Inverse4Id0], [l2].[OneToOne_Optional_PK_Inverse4Id] AS [OneToOne_Optional_PK_Inverse4Id0], [l2].[OneToOne_Optional_Self4Id] AS [OneToOne_Optional_Self4Id0] FROM ( - SELECT TOP(1) [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id] - FROM [LevelThree] AS [l1] - WHERE ([l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) - ORDER BY [l1].[Id] + SELECT TOP(1) [l3].[Id], [l3].[Level2_Optional_Id], [l3].[Level2_Required_Id], [l3].[Name], [l3].[OneToMany_Optional_Inverse3Id], [l3].[OneToMany_Optional_Self_Inverse3Id], [l3].[OneToMany_Required_Inverse3Id], [l3].[OneToMany_Required_Self_Inverse3Id], [l3].[OneToOne_Optional_PK_Inverse3Id], [l3].[OneToOne_Optional_Self3Id] + FROM [LevelThree] AS [l3] + WHERE ([l0].[Id] = [l3].[OneToMany_Optional_Inverse3Id]) AND (([l3].[Name] <> N'Foo') OR [l3].[Name] IS NULL) + ORDER BY [l3].[Id] ) AS [t] - LEFT JOIN [LevelFour] AS [l2] ON [t].[Id] = [l2].[OneToMany_Optional_Inverse4Id] - LEFT JOIN [LevelFour] AS [l3] ON [t].[Id] = [l3].[OneToMany_Required_Inverse4Id] + LEFT JOIN [LevelFour] AS [l1] ON [t].[Id] = [l1].[OneToMany_Optional_Inverse4Id] + LEFT JOIN [LevelFour] AS [l2] ON [t].[Id] = [l2].[OneToMany_Required_Inverse4Id] ) AS [t0] ) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] ORDER BY [l].[Id], [t1].[Id], [t1].[Id0], [t1].[Id00], [t1].[Id1]"); @@ -5068,7 +5068,7 @@ public override async Task Filtered_include_outer_parameter_used_inside_filter(b await base.Filtered_include_outer_parameter_used_inside_filter(async); AssertSql( - @"SELECT [l].[Id], [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [t].[Id0], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name0], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [t1].[Id], [t1].[Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Optional_Self_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToMany_Required_Self_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[OneToOne_Optional_Self2Id], [t1].[Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name0], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id] + @"SELECT [l].[Id], [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [t].[Id0], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name0], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [t0].[Id], [t0].[Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Optional_Self_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToMany_Required_Self_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[OneToOne_Optional_Self2Id], [t0].[Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id] FROM [LevelOne] AS [l] OUTER APPLY ( SELECT [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id], [l1].[Id] AS [Id0], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id] @@ -5076,15 +5076,15 @@ FROM [LevelTwo] AS [l0] LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[OneToMany_Optional_Inverse3Id] ) AS [t] OUTER APPLY ( - SELECT [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Optional_Self_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToMany_Required_Self_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[OneToOne_Optional_Self2Id], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name] AS [Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id] + SELECT [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Optional_Self_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToMany_Required_Self_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[OneToOne_Optional_Self2Id], [t1].[Id] AS [Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name] AS [Name0], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id] FROM [LevelTwo] AS [l2] LEFT JOIN ( SELECT [l3].[Id], [l3].[Level2_Optional_Id], [l3].[Level2_Required_Id], [l3].[Name], [l3].[OneToMany_Optional_Inverse3Id], [l3].[OneToMany_Optional_Self_Inverse3Id], [l3].[OneToMany_Required_Inverse3Id], [l3].[OneToMany_Required_Self_Inverse3Id], [l3].[OneToOne_Optional_PK_Inverse3Id], [l3].[OneToOne_Optional_Self3Id] FROM [LevelThree] AS [l3] WHERE [l3].[Id] <> [l].[Id] - ) AS [t0] ON [l2].[Id] = [t0].[OneToMany_Optional_Inverse3Id] -) AS [t1] -ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t1].[Id], [t1].[Id0]"); + ) AS [t1] ON [l2].[Id] = [t1].[OneToMany_Optional_Inverse3Id] +) AS [t0] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); } public override async Task Filtered_include_basic_Where_split(bool async) @@ -5177,7 +5177,7 @@ WHERE 0 < [t].[row] ) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] ORDER BY [l].[Id], [t0].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Name]", // - @"SELECT [t2].[Id], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Optional_Self_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToMany_Required_Self_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[OneToOne_Optional_Self3Id], [l].[Id], [t0].[Id] + @"SELECT [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id], [l].[Id], [t0].[Id] FROM [LevelOne] AS [l] INNER JOIN ( SELECT [t].[Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id] @@ -5188,14 +5188,14 @@ FROM [LevelTwo] AS [l0] WHERE 0 < [t].[row] ) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] INNER JOIN ( - SELECT [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id] + SELECT [t2].[Id], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Optional_Self_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToMany_Required_Self_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[OneToOne_Optional_Self3Id] FROM ( SELECT [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], ROW_NUMBER() OVER(PARTITION BY [l1].[OneToMany_Optional_Inverse3Id] ORDER BY [l1].[Name] DESC) AS [row] FROM [LevelThree] AS [l1] - ) AS [t1] - WHERE 0 < [t1].[row] -) AS [t2] ON [t0].[Id] = [t2].[OneToMany_Optional_Inverse3Id] -ORDER BY [l].[Id], [t0].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[Name] DESC"); + ) AS [t2] + WHERE 0 < [t2].[row] +) AS [t1] ON [t0].[Id] = [t1].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t0].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[Name] DESC"); } public override async Task Filtered_include_basic_OrderBy_Take_split(bool async) @@ -5416,7 +5416,7 @@ FROM [LevelTwo] AS [l0] ) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] ORDER BY [l].[Id], [t0].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Name]", // - @"SELECT [t2].[Id], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Optional_Self_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToMany_Required_Self_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[OneToOne_Optional_Self3Id], [l].[Id], [t0].[Id] + @"SELECT [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id], [l].[Id], [t0].[Id] FROM [LevelOne] AS [l] INNER JOIN ( SELECT [t].[Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id] @@ -5428,15 +5428,15 @@ FROM [LevelTwo] AS [l0] WHERE [t].[row] <= 3 ) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] INNER JOIN ( - SELECT [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Optional_Self_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToMany_Required_Self_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[OneToOne_Optional_Self3Id] + SELECT [t2].[Id], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Optional_Self_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToMany_Required_Self_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[OneToOne_Optional_Self3Id] FROM ( SELECT [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], ROW_NUMBER() OVER(PARTITION BY [l1].[OneToMany_Required_Inverse3Id] ORDER BY [l1].[Name] DESC) AS [row] FROM [LevelThree] AS [l1] WHERE ([l1].[Name] <> N'Bar') OR [l1].[Name] IS NULL - ) AS [t1] - WHERE 1 < [t1].[row] -) AS [t2] ON [t0].[Id] = [t2].[OneToMany_Required_Inverse3Id] -ORDER BY [l].[Id], [t0].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Name], [t2].[OneToMany_Required_Inverse3Id], [t2].[Name] DESC"); + ) AS [t2] + WHERE 1 < [t2].[row] +) AS [t1] ON [t0].[Id] = [t1].[OneToMany_Required_Inverse3Id] +ORDER BY [l].[Id], [t0].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Name], [t1].[OneToMany_Required_Inverse3Id], [t1].[Name] DESC"); } public override async Task Filtered_include_same_filter_set_on_same_navigation_twice_split(bool async) @@ -5474,28 +5474,28 @@ FROM [LevelOne] AS [l] @"SELECT [t0].[Id], [t0].[Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Optional_Self_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToMany_Required_Self_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[OneToOne_Optional_Self2Id], [t0].[Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id], [l].[Id] FROM [LevelOne] AS [l] CROSS APPLY ( - SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l1].[Id] AS [Id0], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id] + SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l0].[Id] AS [Id0], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name] AS [Name0], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id] FROM ( - SELECT TOP(2) [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(2) [l1].[Id], [l1].[Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Optional_Self_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToMany_Required_Self_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[OneToOne_Optional_Self2Id] + FROM [LevelTwo] AS [l1] + WHERE ([l].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) + ORDER BY [l1].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[Level2_Required_Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[Level2_Required_Id] ) AS [t0] ORDER BY [l].[Id], [t0].[Id], [t0].[Id0]", // @"SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Optional_Self_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToMany_Required_Self_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[OneToOne_Optional_Self3Id], [l].[Id], [t0].[Id], [t0].[Id0] FROM [LevelOne] AS [l] CROSS APPLY ( - SELECT [t].[Id], [l1].[Id] AS [Id0] + SELECT [t].[Id], [l0].[Id] AS [Id0] FROM ( - SELECT TOP(2) [l0].[Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(2) [l1].[Id] + FROM [LevelTwo] AS [l1] + WHERE ([l].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) + ORDER BY [l1].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[Level2_Required_Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[Level2_Required_Id] ) AS [t0] INNER JOIN [LevelThree] AS [l2] ON [t0].[Id] = [l2].[OneToMany_Optional_Inverse3Id] ORDER BY [l].[Id], [t0].[Id], [t0].[Id0]"); @@ -5515,28 +5515,28 @@ FROM [LevelOne] AS [l] @"SELECT [t0].[Id], [t0].[Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Optional_Self_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToMany_Required_Self_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[OneToOne_Optional_Self2Id], [t0].[Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id], [l].[Id] FROM [LevelOne] AS [l] CROSS APPLY ( - SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l1].[Id] AS [Id0], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id] + SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l0].[Id] AS [Id0], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name] AS [Name0], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id] FROM ( - SELECT TOP(2) [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(2) [l1].[Id], [l1].[Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Optional_Self_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToMany_Required_Self_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[OneToOne_Optional_Self2Id] + FROM [LevelTwo] AS [l1] + WHERE ([l].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) + ORDER BY [l1].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[Level2_Required_Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[Level2_Required_Id] ) AS [t0] ORDER BY [l].[Id], [t0].[Id], [t0].[Id0]", // @"SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Optional_Self_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToMany_Required_Self_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[OneToOne_Optional_Self3Id], [l].[Id], [t0].[Id], [t0].[Id0] FROM [LevelOne] AS [l] CROSS APPLY ( - SELECT [t].[Id], [l1].[Id] AS [Id0] + SELECT [t].[Id], [l0].[Id] AS [Id0] FROM ( - SELECT TOP(2) [l0].[Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(2) [l1].[Id] + FROM [LevelTwo] AS [l1] + WHERE ([l].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) + ORDER BY [l1].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[Level2_Required_Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[Level2_Required_Id] ) AS [t0] INNER JOIN [LevelThree] AS [l2] ON [t0].[Id] = [l2].[OneToMany_Optional_Inverse3Id] ORDER BY [l].[Id], [t0].[Id], [t0].[Id0]"); @@ -5600,28 +5600,28 @@ FROM [LevelOne] AS [l] @"SELECT [t0].[Id], [t0].[Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Optional_Self_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToMany_Required_Self_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[OneToOne_Optional_Self2Id], [t0].[Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name0], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id], [l].[Id] FROM [LevelOne] AS [l] CROSS APPLY ( - SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l1].[Id] AS [Id0], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id] + SELECT [t].[Id], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [l0].[Id] AS [Id0], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name] AS [Name0], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id] FROM ( - SELECT TOP(1) [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Optional_Self_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToMany_Required_Self_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[OneToOne_Optional_Self2Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(1) [l1].[Id], [l1].[Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Optional_Self_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToMany_Required_Self_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[OneToOne_Optional_Self2Id] + FROM [LevelTwo] AS [l1] + WHERE ([l].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) + ORDER BY [l1].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[OneToOne_Optional_PK_Inverse3Id] ) AS [t0] ORDER BY [l].[Id], [t0].[Id], [t0].[Id0]", // @"SELECT [t1].[Id], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Optional_Self_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToMany_Required_Self_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[OneToOne_Optional_Self4Id], [l].[Id], [t0].[Id], [t0].[Id0] FROM [LevelOne] AS [l] CROSS APPLY ( - SELECT [t].[Id], [l1].[Id] AS [Id0] + SELECT [t].[Id], [l0].[Id] AS [Id0] FROM ( - SELECT TOP(1) [l0].[Id] - FROM [LevelTwo] AS [l0] - WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND (([l0].[Name] <> N'Foo') OR [l0].[Name] IS NULL) - ORDER BY [l0].[Id] + SELECT TOP(1) [l1].[Id] + FROM [LevelTwo] AS [l1] + WHERE ([l].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND (([l1].[Name] <> N'Foo') OR [l1].[Name] IS NULL) + ORDER BY [l1].[Id] ) AS [t] - LEFT JOIN [LevelThree] AS [l1] ON [t].[Id] = [l1].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN [LevelThree] AS [l0] ON [t].[Id] = [l0].[OneToOne_Optional_PK_Inverse3Id] ) AS [t0] INNER JOIN ( SELECT [l2].[Id], [l2].[Level3_Optional_Id], [l2].[Level3_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_Inverse4Id], [l2].[OneToMany_Optional_Self_Inverse4Id], [l2].[OneToMany_Required_Inverse4Id], [l2].[OneToMany_Required_Self_Inverse4Id], [l2].[OneToOne_Optional_PK_Inverse4Id], [l2].[OneToOne_Optional_Self4Id] @@ -5948,15 +5948,15 @@ SELECT TOP(1) [t0].[Name] FROM ( SELECT [t].[Id], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id] FROM ( - SELECT DISTINCT [l].[Id], [l].[Level2_Optional_Id], [l].[Level2_Required_Id], [l].[Name], [l].[OneToMany_Optional_Inverse3Id], [l].[OneToMany_Optional_Self_Inverse3Id], [l].[OneToMany_Required_Inverse3Id], [l].[OneToMany_Required_Self_Inverse3Id], [l].[OneToOne_Optional_PK_Inverse3Id], [l].[OneToOne_Optional_Self3Id] - FROM [LevelThree] AS [l] + SELECT DISTINCT [l0].[Id], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id] + FROM [LevelThree] AS [l0] ) AS [t] ORDER BY (SELECT 1) OFFSET 1 ROWS ) AS [t0] ORDER BY [t0].[Id]) -FROM [LevelOne] AS [l0] -WHERE [l0].[Id] < 3"); +FROM [LevelOne] AS [l] +WHERE [l].[Id] < 3"); } public override async Task Distinct_take_without_orderby(bool async) @@ -5967,12 +5967,12 @@ public override async Task Distinct_take_without_orderby(bool async) @"SELECT ( SELECT TOP(1) [t].[Name] FROM ( - SELECT DISTINCT TOP(1) [l].[Id], [l].[Level2_Optional_Id], [l].[Level2_Required_Id], [l].[Name], [l].[OneToMany_Optional_Inverse3Id], [l].[OneToMany_Optional_Self_Inverse3Id], [l].[OneToMany_Required_Inverse3Id], [l].[OneToMany_Required_Self_Inverse3Id], [l].[OneToOne_Optional_PK_Inverse3Id], [l].[OneToOne_Optional_Self3Id] - FROM [LevelThree] AS [l] + SELECT DISTINCT TOP(1) [l0].[Id], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id] + FROM [LevelThree] AS [l0] ) AS [t] ORDER BY [t].[Id]) -FROM [LevelOne] AS [l0] -WHERE [l0].[Id] < 3"); +FROM [LevelOne] AS [l] +WHERE [l].[Id] < 3"); } public override async Task Let_let_contains_from_outer_let(bool async) @@ -6049,12 +6049,12 @@ public override async Task Collection_FirstOrDefault_property_accesses_in_projec await base.Collection_FirstOrDefault_property_accesses_in_projection(async); AssertSql( - @"SELECT [l0].[Id], ( - SELECT TOP(1) [l].[Name] - FROM [LevelTwo] AS [l] - WHERE ([l0].[Id] = [l].[OneToMany_Optional_Inverse2Id]) AND ([l].[Name] = N'L2 02')) AS [Pushdown] -FROM [LevelOne] AS [l0] -WHERE [l0].[Id] < 3"); + @"SELECT [l].[Id], ( + SELECT TOP(1) [l0].[Name] + FROM [LevelTwo] AS [l0] + WHERE ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND ([l0].[Name] = N'L2 02')) AS [Pushdown] +FROM [LevelOne] AS [l] +WHERE [l].[Id] < 3"); } public override async Task Collection_FirstOrDefault_entity_reference_accesses_in_projection(bool async) @@ -6090,22 +6090,22 @@ public override async Task Multiple_collection_FirstOrDefault_followed_by_member await base.Multiple_collection_FirstOrDefault_followed_by_member_access_in_projection(async); AssertSql( - @"SELECT [l2].[Id], ( - SELECT TOP(1) [l].[Name] - FROM [LevelThree] AS [l] + @"SELECT [l].[Id], ( + SELECT TOP(1) [l0].[Name] + FROM [LevelThree] AS [l0] WHERE ( - SELECT TOP(1) [l0].[Id] - FROM [LevelTwo] AS [l0] - WHERE ([l2].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND ([l0].[Name] = N'L2 02')) IS NOT NULL AND ((( - SELECT TOP(1) [l1].[Id] - FROM [LevelTwo] AS [l1] - WHERE ([l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND ([l1].[Name] = N'L2 02')) = [l].[OneToMany_Optional_Inverse3Id]) OR (( SELECT TOP(1) [l1].[Id] FROM [LevelTwo] AS [l1] - WHERE ([l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND ([l1].[Name] = N'L2 02')) IS NULL AND [l].[OneToMany_Optional_Inverse3Id] IS NULL)) - ORDER BY [l].[Id]) AS [Pushdown] -FROM [LevelOne] AS [l2] -WHERE [l2].[Id] < 2"); + WHERE ([l].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND ([l1].[Name] = N'L2 02')) IS NOT NULL AND ((( + SELECT TOP(1) [l2].[Id] + FROM [LevelTwo] AS [l2] + WHERE ([l].[Id] = [l2].[OneToMany_Optional_Inverse2Id]) AND ([l2].[Name] = N'L2 02')) = [l0].[OneToMany_Optional_Inverse3Id]) OR (( + SELECT TOP(1) [l2].[Id] + FROM [LevelTwo] AS [l2] + WHERE ([l].[Id] = [l2].[OneToMany_Optional_Inverse2Id]) AND ([l2].[Name] = N'L2 02')) IS NULL AND [l0].[OneToMany_Optional_Inverse3Id] IS NULL)) + ORDER BY [l0].[Id]) AS [Pushdown] +FROM [LevelOne] AS [l] +WHERE [l].[Id] < 2"); } public override async Task Projecting_columns_with_same_name_from_different_entities_making_sure_aliasing_works_after_Distinct(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs index 058a6aed1a0..8ebd6ff5245 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs @@ -49,7 +49,7 @@ public override async Task Simple_level1_level2_include(bool async) { await base.Simple_level1_level2_include(async); AssertSql( - @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id] + @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id] FROM [Level1] AS [l] LEFT JOIN ( SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id] @@ -65,9 +65,9 @@ SELECT [l3].[Id] FROM [Level1] AS [l3] INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] + ) AS [t1] ON [l2].[Id] = [t1].[Id] WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[Id]"); +) AS [t0] ON [t].[Id] = [t0].[Id]"); } public override async Task Simple_level1_level2_GroupBy_Count(bool async) @@ -91,10 +91,10 @@ SELECT [l3].[Id] FROM [Level1] AS [l3] INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] + ) AS [t1] ON [l2].[Id] = [t1].[Id] WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[Id] -GROUP BY [t1].[Level3_Name]"); +) AS [t0] ON [t].[Id] = [t0].[Id] +GROUP BY [t0].[Level3_Name]"); } public override async Task Simple_level1_level2_GroupBy_Having_Count(bool async) @@ -118,10 +118,10 @@ SELECT [l3].[Id] FROM [Level1] AS [l3] INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] + ) AS [t1] ON [l2].[Id] = [t1].[Id] WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[Id] -GROUP BY [t1].[Level3_Name] +) AS [t0] ON [t].[Id] = [t0].[Id] +GROUP BY [t0].[Level3_Name] HAVING MIN(COALESCE([t].[Id], 0)) > 0"); } @@ -130,7 +130,7 @@ public override async Task Simple_level1_level2_level3_include(bool async) await base.Simple_level1_level2_level3_include(async); AssertSql( - @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t4].[Id], [t4].[Level3_Optional_Id], [t4].[Level3_Required_Id], [t4].[Level4_Name], [t4].[OneToMany_Optional_Inverse4Id], [t4].[OneToMany_Required_Inverse4Id], [t4].[OneToOne_Optional_PK_Inverse4Id] + @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t2].[Id], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id] FROM [Level1] AS [l] LEFT JOIN ( SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id] @@ -146,9 +146,9 @@ SELECT [l3].[Id] FROM [Level1] AS [l3] INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] + ) AS [t1] ON [l2].[Id] = [t1].[Id] WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[Id] +) AS [t0] ON [t].[Id] = [t0].[Id] LEFT JOIN ( SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id] FROM [Level1] AS [l5] @@ -160,11 +160,11 @@ SELECT [l7].[Id] FROM [Level1] AS [l7] INNER JOIN [Level1] AS [l8] ON [l7].[Id] = [l8].[Id] WHERE [l7].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l7].[Level1_Required_Id] IS NOT NULL AND [l7].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t2] ON [l6].[Id] = [t2].[Id] + ) AS [t4] ON [l6].[Id] = [t4].[Id] WHERE [l6].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l6].[Level2_Required_Id] IS NOT NULL ) AS [t3] ON [l5].[Id] = [t3].[Id] WHERE [l5].[OneToMany_Required_Inverse4Id] IS NOT NULL AND [l5].[Level3_Required_Id] IS NOT NULL -) AS [t4] ON [t1].[Id] = [t4].[Id]"); +) AS [t2] ON [t0].[Id] = [t2].[Id]"); } public override async Task Nested_group_join_with_take(bool async) @@ -174,7 +174,7 @@ public override async Task Nested_group_join_with_take(bool async) AssertSql( @"@__p_0='2' -SELECT [t3].[Level2_Name] +SELECT [t2].[Level2_Name] FROM ( SELECT TOP(@__p_0) [l].[Id], [t0].[Id0] AS [Id00] FROM [Level1] AS [l] @@ -192,16 +192,16 @@ WHERE [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l1].[Level1_Require ORDER BY [l].[Id] ) AS [t1] LEFT JOIN ( - SELECT [t2].[Level1_Optional_Id], [t2].[Level2_Name] + SELECT [t3].[Level1_Optional_Id], [t3].[Level2_Name] FROM [Level1] AS [l3] LEFT JOIN ( SELECT [l4].[Id], [l4].[OneToOne_Required_PK_Date], [l4].[Level1_Optional_Id], [l4].[Level1_Required_Id], [l4].[Level2_Name], [l4].[OneToMany_Required_Inverse2Id] FROM [Level1] AS [l4] INNER JOIN [Level1] AS [l5] ON [l4].[Id] = [l5].[Id] WHERE [l4].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l4].[Level1_Required_Id] IS NOT NULL AND [l4].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t2] ON [l3].[Id] = [t2].[Id] - WHERE ([t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL) AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL -) AS [t3] ON [t1].[Id00] = [t3].[Level1_Optional_Id] + ) AS [t3] ON [l3].[Id] = [t3].[Id] + WHERE ([t3].[OneToOne_Required_PK_Date] IS NOT NULL AND [t3].[Level1_Required_Id] IS NOT NULL) AND [t3].[OneToMany_Required_Inverse2Id] IS NOT NULL +) AS [t2] ON [t1].[Id00] = [t2].[Level1_Optional_Id] ORDER BY [t1].[Id]"); } @@ -257,7 +257,7 @@ public override async Task SelectMany_with_Include1(bool async) await base.SelectMany_with_Include1(async); AssertSql( - @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [l].[Id], [t].[Id0], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[Id0], [t1].[Id00] + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[Id0], [t0].[Id00] FROM [Level1] AS [l] INNER JOIN ( SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l1].[Id] AS [Id0] @@ -266,17 +266,17 @@ FROM [Level1] AS [l0] WHERE [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToOne_Required_PK_Date] IS NOT NULL) ) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] LEFT JOIN ( - SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [t0].[Id] AS [Id0], [t0].[Id0] AS [Id00] + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] FROM [Level1] AS [l2] INNER JOIN ( SELECT [l3].[Id], [l4].[Id] AS [Id0] FROM [Level1] AS [l3] INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] + ) AS [t1] ON [l2].[Id] = [t1].[Id] WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[OneToMany_Optional_Inverse3Id] -ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t1].[Id], [t1].[Id0], [t1].[Id00]"); +) AS [t0] ON [t].[Id] = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00]"); } public override async Task SelectMany_with_navigation_and_Distinct(bool async) @@ -284,7 +284,7 @@ public override async Task SelectMany_with_navigation_and_Distinct(bool async) await base.SelectMany_with_navigation_and_Distinct(async); AssertSql( - @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[Id0] + @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[Id0] FROM [Level1] AS [l] INNER JOIN ( SELECT DISTINCT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id] @@ -299,7 +299,7 @@ FROM [Level1] AS [l2] WHERE [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToOne_Required_PK_Date] IS NOT NULL) ) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] WHERE ([t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL) AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL -ORDER BY [l].[Id], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t0].[Id], [t0].[Id0]"); +ORDER BY [l].[Id], [t].[Id], [t0].[Id], [t0].[Id0]"); } public override async Task SelectMany_with_navigation_and_Distinct_projecting_columns_including_join_key(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 45e87a3c83a..06f0730c795 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -532,22 +532,22 @@ public override async Task Where_enum_has_flag_subquery(bool async) @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE ([g].[Rank] & COALESCE(( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId]), 0)) = COALESCE(( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId]), 0)", + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId]), 0)) = COALESCE(( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId]), 0)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE (2 & COALESCE(( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId]), 0)) = COALESCE(( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId]), 0)"); + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId]), 0)) = COALESCE(( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId]), 0)"); } public override async Task Where_enum_has_flag_subquery_with_pushdown(bool async) @@ -558,28 +558,28 @@ public override async Task Where_enum_has_flag_subquery_with_pushdown(bool async @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE (([g].[Rank] & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL", + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId])) = ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId])) OR ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE ((2 & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL"); + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId])) = ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId])) OR ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL"); } public override async Task Where_enum_has_flag_subquery_client_eval(bool async) @@ -590,15 +590,15 @@ public override async Task Where_enum_has_flag_subquery_client_eval(bool async) @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE (([g].[Rank] & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL"); + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId])) = ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId])) OR ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL"); } public override async Task Where_enum_has_flag_with_non_nullable_parameter(bool async) @@ -1670,16 +1670,16 @@ public override async Task Union_with_collection_navigations(bool async) @"SELECT ( SELECT COUNT(*) FROM ( - SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] - FROM [Gears] AS [g] - WHERE ([g1].[Nickname] = [g].[LeaderNickname]) AND ([g1].[SquadId] = [g].[LeaderSquadId]) - UNION SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank] FROM [Gears] AS [g0] - WHERE ([g1].[Nickname] = [g0].[LeaderNickname]) AND ([g1].[SquadId] = [g0].[LeaderSquadId]) + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId]) + UNION + SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[Discriminator], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank] + FROM [Gears] AS [g1] + WHERE ([g].[Nickname] = [g1].[LeaderNickname]) AND ([g].[SquadId] = [g1].[LeaderSquadId]) ) AS [t]) -FROM [Gears] AS [g1] -WHERE [g1].[Discriminator] = N'Officer'"); +FROM [Gears] AS [g] +WHERE [g].[Discriminator] = N'Officer'"); } public override async Task Select_subquery_distinct_firstordefault(bool async) @@ -3969,20 +3969,20 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery(async); AssertSql( - @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [g0].[Nickname], [g0].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId], [t0].[Nickname], [t0].[SquadId] + @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [g1].[Nickname], [g1].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId], [t0].[Nickname], [t0].[SquadId] FROM [Gears] AS [g] LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) -LEFT JOIN [Gears] AS [g0] ON ([t].[GearNickName] = [g0].[Nickname]) AND ([t].[GearSquadId] = [g0].[SquadId]) +LEFT JOIN [Gears] AS [g1] ON ([t].[GearNickName] = [g1].[Nickname]) AND ([t].[GearSquadId] = [g1].[SquadId]) LEFT JOIN ( - SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [g1].[Nickname], [g1].[SquadId] + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [g2].[Nickname], [g2].[SquadId] FROM [Weapons] AS [w] - LEFT JOIN [Gears] AS [g1] ON [w].[OwnerFullName] = [g1].[FullName] -) AS [t0] ON [g0].[FullName] = [t0].[OwnerFullName] + LEFT JOIN [Gears] AS [g2] ON [w].[OwnerFullName] = [g2].[FullName] +) AS [t0] ON [g1].[FullName] = [t0].[OwnerFullName] WHERE ([g].[Discriminator] = N'Officer') AND EXISTS ( SELECT 1 - FROM [Gears] AS [g2] - WHERE ([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId])) -ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [g0].[Nickname], [g0].[SquadId], [t0].[IsAutomatic], [t0].[Nickname] DESC, [t0].[Id], [t0].[SquadId]"); + FROM [Gears] AS [g0] + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) +ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [g1].[Nickname], [g1].[SquadId], [t0].[IsAutomatic], [t0].[Nickname] DESC, [t0].[Id], [t0].[SquadId]"); } public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_duplicated_orderings( @@ -3991,20 +3991,20 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_duplicated_orderings(async); AssertSql( - @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [g0].[Nickname], [g0].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId], [t0].[Nickname], [t0].[SquadId] + @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [g1].[Nickname], [g1].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId], [t0].[Nickname], [t0].[SquadId] FROM [Gears] AS [g] LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) -LEFT JOIN [Gears] AS [g0] ON ([t].[GearNickName] = [g0].[Nickname]) AND ([t].[GearSquadId] = [g0].[SquadId]) +LEFT JOIN [Gears] AS [g1] ON ([t].[GearNickName] = [g1].[Nickname]) AND ([t].[GearSquadId] = [g1].[SquadId]) LEFT JOIN ( - SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [g1].[Nickname], [g1].[SquadId] + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [g2].[Nickname], [g2].[SquadId] FROM [Weapons] AS [w] - LEFT JOIN [Gears] AS [g1] ON [w].[OwnerFullName] = [g1].[FullName] -) AS [t0] ON [g0].[FullName] = [t0].[OwnerFullName] + LEFT JOIN [Gears] AS [g2] ON [w].[OwnerFullName] = [g2].[FullName] +) AS [t0] ON [g1].[FullName] = [t0].[OwnerFullName] WHERE ([g].[Discriminator] = N'Officer') AND EXISTS ( SELECT 1 - FROM [Gears] AS [g2] - WHERE ([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId])) -ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [g0].[Nickname], [g0].[SquadId], [t0].[IsAutomatic], [t0].[Nickname] DESC, [t0].[Id], [t0].[SquadId]"); + FROM [Gears] AS [g0] + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) +ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [g1].[Nickname], [g1].[SquadId], [t0].[IsAutomatic], [t0].[Nickname] DESC, [t0].[Id], [t0].[SquadId]"); } public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings( @@ -4013,23 +4013,23 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings(async); AssertSql( - @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [g0].[Nickname], [g0].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId], [t0].[Nickname], [t0].[SquadId] + @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [g1].[Nickname], [g1].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId], [t0].[Nickname], [t0].[SquadId] FROM [Gears] AS [g] LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) -LEFT JOIN [Gears] AS [g0] ON ([t].[GearNickName] = [g0].[Nickname]) AND ([t].[GearSquadId] = [g0].[SquadId]) +LEFT JOIN [Gears] AS [g1] ON ([t].[GearNickName] = [g1].[Nickname]) AND ([t].[GearSquadId] = [g1].[SquadId]) LEFT JOIN ( - SELECT [w0].[Id], [w0].[AmmunitionType], [w0].[IsAutomatic], [w0].[Name], [w0].[OwnerFullName], [w0].[SynergyWithId], [g1].[Nickname], [g1].[SquadId], ( + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [g2].[Nickname], [g2].[SquadId], ( SELECT COUNT(*) - FROM [Weapons] AS [w] - WHERE [g1].[FullName] IS NOT NULL AND ([g1].[FullName] = [w].[OwnerFullName])) AS [c] - FROM [Weapons] AS [w0] - LEFT JOIN [Gears] AS [g1] ON [w0].[OwnerFullName] = [g1].[FullName] -) AS [t0] ON [g0].[FullName] = [t0].[OwnerFullName] + FROM [Weapons] AS [w0] + WHERE [g2].[FullName] IS NOT NULL AND ([g2].[FullName] = [w0].[OwnerFullName])) AS [c] + FROM [Weapons] AS [w] + LEFT JOIN [Gears] AS [g2] ON [w].[OwnerFullName] = [g2].[FullName] +) AS [t0] ON [g1].[FullName] = [t0].[OwnerFullName] WHERE ([g].[Discriminator] = N'Officer') AND EXISTS ( SELECT 1 - FROM [Gears] AS [g2] - WHERE ([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId])) -ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [g0].[Nickname], [g0].[SquadId], [t0].[Id] DESC, [t0].[c], [t0].[Nickname], [t0].[SquadId]"); + FROM [Gears] AS [g0] + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) +ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [g1].[Nickname], [g1].[SquadId], [t0].[Id] DESC, [t0].[c], [t0].[Nickname], [t0].[SquadId]"); } public override async Task Correlated_collections_multiple_nested_complex_collections(bool async) @@ -4037,37 +4037,37 @@ public override async Task Correlated_collections_multiple_nested_complex_collec await base.Correlated_collections_multiple_nested_complex_collections(async); AssertSql( - @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [g0].[Nickname], [g0].[SquadId], [t2].[FullName], [t2].[Nickname], [t2].[SquadId], [t2].[Id], [t2].[Nickname0], [t2].[SquadId0], [t2].[Id0], [t2].[Name], [t2].[IsAutomatic], [t2].[Id1], [t2].[Nickname00], [t2].[HasSoulPatch], [t2].[SquadId00], [t3].[Id], [t3].[AmmunitionType], [t3].[IsAutomatic], [t3].[Name], [t3].[OwnerFullName], [t3].[SynergyWithId], [t3].[Nickname], [t3].[SquadId] + @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [g1].[Nickname], [g1].[SquadId], [t1].[FullName], [t1].[Nickname], [t1].[SquadId], [t1].[Id], [t1].[Nickname0], [t1].[SquadId0], [t1].[Id0], [t1].[Name], [t1].[IsAutomatic], [t1].[Id1], [t1].[Nickname00], [t1].[HasSoulPatch], [t1].[SquadId00], [t3].[Id], [t3].[AmmunitionType], [t3].[IsAutomatic], [t3].[Name], [t3].[OwnerFullName], [t3].[SynergyWithId], [t3].[Nickname], [t3].[SquadId] FROM [Gears] AS [g] LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) -LEFT JOIN [Gears] AS [g0] ON ([t].[GearNickName] = [g0].[Nickname]) AND ([t].[GearSquadId] = [g0].[SquadId]) +LEFT JOIN [Gears] AS [g1] ON ([t].[GearNickName] = [g1].[Nickname]) AND ([t].[GearSquadId] = [g1].[SquadId]) LEFT JOIN ( - SELECT [g1].[FullName], [g1].[Nickname], [g1].[SquadId], [t1].[Id], [t1].[Nickname] AS [Nickname0], [t1].[SquadId] AS [SquadId0], [t1].[Id0], [t1].[Name], [t1].[IsAutomatic], [t1].[Id1], [t1].[Nickname0] AS [Nickname00], [t1].[HasSoulPatch], [t1].[SquadId0] AS [SquadId00], [g1].[Rank], [t1].[IsAutomatic0], [g1].[LeaderNickname], [g1].[LeaderSquadId] - FROM [Gears] AS [g1] + SELECT [g2].[FullName], [g2].[Nickname], [g2].[SquadId], [t0].[Id], [t0].[Nickname] AS [Nickname0], [t0].[SquadId] AS [SquadId0], [t0].[Id0], [t0].[Name], [t0].[IsAutomatic], [t0].[Id1], [t0].[Nickname0] AS [Nickname00], [t0].[HasSoulPatch], [t0].[SquadId0] AS [SquadId00], [g2].[Rank], [t0].[IsAutomatic0], [g2].[LeaderNickname], [g2].[LeaderSquadId] + FROM [Gears] AS [g2] LEFT JOIN ( - SELECT [w].[Id], [g2].[Nickname], [g2].[SquadId], [s].[Id] AS [Id0], [w0].[Name], [w0].[IsAutomatic], [w0].[Id] AS [Id1], [t0].[Nickname] AS [Nickname0], [t0].[HasSoulPatch], [t0].[SquadId] AS [SquadId0], [w].[IsAutomatic] AS [IsAutomatic0], [w].[OwnerFullName] + SELECT [w].[Id], [g3].[Nickname], [g3].[SquadId], [s].[Id] AS [Id0], [w0].[Name], [w0].[IsAutomatic], [w0].[Id] AS [Id1], [t2].[Nickname] AS [Nickname0], [t2].[HasSoulPatch], [t2].[SquadId] AS [SquadId0], [w].[IsAutomatic] AS [IsAutomatic0], [w].[OwnerFullName] FROM [Weapons] AS [w] - LEFT JOIN [Gears] AS [g2] ON [w].[OwnerFullName] = [g2].[FullName] - LEFT JOIN [Squads] AS [s] ON [g2].[SquadId] = [s].[Id] - LEFT JOIN [Weapons] AS [w0] ON [g2].[FullName] = [w0].[OwnerFullName] + LEFT JOIN [Gears] AS [g3] ON [w].[OwnerFullName] = [g3].[FullName] + LEFT JOIN [Squads] AS [s] ON [g3].[SquadId] = [s].[Id] + LEFT JOIN [Weapons] AS [w0] ON [g3].[FullName] = [w0].[OwnerFullName] LEFT JOIN ( - SELECT [g3].[Nickname], [g3].[HasSoulPatch], [g3].[SquadId] - FROM [Gears] AS [g3] - ) AS [t0] ON [s].[Id] = [t0].[SquadId] + SELECT [g4].[Nickname], [g4].[HasSoulPatch], [g4].[SquadId] + FROM [Gears] AS [g4] + ) AS [t2] ON [s].[Id] = [t2].[SquadId] WHERE ([w].[Name] <> N'Bar') OR [w].[Name] IS NULL - ) AS [t1] ON [g1].[FullName] = [t1].[OwnerFullName] - WHERE [g1].[FullName] <> N'Foo' -) AS [t2] ON ([g].[Nickname] = [t2].[LeaderNickname]) AND ([g].[SquadId] = [t2].[LeaderSquadId]) + ) AS [t0] ON [g2].[FullName] = [t0].[OwnerFullName] + WHERE [g2].[FullName] <> N'Foo' +) AS [t1] ON ([g].[Nickname] = [t1].[LeaderNickname]) AND ([g].[SquadId] = [t1].[LeaderSquadId]) LEFT JOIN ( - SELECT [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[SynergyWithId], [g4].[Nickname], [g4].[SquadId] + SELECT [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[SynergyWithId], [g5].[Nickname], [g5].[SquadId] FROM [Weapons] AS [w1] - LEFT JOIN [Gears] AS [g4] ON [w1].[OwnerFullName] = [g4].[FullName] -) AS [t3] ON [g0].[FullName] = [t3].[OwnerFullName] + LEFT JOIN [Gears] AS [g5] ON [w1].[OwnerFullName] = [g5].[FullName] +) AS [t3] ON [g1].[FullName] = [t3].[OwnerFullName] WHERE ([g].[Discriminator] = N'Officer') AND EXISTS ( SELECT 1 - FROM [Gears] AS [g5] - WHERE ([g].[Nickname] = [g5].[LeaderNickname]) AND ([g].[SquadId] = [g5].[LeaderSquadId])) -ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [g0].[Nickname], [g0].[SquadId], [t2].[Rank], [t2].[Nickname], [t2].[SquadId], [t2].[IsAutomatic0], [t2].[Id], [t2].[Nickname0], [t2].[SquadId0], [t2].[Id0], [t2].[Id1], [t2].[Nickname00], [t2].[SquadId00], [t3].[IsAutomatic], [t3].[Nickname] DESC, [t3].[Id], [t3].[SquadId]"); + FROM [Gears] AS [g0] + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) +ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [g1].[Nickname], [g1].[SquadId], [t1].[Rank], [t1].[Nickname], [t1].[SquadId], [t1].[IsAutomatic0], [t1].[Id], [t1].[Nickname0], [t1].[SquadId0], [t1].[Id0], [t1].[Id1], [t1].[Nickname00], [t1].[SquadId00], [t3].[IsAutomatic], [t3].[Nickname] DESC, [t3].[Id], [t3].[SquadId]"); } public override async Task Correlated_collections_inner_subquery_selector_references_outer_qsre(bool async) @@ -4296,21 +4296,21 @@ public override async Task Correlated_collections_deeply_nested_left_join(bool a await base.Correlated_collections_deeply_nested_left_join(async); AssertSql( - @"SELECT [t].[Id], [g].[Nickname], [g].[SquadId], [s].[Id], [t1].[Nickname], [t1].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId] + @"SELECT [t].[Id], [g].[Nickname], [g].[SquadId], [s].[Id], [t0].[Nickname], [t0].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId] FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] LEFT JOIN [Squads] AS [s] ON [g].[SquadId] = [s].[Id] LEFT JOIN ( - SELECT [g0].[Nickname], [g0].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId] + SELECT [g0].[Nickname], [g0].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId] FROM [Gears] AS [g0] LEFT JOIN ( SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] WHERE [w].[IsAutomatic] = CAST(1 AS bit) - ) AS [t0] ON [g0].[FullName] = [t0].[OwnerFullName] + ) AS [t1] ON [g0].[FullName] = [t1].[OwnerFullName] WHERE [g0].[HasSoulPatch] = CAST(1 AS bit) -) AS [t1] ON [s].[Id] = [t1].[SquadId] -ORDER BY [t].[Note], [g].[Nickname] DESC, [t].[Id], [g].[SquadId], [s].[Id], [t1].[Nickname], [t1].[SquadId], [t1].[Id]"); +) AS [t0] ON [s].[Id] = [t0].[SquadId] +ORDER BY [t].[Note], [g].[Nickname] DESC, [t].[Id], [g].[SquadId], [s].[Id], [t0].[Nickname], [t0].[SquadId], [t0].[Id]"); } public override async Task Correlated_collections_from_left_join_with_additional_elements_projected_of_that_join(bool async) @@ -5058,18 +5058,18 @@ public override async Task Correlated_collection_with_very_complex_order_by(bool @"SELECT [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId], [t].[AssignedCityName], [t].[CityOfBirthName], [t].[Discriminator], [t].[FullName], [t].[HasSoulPatch], [t].[LeaderNickname], [t].[LeaderSquadId], [t].[Rank] FROM [Gears] AS [g] LEFT JOIN ( - SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank] - FROM [Gears] AS [g0] - WHERE [g0].[HasSoulPatch] = CAST(0 AS bit) + SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[Discriminator], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank] + FROM [Gears] AS [g1] + WHERE [g1].[HasSoulPatch] = CAST(0 AS bit) ) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [g].[Discriminator] = N'Officer' ORDER BY ( SELECT COUNT(*) FROM [Weapons] AS [w] WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[IsAutomatic] = COALESCE(( - SELECT TOP(1) [g1].[HasSoulPatch] - FROM [Gears] AS [g1] - WHERE [g1].[Nickname] = N'Marcus'), CAST(0 AS bit)))), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); + SELECT TOP(1) [g0].[HasSoulPatch] + FROM [Gears] AS [g0] + WHERE [g0].[Nickname] = N'Marcus'), CAST(0 AS bit)))), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } public override async Task Cast_to_derived_type_after_OfType_works(bool async) @@ -5902,13 +5902,13 @@ public override async Task Include_with_complex_order_by(bool async) await base.Include_with_complex_order_by(async); AssertSql( - @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [w0].[Id], [w0].[AmmunitionType], [w0].[IsAutomatic], [w0].[Name], [w0].[OwnerFullName], [w0].[SynergyWithId] FROM [Gears] AS [g] -LEFT JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] +LEFT JOIN [Weapons] AS [w0] ON [g].[FullName] = [w0].[OwnerFullName] ORDER BY ( - SELECT TOP(1) [w0].[Name] - FROM [Weapons] AS [w0] - WHERE ([g].[FullName] = [w0].[OwnerFullName]) AND ([w0].[Name] LIKE N'%Gnasher%')), [g].[Nickname], [g].[SquadId], [w].[Id]"); + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] LIKE N'%Gnasher%')), [g].[Nickname], [g].[SquadId], [w0].[Id]"); } public override async Task Anonymous_projection_take_followed_by_projecting_single_element_from_collection_navigation(bool async) @@ -5986,19 +5986,19 @@ public override async Task Project_collection_navigation_nested_with_take_compos await base.Project_collection_navigation_nested_with_take_composite_key(async); AssertSql( - @"SELECT [t].[Id], [g].[Nickname], [g].[SquadId], [t1].[Nickname], [t1].[SquadId], [t1].[AssignedCityName], [t1].[CityOfBirthName], [t1].[Discriminator], [t1].[FullName], [t1].[HasSoulPatch], [t1].[LeaderNickname], [t1].[LeaderSquadId], [t1].[Rank] + @"SELECT [t].[Id], [g].[Nickname], [g].[SquadId], [t0].[Nickname], [t0].[SquadId], [t0].[AssignedCityName], [t0].[CityOfBirthName], [t0].[Discriminator], [t0].[FullName], [t0].[HasSoulPatch], [t0].[LeaderNickname], [t0].[LeaderSquadId], [t0].[Rank] FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON ([t].[GearNickName] = [g].[Nickname]) AND ([t].[GearSquadId] = [g].[SquadId]) LEFT JOIN ( - SELECT [t0].[Nickname], [t0].[SquadId], [t0].[AssignedCityName], [t0].[CityOfBirthName], [t0].[Discriminator], [t0].[FullName], [t0].[HasSoulPatch], [t0].[LeaderNickname], [t0].[LeaderSquadId], [t0].[Rank] + SELECT [t1].[Nickname], [t1].[SquadId], [t1].[AssignedCityName], [t1].[CityOfBirthName], [t1].[Discriminator], [t1].[FullName], [t1].[HasSoulPatch], [t1].[LeaderNickname], [t1].[LeaderSquadId], [t1].[Rank] FROM ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], ROW_NUMBER() OVER(PARTITION BY [g0].[LeaderNickname], [g0].[LeaderSquadId] ORDER BY [g0].[Nickname], [g0].[SquadId]) AS [row] FROM [Gears] AS [g0] - ) AS [t0] - WHERE [t0].[row] <= 50 -) AS [t1] ON (([g].[Nickname] = [t1].[LeaderNickname]) OR ([g].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND ([g].[SquadId] = [t1].[LeaderSquadId]) + ) AS [t1] + WHERE [t1].[row] <= 50 +) AS [t0] ON (([g].[Nickname] = [t0].[LeaderNickname]) OR ([g].[Nickname] IS NULL AND [t0].[LeaderNickname] IS NULL)) AND ([g].[SquadId] = [t0].[LeaderSquadId]) WHERE [g].[Discriminator] = N'Officer' -ORDER BY [t].[Id], [g].[Nickname], [g].[SquadId], [t1].[LeaderNickname], [t1].[LeaderSquadId], [t1].[Nickname], [t1].[SquadId]"); +ORDER BY [t].[Id], [g].[Nickname], [g].[SquadId], [t0].[LeaderNickname], [t0].[LeaderSquadId], [t0].[Nickname], [t0].[SquadId]"); } public override async Task Project_collection_navigation_nested_composite_key(bool async) @@ -6358,15 +6358,15 @@ public override async Task Complex_GroupBy_after_set_operator(bool async) FROM ( SELECT [c].[Name], ( SELECT COUNT(*) - FROM [Weapons] AS [w] - WHERE [g].[FullName] = [w].[OwnerFullName]) AS [Count] + FROM [Weapons] AS [w0] + WHERE [g].[FullName] = [w0].[OwnerFullName]) AS [Count] FROM [Gears] AS [g] LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] UNION ALL SELECT [c0].[Name], ( SELECT COUNT(*) - FROM [Weapons] AS [w0] - WHERE [g0].[FullName] = [w0].[OwnerFullName]) AS [Count] + FROM [Weapons] AS [w] + WHERE [g0].[FullName] = [w].[OwnerFullName]) AS [Count] FROM [Gears] AS [g0] INNER JOIN [Cities] AS [c0] ON [g0].[CityOfBirthName] = [c0].[Name] ) AS [t] @@ -6382,15 +6382,15 @@ public override async Task Complex_GroupBy_after_set_operator_using_result_selec FROM ( SELECT [c].[Name], ( SELECT COUNT(*) - FROM [Weapons] AS [w] - WHERE [g].[FullName] = [w].[OwnerFullName]) AS [Count] + FROM [Weapons] AS [w0] + WHERE [g].[FullName] = [w0].[OwnerFullName]) AS [Count] FROM [Gears] AS [g] LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] UNION ALL SELECT [c0].[Name], ( SELECT COUNT(*) - FROM [Weapons] AS [w0] - WHERE [g0].[FullName] = [w0].[OwnerFullName]) AS [Count] + FROM [Weapons] AS [w] + WHERE [g0].[FullName] = [w].[OwnerFullName]) AS [Count] FROM [Gears] AS [g0] INNER JOIN [Cities] AS [c0] ON [g0].[CityOfBirthName] = [c0].[Name] ) AS [t] @@ -7381,17 +7381,17 @@ public override async Task FirstOrDefault_on_empty_collection_of_DateTime_in_sub AssertSql( @"SELECT [g].[Nickname], COALESCE(( - SELECT TOP(1) [t].[IssueDate] - FROM [Tags] AS [t] - WHERE [t].[GearNickName] = [g].[FullName] - ORDER BY [t].[Id]), '0001-01-01T00:00:00.0000000') AS [invalidTagIssueDate] -FROM [Gears] AS [g] -LEFT JOIN [Tags] AS [t0] ON ([g].[Nickname] = [t0].[GearNickName]) AND ([g].[SquadId] = [t0].[GearSquadId]) -WHERE [t0].[IssueDate] > COALESCE(( SELECT TOP(1) [t1].[IssueDate] FROM [Tags] AS [t1] WHERE [t1].[GearNickName] = [g].[FullName] - ORDER BY [t1].[Id]), '0001-01-01T00:00:00.0000000')"); + ORDER BY [t1].[Id]), '0001-01-01T00:00:00.0000000') AS [invalidTagIssueDate] +FROM [Gears] AS [g] +LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) +WHERE [t].[IssueDate] > COALESCE(( + SELECT TOP(1) [t0].[IssueDate] + FROM [Tags] AS [t0] + WHERE [t0].[GearNickName] = [g].[FullName] + ORDER BY [t0].[Id]), '0001-01-01T00:00:00.0000000')"); } public override async Task First_on_byte_array(bool async) @@ -7896,13 +7896,13 @@ public override async Task Correlated_collection_after_distinct_3_levels(bool as await base.Correlated_collection_after_distinct_3_levels(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t2].[Nickname], [t2].[FullName], [t2].[HasSoulPatch], [t2].[Id], [t2].[Name], [t2].[Nickname0], [t2].[FullName0], [t2].[HasSoulPatch0], [t2].[Id0] + @"SELECT [t].[Id], [t].[Name], [t1].[Nickname], [t1].[FullName], [t1].[HasSoulPatch], [t1].[Id], [t1].[Name], [t1].[Nickname0], [t1].[FullName0], [t1].[HasSoulPatch0], [t1].[Id0] FROM ( SELECT DISTINCT [s].[Id], [s].[Name] FROM [Squads] AS [s] ) AS [t] OUTER APPLY ( - SELECT [t0].[Nickname], [t0].[FullName], [t0].[HasSoulPatch], [t1].[Id], [t1].[Name], [t1].[Nickname] AS [Nickname0], [t1].[FullName] AS [FullName0], [t1].[HasSoulPatch] AS [HasSoulPatch0], [t1].[Id0] + SELECT [t0].[Nickname], [t0].[FullName], [t0].[HasSoulPatch], [t2].[Id], [t2].[Name], [t2].[Nickname] AS [Nickname0], [t2].[FullName] AS [FullName0], [t2].[HasSoulPatch] AS [HasSoulPatch0], [t2].[Id0] FROM ( SELECT DISTINCT [g].[Nickname], [g].[FullName], [g].[HasSoulPatch] FROM [Gears] AS [g] @@ -7912,9 +7912,9 @@ OUTER APPLY ( SELECT [t].[Id], [t].[Name], [t0].[Nickname], [t0].[FullName], [t0].[HasSoulPatch], [w].[Id] AS [Id0] FROM [Weapons] AS [w] WHERE [t0].[FullName] = [w].[OwnerFullName] - ) AS [t1] -) AS [t2] -ORDER BY [t].[Id], [t2].[Nickname], [t2].[FullName], [t2].[HasSoulPatch], [t2].[Id0]"); + ) AS [t2] +) AS [t1] +ORDER BY [t].[Id], [t1].[Nickname], [t1].[FullName], [t1].[HasSoulPatch], [t1].[Id0]"); } public override async Task Correlated_collection_after_distinct_3_levels_without_original_identifiers(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyNoTrackingQuerySqlServerTest.cs index 49c783cae7c..5e6a6130b5e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyNoTrackingQuerySqlServerTest.cs @@ -197,12 +197,12 @@ public override async Task Skip_navigation_select_subquery_average(bool async) AssertSql( @"SELECT ( - SELECT AVG(CAST([e].[Key1] AS float)) + SELECT AVG(CAST([e0].[Key1] AS float)) FROM [JoinCompositeKeyToLeaf] AS [j] - INNER JOIN [EntityCompositeKeys] AS [e] ON (([j].[CompositeId1] = [e].[Key1]) AND ([j].[CompositeId2] = [e].[Key2])) AND ([j].[CompositeId3] = [e].[Key3]) - WHERE [e0].[Id] = [j].[LeafId]) -FROM [EntityRoots] AS [e0] -WHERE [e0].[Discriminator] = N'EntityLeaf'"); + INNER JOIN [EntityCompositeKeys] AS [e0] ON (([j].[CompositeId1] = [e0].[Key1]) AND ([j].[CompositeId2] = [e0].[Key2])) AND ([j].[CompositeId3] = [e0].[Key3]) + WHERE [e].[Id] = [j].[LeafId]) +FROM [EntityRoots] AS [e] +WHERE [e].[Discriminator] = N'EntityLeaf'"); } public override async Task Skip_navigation_select_subquery_max(bool async) @@ -211,11 +211,11 @@ public override async Task Skip_navigation_select_subquery_max(bool async) AssertSql( @"SELECT ( - SELECT MAX([e].[Id]) + SELECT MAX([e0].[Id]) FROM [JoinOneToTwo] AS [j] - INNER JOIN [EntityOnes] AS [e] ON [j].[OneId] = [e].[Id] - WHERE [e0].[Id] = [j].[TwoId]) -FROM [EntityTwos] AS [e0]"); + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e].[Id] = [j].[TwoId]) +FROM [EntityTwos] AS [e]"); } public override async Task Skip_navigation_select_subquery_min(bool async) @@ -224,11 +224,11 @@ public override async Task Skip_navigation_select_subquery_min(bool async) AssertSql( @"SELECT ( - SELECT MIN([e].[Id]) + SELECT MIN([e0].[Id]) FROM [JoinOneToThreePayloadFull] AS [j] - INNER JOIN [EntityOnes] AS [e] ON [j].[OneId] = [e].[Id] - WHERE [e0].[Id] = [j].[ThreeId]) -FROM [EntityThrees] AS [e0]"); + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e].[Id] = [j].[ThreeId]) +FROM [EntityThrees] AS [e]"); } public override async Task Skip_navigation_select_subquery_sum(bool async) @@ -237,11 +237,11 @@ public override async Task Skip_navigation_select_subquery_sum(bool async) AssertSql( @"SELECT ( - SELECT COALESCE(SUM([e0].[Id]), 0) - FROM [EntityOneEntityTwo] AS [e] - INNER JOIN [EntityOnes] AS [e0] ON [e].[EntityOneId] = [e0].[Id] - WHERE [e1].[Id] = [e].[EntityTwoId]) -FROM [EntityTwos] AS [e1]"); + SELECT COALESCE(SUM([e1].[Id]), 0) + FROM [EntityOneEntityTwo] AS [e0] + INNER JOIN [EntityOnes] AS [e1] ON [e0].[EntityOneId] = [e1].[Id] + WHERE [e].[Id] = [e0].[EntityTwoId]) +FROM [EntityTwos] AS [e]"); } public override async Task Skip_navigation_order_by_first_or_default(bool async) @@ -889,7 +889,7 @@ public override async Task Filter_include_on_skip_navigation_combined_with_filte @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId], [t3].[Id], [t3].[Name], [t3].[OneId], [t3].[ThreeId], [t3].[Id0], [t3].[CollectionInverseId], [t3].[Name0], [t3].[ReferenceInverseId], [t3].[OneId0], [t3].[TwoId], [t3].[Id1], [t3].[Discriminator], [t3].[Name1], [t3].[Number], [t3].[IsGreen], [t3].[EntityBranchId], [t3].[EntityOneId] FROM [EntityThrees] AS [e] LEFT JOIN ( - SELECT [e0].[Id], [e0].[Name], [j].[OneId], [j].[ThreeId], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t0].[OneId] AS [OneId0], [t0].[TwoId], [t2].[Id] AS [Id1], [t2].[Discriminator], [t2].[Name] AS [Name1], [t2].[Number], [t2].[IsGreen], [t2].[EntityBranchId], [t2].[EntityOneId] + SELECT [e0].[Id], [e0].[Name], [j].[OneId], [j].[ThreeId], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t0].[OneId] AS [OneId0], [t0].[TwoId], [t1].[Id] AS [Id1], [t1].[Discriminator], [t1].[Name] AS [Name1], [t1].[Number], [t1].[IsGreen], [t1].[EntityBranchId], [t1].[EntityOneId] FROM [JoinOneToThreePayloadFull] AS [j] INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] LEFT JOIN ( @@ -902,15 +902,15 @@ FROM [JoinOneToTwo] AS [j0] WHERE (1 < [t].[row]) AND ([t].[row] <= 3) ) AS [t0] ON [e0].[Id] = [t0].[OneId] LEFT JOIN ( - SELECT [t1].[Id], [t1].[Discriminator], [t1].[Name], [t1].[Number], [t1].[IsGreen], [j1].[EntityBranchId], [j1].[EntityOneId] + SELECT [t2].[Id], [t2].[Discriminator], [t2].[Name], [t2].[Number], [t2].[IsGreen], [j1].[EntityBranchId], [j1].[EntityOneId] FROM [JoinOneToBranch] AS [j1] INNER JOIN ( SELECT [e2].[Id], [e2].[Discriminator], [e2].[Name], [e2].[Number], [e2].[IsGreen] FROM [EntityRoots] AS [e2] WHERE [e2].[Discriminator] IN (N'EntityBranch', N'EntityLeaf') - ) AS [t1] ON [j1].[EntityBranchId] = [t1].[Id] - WHERE [t1].[Id] < 20 - ) AS [t2] ON [e0].[Id] = [t2].[EntityOneId] + ) AS [t2] ON [j1].[EntityBranchId] = [t2].[Id] + WHERE [t2].[Id] < 20 + ) AS [t1] ON [e0].[Id] = [t1].[EntityOneId] WHERE [e0].[Id] < 10 ) AS [t3] ON [e].[Id] = [t3].[ThreeId] ORDER BY [e].[Id], [t3].[OneId], [t3].[ThreeId], [t3].[Id], [t3].[OneId0], [t3].[Id0], [t3].[TwoId], [t3].[EntityBranchId], [t3].[EntityOneId], [t3].[Id1]"); @@ -1272,7 +1272,7 @@ INNER JOIN [EntityCompositeKeys] AS [e0] ON (([j].[CompositeId1] = [e0].[Key1]) ) AS [t] ON [e].[Id] = [t].[RootId] ORDER BY [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3]", // - @"SELECT [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3] + @"SELECT [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3] FROM [EntityRoots] AS [e] INNER JOIN ( SELECT [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3], [j].[RootId], [e0].[Key1], [e0].[Key2], [e0].[Key3] @@ -1280,15 +1280,15 @@ FROM [JoinCompositeKeyToRootShared] AS [j] INNER JOIN [EntityCompositeKeys] AS [e0] ON (([j].[CompositeId1] = [e0].[Key1]) AND ([j].[CompositeId2] = [e0].[Key2])) AND ([j].[CompositeId3] = [e0].[Key3]) ) AS [t] ON [e].[Id] = [t].[RootId] INNER JOIN ( - SELECT [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[CompositeId1], [j0].[CompositeId2], [j0].[CompositeId3], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[CompositeId1], [j0].[CompositeId2], [j0].[CompositeId3] ORDER BY [e1].[Id]) AS [row] FROM [JoinThreeToCompositeKeyFull] AS [j0] INNER JOIN [EntityThrees] AS [e1] ON [j0].[ThreeId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON (([t].[Key1] = [t1].[CompositeId1]) AND ([t].[Key2] = [t1].[CompositeId2])) AND ([t].[Key3] = [t1].[CompositeId3]) -ORDER BY [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id0]"); + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON (([t].[Key1] = [t0].[CompositeId1]) AND ([t].[Key2] = [t0].[CompositeId2])) AND ([t].[Key3] = [t0].[CompositeId3]) +ORDER BY [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0]"); } public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_split(bool async) @@ -1390,7 +1390,7 @@ WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id]", // - @"SELECT [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [e0].[Id] @@ -1399,15 +1399,15 @@ FROM [JoinOneToTwo] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] INNER JOIN ( - SELECT [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[TwoId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[TwoId] ORDER BY [e1].[Id]) AS [row] FROM [JoinTwoToThree] AS [j0] INNER JOIN [EntityThrees] AS [e1] ON [j0].[ThreeId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON [t].[Id] = [t1].[TwoId] -ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t1].[TwoId], [t1].[Id]"); + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON [t].[Id] = [t0].[TwoId] +ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t0].[TwoId], [t0].[Id]"); } public override async Task Filter_include_on_skip_navigation_combined_split(bool async) @@ -1462,7 +1462,7 @@ WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]", // - @"SELECT [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1471,17 +1471,17 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] INNER JOIN ( - SELECT [t0].[OneId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[OneId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[OneId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[OneId] ORDER BY [e1].[Id]) AS [row] FROM [JoinOneToTwo] AS [j0] INNER JOIN [EntityTwos] AS [e1] ON [j0].[TwoId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON [t].[Id] = [t1].[OneId] -ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t1].[OneId], [t1].[Id]", + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON [t].[Id] = [t0].[OneId] +ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t0].[OneId], [t0].[Id]", // - @"SELECT [t1].[Id], [t1].[Discriminator], [t1].[Name], [t1].[Number], [t1].[IsGreen], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + @"SELECT [t0].[Id], [t0].[Discriminator], [t0].[Name], [t0].[Number], [t0].[IsGreen], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1490,15 +1490,15 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] INNER JOIN ( - SELECT [j0].[EntityOneId], [t0].[Id], [t0].[Discriminator], [t0].[Name], [t0].[Number], [t0].[IsGreen] + SELECT [j0].[EntityOneId], [t1].[Id], [t1].[Discriminator], [t1].[Name], [t1].[Number], [t1].[IsGreen] FROM [JoinOneToBranch] AS [j0] INNER JOIN ( SELECT [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[IsGreen] FROM [EntityRoots] AS [e1] WHERE [e1].[Discriminator] IN (N'EntityBranch', N'EntityLeaf') - ) AS [t0] ON [j0].[EntityBranchId] = [t0].[Id] - WHERE [t0].[Id] < 20 -) AS [t1] ON [t].[Id] = [t1].[EntityOneId] + ) AS [t1] ON [j0].[EntityBranchId] = [t1].[Id] + WHERE [t1].[Id] < 20 +) AS [t0] ON [t].[Id] = [t0].[EntityOneId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyQuerySqlServerTest.cs index 6766a6cb4d2..d4de39138a0 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyQuerySqlServerTest.cs @@ -196,12 +196,12 @@ public override async Task Skip_navigation_select_subquery_average(bool async) AssertSql( @"SELECT ( - SELECT AVG(CAST([e].[Key1] AS float)) + SELECT AVG(CAST([e0].[Key1] AS float)) FROM [JoinCompositeKeyToLeaf] AS [j] - INNER JOIN [EntityCompositeKeys] AS [e] ON (([j].[CompositeId1] = [e].[Key1]) AND ([j].[CompositeId2] = [e].[Key2])) AND ([j].[CompositeId3] = [e].[Key3]) - WHERE [e0].[Id] = [j].[LeafId]) -FROM [EntityRoots] AS [e0] -WHERE [e0].[Discriminator] = N'EntityLeaf'"); + INNER JOIN [EntityCompositeKeys] AS [e0] ON (([j].[CompositeId1] = [e0].[Key1]) AND ([j].[CompositeId2] = [e0].[Key2])) AND ([j].[CompositeId3] = [e0].[Key3]) + WHERE [e].[Id] = [j].[LeafId]) +FROM [EntityRoots] AS [e] +WHERE [e].[Discriminator] = N'EntityLeaf'"); } public override async Task Skip_navigation_select_subquery_max(bool async) @@ -210,11 +210,11 @@ public override async Task Skip_navigation_select_subquery_max(bool async) AssertSql( @"SELECT ( - SELECT MAX([e].[Id]) + SELECT MAX([e0].[Id]) FROM [JoinOneToTwo] AS [j] - INNER JOIN [EntityOnes] AS [e] ON [j].[OneId] = [e].[Id] - WHERE [e0].[Id] = [j].[TwoId]) -FROM [EntityTwos] AS [e0]"); + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e].[Id] = [j].[TwoId]) +FROM [EntityTwos] AS [e]"); } public override async Task Skip_navigation_select_subquery_min(bool async) @@ -223,11 +223,11 @@ public override async Task Skip_navigation_select_subquery_min(bool async) AssertSql( @"SELECT ( - SELECT MIN([e].[Id]) + SELECT MIN([e0].[Id]) FROM [JoinOneToThreePayloadFull] AS [j] - INNER JOIN [EntityOnes] AS [e] ON [j].[OneId] = [e].[Id] - WHERE [e0].[Id] = [j].[ThreeId]) -FROM [EntityThrees] AS [e0]"); + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e].[Id] = [j].[ThreeId]) +FROM [EntityThrees] AS [e]"); } public override async Task Skip_navigation_select_subquery_sum(bool async) @@ -236,11 +236,11 @@ public override async Task Skip_navigation_select_subquery_sum(bool async) AssertSql( @"SELECT ( - SELECT COALESCE(SUM([e0].[Id]), 0) - FROM [EntityOneEntityTwo] AS [e] - INNER JOIN [EntityOnes] AS [e0] ON [e].[EntityOneId] = [e0].[Id] - WHERE [e1].[Id] = [e].[EntityTwoId]) -FROM [EntityTwos] AS [e1]"); + SELECT COALESCE(SUM([e1].[Id]), 0) + FROM [EntityOneEntityTwo] AS [e0] + INNER JOIN [EntityOnes] AS [e1] ON [e0].[EntityOneId] = [e1].[Id] + WHERE [e].[Id] = [e0].[EntityTwoId]) +FROM [EntityTwos] AS [e]"); } public override async Task Skip_navigation_order_by_first_or_default(bool async) @@ -888,7 +888,7 @@ public override async Task Filter_include_on_skip_navigation_combined_with_filte @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId], [t3].[OneId], [t3].[ThreeId], [t3].[Payload], [t3].[Id], [t3].[Name], [t3].[OneId0], [t3].[TwoId], [t3].[Id0], [t3].[CollectionInverseId], [t3].[Name0], [t3].[ReferenceInverseId], [t3].[EntityBranchId], [t3].[EntityOneId], [t3].[Id1], [t3].[Discriminator], [t3].[Name1], [t3].[Number], [t3].[IsGreen] FROM [EntityThrees] AS [e] LEFT JOIN ( - SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name], [t0].[OneId] AS [OneId0], [t0].[TwoId], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t2].[EntityBranchId], [t2].[EntityOneId], [t2].[Id] AS [Id1], [t2].[Discriminator], [t2].[Name] AS [Name1], [t2].[Number], [t2].[IsGreen] + SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name], [t0].[OneId] AS [OneId0], [t0].[TwoId], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t1].[EntityBranchId], [t1].[EntityOneId], [t1].[Id] AS [Id1], [t1].[Discriminator], [t1].[Name] AS [Name1], [t1].[Number], [t1].[IsGreen] FROM [JoinOneToThreePayloadFull] AS [j] INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] LEFT JOIN ( @@ -901,15 +901,15 @@ FROM [JoinOneToTwo] AS [j0] WHERE (1 < [t].[row]) AND ([t].[row] <= 3) ) AS [t0] ON [e0].[Id] = [t0].[OneId] LEFT JOIN ( - SELECT [j1].[EntityBranchId], [j1].[EntityOneId], [t1].[Id], [t1].[Discriminator], [t1].[Name], [t1].[Number], [t1].[IsGreen] + SELECT [j1].[EntityBranchId], [j1].[EntityOneId], [t2].[Id], [t2].[Discriminator], [t2].[Name], [t2].[Number], [t2].[IsGreen] FROM [JoinOneToBranch] AS [j1] INNER JOIN ( SELECT [e2].[Id], [e2].[Discriminator], [e2].[Name], [e2].[Number], [e2].[IsGreen] FROM [EntityRoots] AS [e2] WHERE [e2].[Discriminator] IN (N'EntityBranch', N'EntityLeaf') - ) AS [t1] ON [j1].[EntityBranchId] = [t1].[Id] - WHERE [t1].[Id] < 20 - ) AS [t2] ON [e0].[Id] = [t2].[EntityOneId] + ) AS [t2] ON [j1].[EntityBranchId] = [t2].[Id] + WHERE [t2].[Id] < 20 + ) AS [t1] ON [e0].[Id] = [t1].[EntityOneId] WHERE [e0].[Id] < 10 ) AS [t3] ON [e].[Id] = [t3].[ThreeId] ORDER BY [e].[Id], [t3].[OneId], [t3].[ThreeId], [t3].[Id], [t3].[OneId0], [t3].[Id0], [t3].[TwoId], [t3].[EntityBranchId], [t3].[EntityOneId], [t3].[Id1]"); @@ -1271,7 +1271,7 @@ INNER JOIN [EntityCompositeKeys] AS [e0] ON (([j].[CompositeId1] = [e0].[Key1]) ) AS [t] ON [e].[Id] = [t].[RootId] ORDER BY [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3]", // - @"SELECT [t1].[Id], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[ThreeId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3] + @"SELECT [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3] FROM [EntityRoots] AS [e] INNER JOIN ( SELECT [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3], [j].[RootId], [e0].[Key1], [e0].[Key2], [e0].[Key3] @@ -1279,15 +1279,15 @@ FROM [JoinCompositeKeyToRootShared] AS [j] INNER JOIN [EntityCompositeKeys] AS [e0] ON (([j].[CompositeId1] = [e0].[Key1]) AND ([j].[CompositeId2] = [e0].[Key2])) AND ([j].[CompositeId3] = [e0].[Key3]) ) AS [t] ON [e].[Id] = [t].[RootId] INNER JOIN ( - SELECT [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[Id], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[ThreeId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[Id], [j0].[CompositeId1], [j0].[CompositeId2], [j0].[CompositeId3], [j0].[ThreeId], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[CompositeId1], [j0].[CompositeId2], [j0].[CompositeId3] ORDER BY [e1].[Id]) AS [row] FROM [JoinThreeToCompositeKeyFull] AS [j0] INNER JOIN [EntityThrees] AS [e1] ON [j0].[ThreeId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON (([t].[Key1] = [t1].[CompositeId1]) AND ([t].[Key2] = [t1].[CompositeId2])) AND ([t].[Key3] = [t1].[CompositeId3]) -ORDER BY [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id0]"); + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON (([t].[Key1] = [t0].[CompositeId1]) AND ([t].[Key2] = [t0].[CompositeId2])) AND ([t].[Key3] = [t0].[CompositeId3]) +ORDER BY [e].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0]"); } public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_split(bool async) @@ -1389,7 +1389,7 @@ WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id]", // - @"SELECT [t1].[ThreeId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] + @"SELECT [t0].[ThreeId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [e0].[Id] @@ -1398,15 +1398,15 @@ FROM [JoinOneToTwo] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] INNER JOIN ( - SELECT [t0].[ThreeId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[ThreeId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[ThreeId], [j0].[TwoId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[TwoId] ORDER BY [e1].[Id]) AS [row] FROM [JoinTwoToThree] AS [j0] INNER JOIN [EntityThrees] AS [e1] ON [j0].[ThreeId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON [t].[Id] = [t1].[TwoId] -ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t1].[TwoId], [t1].[Id]"); + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON [t].[Id] = [t0].[TwoId] +ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t0].[TwoId], [t0].[Id]"); } public override async Task Filter_include_on_skip_navigation_combined_split(bool async) @@ -1461,7 +1461,7 @@ WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]", // - @"SELECT [t1].[OneId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + @"SELECT [t0].[OneId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1470,17 +1470,17 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] INNER JOIN ( - SELECT [t0].[OneId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[OneId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[OneId], [j0].[TwoId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[OneId] ORDER BY [e1].[Id]) AS [row] FROM [JoinOneToTwo] AS [j0] INNER JOIN [EntityTwos] AS [e1] ON [j0].[TwoId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON [t].[Id] = [t1].[OneId] -ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t1].[OneId], [t1].[Id]", + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON [t].[Id] = [t0].[OneId] +ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t0].[OneId], [t0].[Id]", // - @"SELECT [t1].[EntityBranchId], [t1].[EntityOneId], [t1].[Id], [t1].[Discriminator], [t1].[Name], [t1].[Number], [t1].[IsGreen], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + @"SELECT [t0].[EntityBranchId], [t0].[EntityOneId], [t0].[Id], [t0].[Discriminator], [t0].[Name], [t0].[Number], [t0].[IsGreen], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1489,15 +1489,15 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] INNER JOIN ( - SELECT [j0].[EntityBranchId], [j0].[EntityOneId], [t0].[Id], [t0].[Discriminator], [t0].[Name], [t0].[Number], [t0].[IsGreen] + SELECT [j0].[EntityBranchId], [j0].[EntityOneId], [t1].[Id], [t1].[Discriminator], [t1].[Name], [t1].[Number], [t1].[IsGreen] FROM [JoinOneToBranch] AS [j0] INNER JOIN ( SELECT [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[IsGreen] FROM [EntityRoots] AS [e1] WHERE [e1].[Discriminator] IN (N'EntityBranch', N'EntityLeaf') - ) AS [t0] ON [j0].[EntityBranchId] = [t0].[Id] - WHERE [t0].[Id] < 20 -) AS [t1] ON [t].[Id] = [t1].[EntityOneId] + ) AS [t1] ON [j0].[EntityBranchId] = [t1].[Id] + WHERE [t1].[Id] < 20 +) AS [t0] ON [t].[Id] = [t0].[EntityOneId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs index 7036dbc1491..1332a7153d9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindAggregateOperatorsQuerySqlServerTest.cs @@ -144,12 +144,12 @@ public override async Task Sum_on_float_column_in_subquery(bool async) await base.Sum_on_float_column_in_subquery(async); AssertSql( - @"SELECT [o0].[OrderID], ( - SELECT CAST(COALESCE(SUM([o].[Discount]), 0.0E0) AS real) - FROM [Order Details] AS [o] - WHERE [o0].[OrderID] = [o].[OrderID]) AS [Sum] -FROM [Orders] AS [o0] -WHERE [o0].[OrderID] < 10300"); + @"SELECT [o].[OrderID], ( + SELECT CAST(COALESCE(SUM([o0].[Discount]), 0.0E0) AS real) + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) AS [Sum] +FROM [Orders] AS [o] +WHERE [o].[OrderID] < 10300"); } public override async Task Average_with_no_arg(bool async) @@ -266,12 +266,12 @@ public override async Task Average_on_float_column_in_subquery(bool async) await base.Average_on_float_column_in_subquery(async); AssertSql( - @"SELECT [o0].[OrderID], ( - SELECT CAST(AVG([o].[Discount]) AS real) - FROM [Order Details] AS [o] - WHERE [o0].[OrderID] = [o].[OrderID]) AS [Sum] -FROM [Orders] AS [o0] -WHERE [o0].[OrderID] < 10300"); + @"SELECT [o].[OrderID], ( + SELECT CAST(AVG([o0].[Discount]) AS real) + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) AS [Sum] +FROM [Orders] AS [o] +WHERE [o].[OrderID] < 10300"); } public override async Task Average_on_float_column_in_subquery_with_cast(bool async) @@ -279,12 +279,12 @@ public override async Task Average_on_float_column_in_subquery_with_cast(bool as await base.Average_on_float_column_in_subquery_with_cast(async); AssertSql( - @"SELECT [o0].[OrderID], ( - SELECT CAST(AVG([o].[Discount]) AS real) - FROM [Order Details] AS [o] - WHERE [o0].[OrderID] = [o].[OrderID]) AS [Sum] -FROM [Orders] AS [o0] -WHERE [o0].[OrderID] < 10300"); + @"SELECT [o].[OrderID], ( + SELECT CAST(AVG([o0].[Discount]) AS real) + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) AS [Sum] +FROM [Orders] AS [o] +WHERE [o].[OrderID] < 10300"); } public override async Task Min_with_no_arg(bool async) @@ -1233,11 +1233,11 @@ public override async Task Contains_over_nullable_scalar_with_null_in_subquery_t @"SELECT CASE WHEN EXISTS ( SELECT 1 - FROM [Orders] AS [o] - WHERE ([o].[CustomerID] = N'VINET') AND [o].[CustomerID] IS NULL) THEN CAST(1 AS bit) + FROM [Orders] AS [o0] + WHERE ([o0].[CustomerID] = N'VINET') AND [o0].[CustomerID] IS NULL) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END -FROM [Orders] AS [o0]"); +FROM [Orders] AS [o]"); } public override async Task Contains_over_non_nullable_scalar_with_null_in_subquery_simplifies_to_false(bool async) @@ -1410,7 +1410,7 @@ public override async Task DefaultIfEmpty_selects_only_required_columns(bool asy @"SELECT [p].[ProductName] FROM ( SELECT NULL AS [empty] -) AS [empty] +) AS [e] LEFT JOIN [Products] AS [p] ON 1 = 1"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeQuerySqlServerTest.cs index adf71aaf973..20c0302fafc 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindIncludeQuerySqlServerTest.cs @@ -925,13 +925,13 @@ public override async Task Include_with_complex_projection_does_not_change_order AssertSql( @"SELECT [c].[CustomerID] AS [Id], ( SELECT COUNT(*) - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID]) AS [TotalOrders] + FROM [Orders] AS [o0] + WHERE [c].[CustomerID] = [o0].[CustomerID]) AS [TotalOrders] FROM [Customers] AS [c] WHERE ([c].[ContactTitle] = N'Owner') AND (( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID]) > 2) + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID]) > 2) ORDER BY [c].[CustomerID]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs index b43bcb001e6..d895f69d5bd 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindJoinQuerySqlServerTest.cs @@ -549,7 +549,7 @@ public override async Task SelectMany_with_client_eval_with_collection_shaper(bo await base.SelectMany_with_client_eval_with_collection_shaper(async); AssertSql( - @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t].[ContactName], [c].[CustomerID], [t].[OrderID], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t].[ContactName], [c].[CustomerID], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] FROM [Customers] AS [c] CROSS APPLY ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[ContactName] @@ -581,10 +581,10 @@ public override async Task SelectMany_with_client_eval_with_constructor(bool asy await base.SelectMany_with_client_eval_with_constructor(async); AssertSql( - @"SELECT [c].[CustomerID], [c].[City], [t0].[OrderID], [t0].[ProductID], [t0].[OrderID0], [t0].[OrderID1], [t0].[ProductID0] + @"SELECT [c].[CustomerID], [c].[City], [t0].[OrderID], [t0].[ProductID], [t0].[OrderID0] FROM [Customers] AS [c] LEFT JOIN ( - SELECT [t].[OrderID], [t].[ProductID], [o].[OrderID] AS [OrderID0], [t].[OrderID] AS [OrderID1], [t].[ProductID] AS [ProductID0], [o].[CustomerID] + SELECT [t].[OrderID], [t].[ProductID], [o].[OrderID] AS [OrderID0], [o].[CustomerID] FROM [Orders] AS [o] INNER JOIN ( SELECT [o0].[OrderID], [o0].[ProductID] @@ -593,7 +593,7 @@ WHERE [o0].[OrderID] < 11000 ) AS [t] ON [o].[OrderID] = [t].[OrderID] ) AS [t0] ON [c].[CustomerID] = [t0].[CustomerID] WHERE [c].[CustomerID] LIKE N'A%' -ORDER BY [c].[CustomerID], [t0].[OrderID0], [t0].[OrderID1], [t0].[ProductID0]"); +ORDER BY [c].[CustomerID], [t0].[OrderID0], [t0].[OrderID], [t0].[ProductID]"); } public override async Task SelectMany_with_selecting_outer_entity(bool async) @@ -663,19 +663,19 @@ public override async Task Distinct_SelectMany_correlated_subquery_take(bool asy await base.Distinct_SelectMany_correlated_subquery_take(async); AssertSql( - @"SELECT [t1].[CustomerID], [t1].[Address], [t1].[City], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Country], [t1].[Fax], [t1].[Phone], [t1].[PostalCode], [t1].[Region] + @"SELECT [t0].[CustomerID], [t0].[Address], [t0].[City], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Country], [t0].[Fax], [t0].[Phone], [t0].[PostalCode], [t0].[Region] FROM ( SELECT DISTINCT [c].[CustomerID] FROM [Customers] AS [c] ) AS [t] INNER JOIN ( - SELECT [t0].[CustomerID], [t0].[Address], [t0].[City], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Country], [t0].[Fax], [t0].[Phone], [t0].[PostalCode], [t0].[Region] + SELECT [t1].[CustomerID], [t1].[Address], [t1].[City], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Country], [t1].[Fax], [t1].[Phone], [t1].[PostalCode], [t1].[Region] FROM ( SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], ROW_NUMBER() OVER(PARTITION BY [c0].[CustomerID] ORDER BY [c0].[CustomerID] + COALESCE([c0].[City], N'')) AS [row] FROM [Customers] AS [c0] - ) AS [t0] - WHERE [t0].[row] <= 2 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID]"); + ) AS [t1] + WHERE [t1].[row] <= 2 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID]"); } public override async Task Distinct_SelectMany_correlated_subquery_take_2(bool async) @@ -683,19 +683,19 @@ public override async Task Distinct_SelectMany_correlated_subquery_take_2(bool a await base.Distinct_SelectMany_correlated_subquery_take_2(async); AssertSql( - @"SELECT [t1].[CustomerID], [t1].[Address], [t1].[City], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Country], [t1].[Fax], [t1].[Phone], [t1].[PostalCode], [t1].[Region] + @"SELECT [t0].[CustomerID], [t0].[Address], [t0].[City], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Country], [t0].[Fax], [t0].[Phone], [t0].[PostalCode], [t0].[Region] FROM ( SELECT DISTINCT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] ) AS [t] INNER JOIN ( - SELECT [t0].[CustomerID], [t0].[Address], [t0].[City], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Country], [t0].[Fax], [t0].[Phone], [t0].[PostalCode], [t0].[Region] + SELECT [t1].[CustomerID], [t1].[Address], [t1].[City], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Country], [t1].[Fax], [t1].[Phone], [t1].[PostalCode], [t1].[Region] FROM ( SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], ROW_NUMBER() OVER(PARTITION BY [c0].[CustomerID] ORDER BY [c0].[CustomerID] + COALESCE([c0].[City], N'')) AS [row] FROM [Customers] AS [c0] - ) AS [t0] - WHERE [t0].[row] <= 2 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID]"); + ) AS [t1] + WHERE [t1].[row] <= 2 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID]"); } public override async Task Take_SelectMany_correlated_subquery_take(bool async) @@ -705,20 +705,20 @@ public override async Task Take_SelectMany_correlated_subquery_take(bool async) AssertSql( @"@__p_0='2' -SELECT [t1].[CustomerID], [t1].[Address], [t1].[City], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Country], [t1].[Fax], [t1].[Phone], [t1].[PostalCode], [t1].[Region] +SELECT [t0].[CustomerID], [t0].[Address], [t0].[City], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Country], [t0].[Fax], [t0].[Phone], [t0].[PostalCode], [t0].[Region] FROM ( SELECT TOP(@__p_0) [c].[CustomerID] FROM [Customers] AS [c] ORDER BY [c].[CustomerID] ) AS [t] INNER JOIN ( - SELECT [t0].[CustomerID], [t0].[Address], [t0].[City], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Country], [t0].[Fax], [t0].[Phone], [t0].[PostalCode], [t0].[Region] + SELECT [t1].[CustomerID], [t1].[Address], [t1].[City], [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t1].[Country], [t1].[Fax], [t1].[Phone], [t1].[PostalCode], [t1].[Region] FROM ( SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], ROW_NUMBER() OVER(PARTITION BY [c0].[CustomerID] ORDER BY [c0].[CustomerID] + COALESCE([c0].[City], N'')) AS [row] FROM [Customers] AS [c0] - ) AS [t0] - WHERE [t0].[row] <= 2 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID] + ) AS [t1] + WHERE [t1].[row] <= 2 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID] ORDER BY [t].[CustomerID]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs index 7a8bb4bec61..e1ac00e7f48 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs @@ -338,7 +338,7 @@ public override async Task Default_if_empty_top_level(bool async) @"SELECT [t].[EmployeeID], [t].[City], [t].[Country], [t].[FirstName], [t].[ReportsTo], [t].[Title] FROM ( SELECT NULL AS [empty] -) AS [empty] +) AS [e0] LEFT JOIN ( SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] @@ -354,23 +354,23 @@ public override async Task Join_with_default_if_empty_on_both_sources(bool async @"SELECT [t].[EmployeeID], [t].[City], [t].[Country], [t].[FirstName], [t].[ReportsTo], [t].[Title] FROM ( SELECT NULL AS [empty] -) AS [empty] +) AS [e0] LEFT JOIN ( SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] WHERE [e].[EmployeeID] = -1 ) AS [t] ON 1 = 1 INNER JOIN ( - SELECT [t0].[EmployeeID] + SELECT [t1].[EmployeeID] FROM ( SELECT NULL AS [empty] - ) AS [empty0] + ) AS [e1] LEFT JOIN ( - SELECT [e0].[EmployeeID] - FROM [Employees] AS [e0] - WHERE [e0].[EmployeeID] = -1 - ) AS [t0] ON 1 = 1 -) AS [t1] ON [t].[EmployeeID] = [t1].[EmployeeID]"); + SELECT [e2].[EmployeeID] + FROM [Employees] AS [e2] + WHERE [e2].[EmployeeID] = -1 + ) AS [t1] ON 1 = 1 +) AS [t0] ON [t].[EmployeeID] = [t0].[EmployeeID]"); } public override async Task Default_if_empty_top_level_followed_by_projecting_constant(bool async) @@ -381,7 +381,7 @@ public override async Task Default_if_empty_top_level_followed_by_projecting_con @"SELECT N'Foo' FROM ( SELECT NULL AS [empty] -) AS [empty] +) AS [e0] LEFT JOIN ( SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] @@ -397,7 +397,7 @@ public override async Task Default_if_empty_top_level_positive(bool async) @"SELECT [t].[EmployeeID], [t].[City], [t].[Country], [t].[FirstName], [t].[ReportsTo], [t].[Title] FROM ( SELECT NULL AS [empty] -) AS [empty] +) AS [e0] LEFT JOIN ( SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] @@ -413,7 +413,7 @@ public override async Task Default_if_empty_top_level_projection(bool async) @"SELECT COALESCE([t].[EmployeeID], 0) FROM ( SELECT NULL AS [empty] -) AS [empty] +) AS [e0] LEFT JOIN ( SELECT [e].[EmployeeID] FROM [Employees] AS [e] @@ -705,20 +705,20 @@ public override void Select_Subquery_Single() AssertSql( @"@__p_0='2' -SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] +SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[ProductID] FROM [Order Details] AS [o] ORDER BY [o].[ProductID], [o].[OrderID] ) AS [t] LEFT JOIN ( - SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] + SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] FROM ( SELECT [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], ROW_NUMBER() OVER(PARTITION BY [o0].[OrderID] ORDER BY [o0].[OrderID]) AS [row] FROM [Orders] AS [o0] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[OrderID] = [t1].[OrderID] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[OrderID] = [t0].[OrderID] ORDER BY [t].[ProductID], [t].[OrderID]"); } @@ -3022,18 +3022,18 @@ public override async Task Subquery_member_pushdown_does_not_change_original_sub @"@__p_0='3' SELECT [t].[OrderID] AS [OrderId], ( - SELECT TOP(1) [c].[City] - FROM [Customers] AS [c] - WHERE [c].[CustomerID] = [t].[CustomerID]) AS [City] + SELECT TOP(1) [c0].[City] + FROM [Customers] AS [c0] + WHERE [c0].[CustomerID] = [t].[CustomerID]) AS [City] FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID] FROM [Orders] AS [o] ORDER BY [o].[OrderID] ) AS [t] ORDER BY ( - SELECT TOP(1) [c0].[City] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = [t].[CustomerID])"); + SELECT TOP(1) [c].[City] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] = [t].[CustomerID])"); } public override async Task Subquery_member_pushdown_does_not_change_original_subquery_model2(bool async) @@ -3044,18 +3044,18 @@ public override async Task Subquery_member_pushdown_does_not_change_original_sub @"@__p_0='3' SELECT [t].[OrderID] AS [OrderId], ( - SELECT TOP(1) [c].[City] - FROM [Customers] AS [c] - WHERE [c].[CustomerID] = [t].[CustomerID]) AS [City] + SELECT TOP(1) [c0].[City] + FROM [Customers] AS [c0] + WHERE [c0].[CustomerID] = [t].[CustomerID]) AS [City] FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID] FROM [Orders] AS [o] ORDER BY [o].[OrderID] ) AS [t] ORDER BY ( - SELECT TOP(1) [c0].[City] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = [t].[CustomerID])"); + SELECT TOP(1) [c].[City] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] = [t].[CustomerID])"); } public override async Task Query_expression_with_to_string_and_contains(bool async) @@ -3225,7 +3225,7 @@ public override async Task DefaultIfEmpty_without_group_join(bool async) @"SELECT [t].[CustomerID] FROM ( SELECT NULL AS [empty] -) AS [empty] +) AS [e] LEFT JOIN ( SELECT [c].[CustomerID] FROM [Customers] AS [c] @@ -3256,7 +3256,7 @@ CROSS JOIN ( SELECT [t].[OrderID] FROM ( SELECT NULL AS [empty] - ) AS [empty] + ) AS [e] LEFT JOIN ( SELECT [o].[OrderID] FROM [Orders] AS [o] @@ -3276,7 +3276,7 @@ CROSS JOIN ( SELECT [t].[OrderID] FROM ( SELECT NULL AS [empty] - ) AS [empty] + ) AS [e] LEFT JOIN ( SELECT [o].[OrderID] FROM [Orders] AS [o] @@ -3299,7 +3299,7 @@ CROSS JOIN ( SELECT [t].[OrderID] FROM ( SELECT NULL AS [empty] - ) AS [empty] + ) AS [e] LEFT JOIN ( SELECT [o].[OrderID] FROM [Orders] AS [o] @@ -3716,20 +3716,20 @@ public override async Task Anonymous_subquery_orderby(bool async) AssertSql( @"SELECT ( - SELECT TOP(1) [o].[OrderDate] - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID] - ORDER BY [o].[OrderID] DESC) AS [A] + SELECT TOP(1) [o1].[OrderDate] + FROM [Orders] AS [o1] + WHERE [c].[CustomerID] = [o1].[CustomerID] + ORDER BY [o1].[OrderID] DESC) AS [A] FROM [Customers] AS [c] WHERE ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID]) > 1 + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID]) > 1 ORDER BY ( - SELECT TOP(1) [o1].[OrderDate] - FROM [Orders] AS [o1] - WHERE [c].[CustomerID] = [o1].[CustomerID] - ORDER BY [o1].[OrderID] DESC)"); + SELECT TOP(1) [o0].[OrderDate] + FROM [Orders] AS [o0] + WHERE [c].[CustomerID] = [o0].[CustomerID] + ORDER BY [o0].[OrderID] DESC)"); } public override async Task DTO_member_distinct_where(bool async) @@ -3821,20 +3821,20 @@ public override async Task DTO_subquery_orderby(bool async) AssertSql( @"SELECT ( - SELECT TOP(1) [o].[OrderDate] - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID] - ORDER BY [o].[OrderID] DESC) AS [Property] + SELECT TOP(1) [o1].[OrderDate] + FROM [Orders] AS [o1] + WHERE [c].[CustomerID] = [o1].[CustomerID] + ORDER BY [o1].[OrderID] DESC) AS [Property] FROM [Customers] AS [c] WHERE ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID]) > 1 + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID]) > 1 ORDER BY ( - SELECT TOP(1) [o1].[OrderDate] - FROM [Orders] AS [o1] - WHERE [c].[CustomerID] = [o1].[CustomerID] - ORDER BY [o1].[OrderID] DESC)"); + SELECT TOP(1) [o0].[OrderDate] + FROM [Orders] AS [o0] + WHERE [c].[CustomerID] = [o0].[CustomerID] + ORDER BY [o0].[OrderID] DESC)"); } public override async Task Include_with_orderby_skip_preserves_ordering(bool async) @@ -4409,10 +4409,10 @@ FROM [Customers] AS [c] OUTER APPLY ( SELECT ( SELECT COUNT(*) - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID]) AS [InnerOrder], [c].[CustomerID] AS [Id], [o0].[OrderID] - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID] + FROM [Orders] AS [o0] + WHERE [c].[CustomerID] = [o0].[CustomerID]) AS [InnerOrder], [c].[CustomerID] AS [Id], [o].[OrderID] + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID] ) AS [t] WHERE [c].[CustomerID] = N'ALFKI' ORDER BY [c].[CustomerID], [t].[OrderID]"); @@ -4519,13 +4519,13 @@ public override async Task Let_subquery_with_multiple_occurrences(bool async) AssertSql( @"SELECT ( SELECT COUNT(*) - FROM [Order Details] AS [o] - WHERE ([o0].[OrderID] = [o].[OrderID]) AND ([o].[Quantity] < CAST(10 AS smallint))) AS [Count] -FROM [Orders] AS [o0] + FROM [Order Details] AS [o1] + WHERE ([o].[OrderID] = [o1].[OrderID]) AND ([o1].[Quantity] < CAST(10 AS smallint))) AS [Count] +FROM [Orders] AS [o] WHERE EXISTS ( SELECT 1 - FROM [Order Details] AS [o1] - WHERE ([o0].[OrderID] = [o1].[OrderID]) AND ([o1].[Quantity] < CAST(10 AS smallint)))"); + FROM [Order Details] AS [o0] + WHERE ([o].[OrderID] = [o0].[OrderID]) AND ([o0].[Quantity] < CAST(10 AS smallint)))"); } public override async Task Let_entity_equality_to_null(bool async) @@ -4534,16 +4534,16 @@ public override async Task Let_entity_equality_to_null(bool async) AssertSql( @"SELECT [c].[CustomerID], ( - SELECT TOP(1) [o].[OrderDate] - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID] - ORDER BY [o].[OrderDate]) AS [OrderDate] -FROM [Customers] AS [c] -WHERE ([c].[CustomerID] LIKE N'A%') AND ( - SELECT TOP(1) [o0].[OrderID] + SELECT TOP(1) [o0].[OrderDate] FROM [Orders] AS [o0] WHERE [c].[CustomerID] = [o0].[CustomerID] - ORDER BY [o0].[OrderDate]) IS NOT NULL"); + ORDER BY [o0].[OrderDate]) AS [OrderDate] +FROM [Customers] AS [c] +WHERE ([c].[CustomerID] LIKE N'A%') AND ( + SELECT TOP(1) [o].[OrderID] + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID] + ORDER BY [o].[OrderDate]) IS NOT NULL"); } public override async Task Let_entity_equality_to_other_entity(bool async) @@ -4552,20 +4552,20 @@ public override async Task Let_entity_equality_to_other_entity(bool async) AssertSql( @"SELECT [c].[CustomerID], ( - SELECT TOP(1) [o].[OrderDate] - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID] - ORDER BY [o].[OrderDate]) AS [A] -FROM [Customers] AS [c] -WHERE ([c].[CustomerID] LIKE N'A%') AND ((( - SELECT TOP(1) [o0].[OrderID] - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID] - ORDER BY [o0].[OrderDate]) <> 0) OR ( - SELECT TOP(1) [o0].[OrderID] + SELECT TOP(1) [o0].[OrderDate] FROM [Orders] AS [o0] WHERE [c].[CustomerID] = [o0].[CustomerID] - ORDER BY [o0].[OrderDate]) IS NULL)"); + ORDER BY [o0].[OrderDate]) AS [A] +FROM [Customers] AS [c] +WHERE ([c].[CustomerID] LIKE N'A%') AND ((( + SELECT TOP(1) [o].[OrderID] + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID] + ORDER BY [o].[OrderDate]) <> 0) OR ( + SELECT TOP(1) [o].[OrderID] + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID] + ORDER BY [o].[OrderDate]) IS NULL)"); } public override async Task Collection_navigation_equal_to_null_for_subquery(bool async) @@ -4699,7 +4699,7 @@ WHEN EXISTS ( SELECT 1 FROM ( SELECT NULL AS [empty] - ) AS [empty] + ) AS [e0] LEFT JOIN ( SELECT [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] @@ -4887,7 +4887,7 @@ public override async Task Anonymous_projection_skip_empty_collection_FirstOrDef AssertSql( @"@__p_0='0' -SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] +SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] FROM ( SELECT [c].[CustomerID] FROM [Customers] AS [c] @@ -4896,13 +4896,13 @@ ORDER BY (SELECT 1) OFFSET @__p_0 ROWS ) AS [t] LEFT JOIN ( - SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] + SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] FROM ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID]"); + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID]"); } public override async Task Anonymous_projection_take_empty_collection_FirstOrDefault(bool async) @@ -4912,20 +4912,20 @@ public override async Task Anonymous_projection_take_empty_collection_FirstOrDef AssertSql( @"@__p_0='1' -SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] +SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] FROM ( SELECT TOP(@__p_0) [c].[CustomerID] FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'FISSA' ) AS [t] LEFT JOIN ( - SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] + SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] FROM ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID]"); + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID]"); } public override async Task Anonymous_projection_skip_take_empty_collection_FirstOrDefault(bool async) @@ -4936,7 +4936,7 @@ public override async Task Anonymous_projection_skip_take_empty_collection_First @"@__p_0='0' @__p_1='1' -SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] +SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] FROM ( SELECT [c].[CustomerID] FROM [Customers] AS [c] @@ -4945,13 +4945,13 @@ ORDER BY (SELECT 1) OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY ) AS [t] LEFT JOIN ( - SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] + SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] FROM ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID]"); + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID]"); } public override async Task Checked_context_with_arithmetic_does_not_fail(bool isAsync) @@ -5118,26 +5118,26 @@ WHEN EXISTS ( SELECT 1 FROM [Orders] AS [o] WHERE (( - SELECT TOP(1) [c].[CustomerID] + SELECT TOP(1) [c0].[CustomerID] FROM [Orders] AS [o0] - LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID] - WHERE [c1].[CustomerID] = [o0].[CustomerID] + LEFT JOIN [Customers] AS [c0] ON [o0].[CustomerID] = [c0].[CustomerID] + WHERE [c].[CustomerID] = [o0].[CustomerID] ORDER BY [o0].[OrderDate]) IS NOT NULL AND ((( - SELECT TOP(1) [c0].[CustomerID] + SELECT TOP(1) [c1].[CustomerID] FROM [Orders] AS [o1] - LEFT JOIN [Customers] AS [c0] ON [o1].[CustomerID] = [c0].[CustomerID] - WHERE [c1].[CustomerID] = [o1].[CustomerID] + LEFT JOIN [Customers] AS [c1] ON [o1].[CustomerID] = [c1].[CustomerID] + WHERE [c].[CustomerID] = [o1].[CustomerID] ORDER BY [o1].[OrderDate]) = [o].[CustomerID]) OR (( - SELECT TOP(1) [c0].[CustomerID] + SELECT TOP(1) [c1].[CustomerID] FROM [Orders] AS [o1] - LEFT JOIN [Customers] AS [c0] ON [o1].[CustomerID] = [c0].[CustomerID] - WHERE [c1].[CustomerID] = [o1].[CustomerID] + LEFT JOIN [Customers] AS [c1] ON [o1].[CustomerID] = [c1].[CustomerID] + WHERE [c].[CustomerID] = [o1].[CustomerID] ORDER BY [o1].[OrderDate]) IS NULL AND [o].[CustomerID] IS NULL))) AND ([o].[OrderID] < 11000)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [Complex] -FROM [Customers] AS [c1] -WHERE [c1].[CustomerID] LIKE N'F%' -ORDER BY [c1].[CustomerID]"); +FROM [Customers] AS [c] +WHERE [c].[CustomerID] LIKE N'F%' +ORDER BY [c].[CustomerID]"); } public override async Task Distinct_followed_by_ordering_on_condition(bool async) @@ -5169,7 +5169,7 @@ public override async Task DefaultIfEmpty_Sum_over_collection_navigation(bool as SELECT COALESCE(SUM(COALESCE([t].[OrderID], 0)), 0) FROM ( SELECT NULL AS [empty] - ) AS [empty] + ) AS [e] LEFT JOIN ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] @@ -5207,7 +5207,7 @@ public override async Task DefaultIfEmpty_over_empty_collection_followed_by_proj @"SELECT TOP(1) N'520' FROM ( SELECT NULL AS [empty] -) AS [empty] +) AS [e] LEFT JOIN ( SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Customers] AS [c] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs index 75709193b6b..17fbd0ef8f0 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindNavigationsQuerySqlServerTest.cs @@ -65,20 +65,20 @@ public override async Task Take_Select_Navigation(bool async) AssertSql( @"@__p_0='2' -SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] +SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] FROM ( SELECT TOP(@__p_0) [c].[CustomerID] FROM [Customers] AS [c] ORDER BY [c].[CustomerID] ) AS [t] LEFT JOIN ( - SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] + SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] FROM ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -121,7 +121,7 @@ public override async Task Select_collection_FirstOrDefault_project_anonymous_ty AssertSql( @"@__p_0='2' -SELECT [t1].[CustomerID], [t1].[OrderID], [t1].[c] +SELECT [t0].[CustomerID], [t0].[OrderID], [t0].[c] FROM ( SELECT TOP(@__p_0) [c].[CustomerID] FROM [Customers] AS [c] @@ -129,13 +129,13 @@ WHERE [c].[CustomerID] LIKE N'F%' ORDER BY [c].[CustomerID] ) AS [t] LEFT JOIN ( - SELECT [t0].[CustomerID], [t0].[OrderID], [t0].[c] + SELECT [t1].[CustomerID], [t1].[OrderID], [t1].[c] FROM ( SELECT [o].[CustomerID], [o].[OrderID], 1 AS [c], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -146,7 +146,7 @@ public override async Task Select_collection_FirstOrDefault_project_anonymous_ty AssertSql( @"@__p_0='2' -SELECT [t1].[CustomerID], [t1].[OrderID], [t1].[c] +SELECT [t0].[CustomerID], [t0].[OrderID], [t0].[c] FROM ( SELECT TOP(@__p_0) [c].[CustomerID] FROM [Customers] AS [c] @@ -154,13 +154,13 @@ WHERE [c].[CustomerID] LIKE N'F%' ORDER BY [c].[CustomerID] ) AS [t] LEFT JOIN ( - SELECT [t0].[CustomerID], [t0].[OrderID], [t0].[c] + SELECT [t1].[CustomerID], [t1].[OrderID], [t1].[c] FROM ( SELECT [o].[CustomerID], [o].[OrderID], 1 AS [c], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -171,20 +171,20 @@ public override async Task Select_collection_FirstOrDefault_project_entity(bool AssertSql( @"@__p_0='2' -SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] +SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] FROM ( SELECT TOP(@__p_0) [c].[CustomerID] FROM [Customers] AS [c] ORDER BY [c].[CustomerID] ) AS [t] LEFT JOIN ( - SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] + SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] FROM ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -195,7 +195,7 @@ public override async Task Skip_Select_Navigation(bool async) AssertSql( @"@__p_0='20' -SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] +SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] FROM ( SELECT [c].[CustomerID] FROM [Customers] AS [c] @@ -203,13 +203,13 @@ ORDER BY [c].[CustomerID] OFFSET @__p_0 ROWS ) AS [t] LEFT JOIN ( - SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] + SELECT [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate] FROM ( SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] FROM [Orders] AS [o] - ) AS [t0] - WHERE [t0].[row] <= 1 -) AS [t1] ON [t].[CustomerID] = [t1].[CustomerID] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[CustomerID] = [t0].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -295,13 +295,13 @@ public override async Task Select_count_plus_sum(bool async) AssertSql( @"SELECT ( - SELECT COALESCE(SUM(CAST([o].[Quantity] AS int)), 0) - FROM [Order Details] AS [o] - WHERE [o1].[OrderID] = [o].[OrderID]) + ( - SELECT COUNT(*) + SELECT COALESCE(SUM(CAST([o0].[Quantity] AS int)), 0) FROM [Order Details] AS [o0] - WHERE [o1].[OrderID] = [o0].[OrderID]) AS [Total] -FROM [Orders] AS [o1]"); + WHERE [o].[OrderID] = [o0].[OrderID]) + ( + SELECT COUNT(*) + FROM [Order Details] AS [o1] + WHERE [o].[OrderID] = [o1].[OrderID]) AS [Total] +FROM [Orders] AS [o]"); } public override async Task Singleton_Navigation_With_Member_Access(bool async) @@ -598,28 +598,28 @@ public override async Task Select_multiple_complex_projections(bool async) AssertSql( @"SELECT ( SELECT COUNT(*) - FROM [Order Details] AS [o] - WHERE [o3].[OrderID] = [o].[OrderID]) AS [collection1], [o3].[OrderDate] AS [scalar1], CASE + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) AS [collection1], [o].[OrderDate] AS [scalar1], CASE WHEN EXISTS ( SELECT 1 - FROM [Order Details] AS [o0] - WHERE ([o3].[OrderID] = [o0].[OrderID]) AND ([o0].[UnitPrice] > 10.0)) THEN CAST(1 AS bit) + FROM [Order Details] AS [o1] + WHERE ([o].[OrderID] = [o1].[OrderID]) AND ([o1].[UnitPrice] > 10.0)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [any], CASE - WHEN [o3].[CustomerID] = N'ALFKI' THEN N'50' + WHEN [o].[CustomerID] = N'ALFKI' THEN N'50' ELSE N'10' -END AS [conditional], [o3].[OrderID] AS [scalar2], CASE +END AS [conditional], [o].[OrderID] AS [scalar2], CASE WHEN NOT EXISTS ( SELECT 1 - FROM [Order Details] AS [o1] - WHERE ([o3].[OrderID] = [o1].[OrderID]) AND ([o1].[OrderID] <> 42)) THEN CAST(1 AS bit) + FROM [Order Details] AS [o2] + WHERE ([o].[OrderID] = [o2].[OrderID]) AND ([o2].[OrderID] <> 42)) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [all], ( SELECT COUNT_BIG(*) - FROM [Order Details] AS [o2] - WHERE [o3].[OrderID] = [o2].[OrderID]) AS [collection2] -FROM [Orders] AS [o3] -WHERE [o3].[CustomerID] IS NOT NULL AND ([o3].[CustomerID] LIKE N'A%')"); + FROM [Order Details] AS [o3] + WHERE [o].[OrderID] = [o3].[OrderID]) AS [collection2] +FROM [Orders] AS [o] +WHERE [o].[CustomerID] IS NOT NULL AND ([o].[CustomerID] LIKE N'A%')"); } public override async Task Collection_select_nav_prop_sum(bool async) @@ -704,12 +704,12 @@ public override async Task Collection_select_nav_prop_first_or_default_then_nav_ AssertSql( @"SELECT ( - SELECT TOP(1) [c].[City] + SELECT TOP(1) [c0].[City] FROM [Orders] AS [o] - LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] + LEFT JOIN [Customers] AS [c0] ON [o].[CustomerID] = [c0].[CustomerID] WHERE [o].[CustomerID] = N'ALFKI') -FROM [Customers] AS [c0] -WHERE [c0].[CustomerID] LIKE N'A%'"); +FROM [Customers] AS [c] +WHERE [c].[CustomerID] LIKE N'A%'"); } public override async Task Collection_select_nav_prop_single_or_default_then_nav_prop_nested(bool async) @@ -718,12 +718,12 @@ public override async Task Collection_select_nav_prop_single_or_default_then_nav AssertSql( @"SELECT ( - SELECT TOP(1) [c].[City] + SELECT TOP(1) [c0].[City] FROM [Orders] AS [o] - LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] + LEFT JOIN [Customers] AS [c0] ON [o].[CustomerID] = [c0].[CustomerID] WHERE [o].[OrderID] = 10643) -FROM [Customers] AS [c0] -WHERE [c0].[CustomerID] LIKE N'A%'"); +FROM [Customers] AS [c] +WHERE [c].[CustomerID] LIKE N'A%'"); } public override async Task Collection_select_nav_prop_first_or_default_then_nav_prop_nested_using_property_method(bool async) @@ -732,12 +732,12 @@ public override async Task Collection_select_nav_prop_first_or_default_then_nav_ AssertSql( @"SELECT ( - SELECT TOP(1) [c].[City] + SELECT TOP(1) [c0].[City] FROM [Orders] AS [o] - LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] + LEFT JOIN [Customers] AS [c0] ON [o].[CustomerID] = [c0].[CustomerID] WHERE [o].[CustomerID] = N'ALFKI') -FROM [Customers] AS [c0] -WHERE [c0].[CustomerID] LIKE N'A%'"); +FROM [Customers] AS [c] +WHERE [c].[CustomerID] LIKE N'A%'"); } public override async Task Collection_select_nav_prop_first_or_default_then_nav_prop_nested_with_orderby(bool async) @@ -746,13 +746,13 @@ public override async Task Collection_select_nav_prop_first_or_default_then_nav_ AssertSql( @"SELECT ( - SELECT TOP(1) [c].[City] + SELECT TOP(1) [c0].[City] FROM [Orders] AS [o] - LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] + LEFT JOIN [Customers] AS [c0] ON [o].[CustomerID] = [c0].[CustomerID] WHERE [o].[CustomerID] = N'ALFKI' ORDER BY [o].[CustomerID]) -FROM [Customers] AS [c0] -WHERE [c0].[CustomerID] LIKE N'A%'"); +FROM [Customers] AS [c] +WHERE [c].[CustomerID] LIKE N'A%'"); } public override async Task Navigation_fk_based_inside_contains(bool async) @@ -900,14 +900,14 @@ public override async Task Project_single_scalar_value_subquery_in_query_with_op @"@__p_0='3' SELECT [t].[OrderID], COALESCE(( - SELECT TOP(1) [o].[OrderID] - FROM [Order Details] AS [o] - WHERE [t].[OrderID] = [o].[OrderID] - ORDER BY [o].[OrderID], [o].[ProductID]), 0) AS [OrderDetail], [c].[City] + SELECT TOP(1) [o0].[OrderID] + FROM [Order Details] AS [o0] + WHERE [t].[OrderID] = [o0].[OrderID] + ORDER BY [o0].[OrderID], [o0].[ProductID]), 0) AS [OrderDetail], [c].[City] FROM ( - SELECT TOP(@__p_0) [o0].[OrderID], [o0].[CustomerID] - FROM [Orders] AS [o0] - ORDER BY [o0].[OrderID] + SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID] + FROM [Orders] AS [o] + ORDER BY [o].[OrderID] ) AS [t] LEFT JOIN [Customers] AS [c] ON [t].[CustomerID] = [c].[CustomerID] ORDER BY [t].[OrderID]"); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindQueryFiltersQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindQueryFiltersQuerySqlServerTest.cs index 4ef19169626..044d87f8f37 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindQueryFiltersQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindQueryFiltersQuerySqlServerTest.cs @@ -216,12 +216,12 @@ LEFT JOIN ( SELECT [c1].[CustomerID], [c1].[CompanyName] FROM [Customers] AS [c1] WHERE (@__ef_filter__TenantPrefix_0 = N'') OR ([c1].[CompanyName] IS NOT NULL AND (LEFT([c1].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0)) - ) AS [t1] ON [o1].[CustomerID] = [t1].[CustomerID] - WHERE [t1].[CustomerID] IS NOT NULL AND [t1].[CompanyName] IS NOT NULL + ) AS [t3] ON [o1].[CustomerID] = [t3].[CustomerID] + WHERE [t3].[CustomerID] IS NOT NULL AND [t3].[CompanyName] IS NOT NULL ) AS [t2] ON [o0].[OrderID] = [t2].[OrderID] WHERE [o0].[Quantity] > @__ef_filter___quantity_1 -) AS [t3] ON [t0].[OrderID] = [t3].[OrderID] -WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))) AND ([t3].[Discount] < CAST(10 AS real))"); +) AS [t1] ON [t0].[OrderID] = [t1].[OrderID] +WHERE ((@__ef_filter__TenantPrefix_0 = N'') OR ([c].[CompanyName] IS NOT NULL AND (LEFT([c].[CompanyName], LEN(@__ef_filter__TenantPrefix_0)) = @__ef_filter__TenantPrefix_0))) AND ([t1].[Discount] < CAST(10 AS real))"); } [ConditionalFact] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index 5d675fb6df6..3c54dd1a8fd 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -344,10 +344,10 @@ public override void Select_nested_collection_multi_level4() @"SELECT COALESCE(( SELECT TOP(1) ( SELECT COUNT(*) - FROM [Order Details] AS [o] - WHERE ([o0].[OrderID] = [o].[OrderID]) AND ([o].[OrderID] > 10)) - FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND ([o0].[OrderID] < 10500)), 0) AS [Order] + FROM [Order Details] AS [o0] + WHERE ([o].[OrderID] = [o0].[OrderID]) AND ([o0].[OrderID] > 10)) + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] < 10500)), 0) AS [Order] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -359,17 +359,17 @@ public override void Select_nested_collection_multi_level5() AssertSql( @"SELECT COALESCE(( SELECT TOP(1) COALESCE(( - SELECT TOP(1) [o].[ProductID] - FROM [Order Details] AS [o] - WHERE ([o1].[OrderID] = [o].[OrderID]) AND (([o].[OrderID] <> ( + SELECT TOP(1) [o0].[ProductID] + FROM [Order Details] AS [o0] + WHERE ([o].[OrderID] = [o0].[OrderID]) AND (([o0].[OrderID] <> ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID])) OR ( + FROM [Orders] AS [o1] + WHERE [c].[CustomerID] = [o1].[CustomerID])) OR ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID]) IS NULL)), 0) - FROM [Orders] AS [o1] - WHERE ([c].[CustomerID] = [o1].[CustomerID]) AND ([o1].[OrderID] < 10500)), 0) AS [Order] + FROM [Orders] AS [o1] + WHERE [c].[CustomerID] = [o1].[CustomerID]) IS NULL)), 0) + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] < 10500)), 0) AS [Order] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -381,11 +381,11 @@ public override void Select_nested_collection_multi_level6() AssertSql( @"SELECT COALESCE(( SELECT TOP(1) COALESCE(( - SELECT TOP(1) [o].[ProductID] - FROM [Order Details] AS [o] - WHERE ([o0].[OrderID] = [o].[OrderID]) AND ([o].[OrderID] <> CAST(LEN([c].[CustomerID]) AS int))), 0) - FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND ([o0].[OrderID] < 10500)), 0) AS [Order] + SELECT TOP(1) [o0].[ProductID] + FROM [Order Details] AS [o0] + WHERE ([o].[OrderID] = [o0].[OrderID]) AND ([o0].[OrderID] <> CAST(LEN([c].[CustomerID]) AS int))), 0) + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] < 10500)), 0) AS [Order] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'A%'"); } @@ -747,15 +747,15 @@ public override async Task Project_single_element_from_collection_with_OrderBy_o @"SELECT COALESCE(( SELECT TOP(1) [t].[OrderID] FROM ( - SELECT TOP(1) [o].[OrderID], [o].[ProductID], [p].[ProductID] AS [ProductID0], [p].[ProductName] - FROM [Order Details] AS [o] - INNER JOIN [Products] AS [p] ON [o].[ProductID] = [p].[ProductID] - WHERE [o0].[OrderID] = [o].[OrderID] + SELECT TOP(1) [o0].[OrderID], [o0].[ProductID], [p].[ProductID] AS [ProductID0], [p].[ProductName] + FROM [Order Details] AS [o0] + INNER JOIN [Products] AS [p] ON [o0].[ProductID] = [p].[ProductID] + WHERE [o].[OrderID] = [o0].[OrderID] ORDER BY [p].[ProductName] ) AS [t] ORDER BY [t].[ProductName]), 0) -FROM [Orders] AS [o0] -WHERE [o0].[OrderID] < 10300"); +FROM [Orders] AS [o] +WHERE [o].[OrderID] < 10300"); } public override async Task Project_single_element_from_collection_with_OrderBy_over_navigation_Take_and_FirstOrDefault_2( @@ -1389,14 +1389,14 @@ public override async Task Projection_AsEnumerable_projection(bool async) @"SELECT [c].[CustomerID], [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate] FROM [Customers] AS [c] LEFT JOIN ( - SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] - FROM [Orders] AS [o] - WHERE [o].[OrderID] < 10750 + SELECT [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] + FROM [Orders] AS [o0] + WHERE [o0].[OrderID] < 10750 ) AS [t] ON [c].[CustomerID] = [t].[CustomerID] WHERE ([c].[CustomerID] LIKE N'A%') AND (( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND ([o0].[OrderID] < 11000)) > 0) + FROM [Orders] AS [o] + WHERE ([o].[CustomerID] = [c].[CustomerID]) AND ([o].[OrderID] < 11000)) > 0) ORDER BY [c].[CustomerID], [t].[OrderID]"); } @@ -1418,7 +1418,7 @@ public override async Task Projecting_multiple_collection_with_same_constant_wor await base.Projecting_multiple_collection_with_same_constant_works(async); AssertSql( - @"SELECT [c].[CustomerID], 1, [o].[OrderID], [o0].[OrderID] + @"SELECT [c].[CustomerID], 1 AS [Value], [o].[OrderID], [o0].[OrderID] FROM [Customers] AS [c] LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] @@ -1584,7 +1584,7 @@ public override async Task Projecting_after_navigation_and_distinct(bool async) await base.Projecting_after_navigation_and_distinct(async); AssertSql( - @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [t0].[CustomerID], [t0].[OrderID], [t0].[OrderDate] + @"SELECT [t].[CustomerID], [t0].[CustomerID], [t0].[OrderID], [t0].[OrderDate] FROM ( SELECT DISTINCT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Orders] AS [o] @@ -1595,7 +1595,7 @@ OUTER APPLY ( FROM [Orders] AS [o0] WHERE [o0].[OrderID] IN (10248, 10249, 10250) AND (([t].[CustomerID] = [o0].[CustomerID]) OR ([t].[CustomerID] IS NULL AND [o0].[CustomerID] IS NULL)) ) AS [t0] -ORDER BY [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [t0].[OrderID]"); +ORDER BY [t].[CustomerID], [t0].[OrderID]"); } public override async Task Correlated_collection_after_distinct_with_complex_projection_containing_original_identifier(bool async) @@ -1697,14 +1697,14 @@ public override async Task Select_nested_collection_deep_distinct_no_identifiers await base.Select_nested_collection_deep_distinct_no_identifiers(async); AssertSql( - @"SELECT [t].[City], [t2].[OrderID], [t2].[OrderID0], [t2].[OrderID00] + @"SELECT [t].[City], [t1].[OrderID], [t1].[OrderID0], [t1].[OrderID00] FROM ( SELECT DISTINCT [c].[City] FROM [Customers] AS [c] WHERE [c].[City] = N'London' ) AS [t] OUTER APPLY ( - SELECT [t0].[OrderID], [t1].[OrderID] AS [OrderID0], [t1].[OrderID0] AS [OrderID00] + SELECT [t0].[OrderID], [t2].[OrderID] AS [OrderID0], [t2].[OrderID0] AS [OrderID00] FROM ( SELECT DISTINCT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] @@ -1714,9 +1714,34 @@ OUTER APPLY ( SELECT [t0].[OrderID], [o0].[OrderID] AS [OrderID0] FROM [Orders] AS [o0] WHERE ([t0].[CustomerID] = [t].[City]) OR ([t0].[CustomerID] IS NULL AND [t].[City] IS NULL) - ) AS [t1] -) AS [t2] -ORDER BY [t].[City], [t2].[OrderID], [t2].[OrderID00]"); + ) AS [t2] +) AS [t1] +ORDER BY [t].[City], [t1].[OrderID], [t1].[OrderID00]"); + } + + public override async Task Collection_include_over_result_of_single_non_scalar(bool async) + { + await base.Collection_include_over_result_of_single_non_scalar(async); + + AssertSql( + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[c], [t1].[OrderID], [t1].[CustomerID], [t1].[EmployeeID], [t1].[OrderDate], [t1].[OrderID0], [t1].[ProductID], [t1].[Discount], [t1].[Quantity], [t1].[UnitPrice], [o2].[OrderID], [o2].[ProductID], [o2].[Discount], [o2].[Quantity], [o2].[UnitPrice] +FROM [Customers] AS [c] +LEFT JOIN ( + SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t].[c] + FROM ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], 1 AS [c], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderDate]) AS [row] + FROM [Orders] AS [o] + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [c].[CustomerID] = [t0].[CustomerID] +LEFT JOIN ( + SELECT [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], [o1].[OrderID] AS [OrderID0], [o1].[ProductID], [o1].[Discount], [o1].[Quantity], [o1].[UnitPrice] + FROM [Orders] AS [o0] + LEFT JOIN [Order Details] AS [o1] ON [o0].[OrderID] = [o1].[OrderID] +) AS [t1] ON [c].[CustomerID] = [t1].[CustomerID] +LEFT JOIN [Order Details] AS [o2] ON [t0].[OrderID] = [o2].[OrderID] +WHERE [c].[CustomerID] LIKE N'F%' +ORDER BY [c].[CustomerID], [t0].[OrderID], [t1].[OrderID], [t1].[OrderID0], [t1].[ProductID], [o2].[OrderID], [o2].[ProductID]"); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSetOperationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSetOperationsQuerySqlServerTest.cs index c3c3ad203a6..bf2153020ca 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSetOperationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSetOperationsQuerySqlServerTest.cs @@ -386,14 +386,14 @@ public override async Task SubSelect_Union(bool async) AssertSql( @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( SELECT COUNT(*) - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID]) AS [Orders] + FROM [Orders] AS [o0] + WHERE [c].[CustomerID] = [o0].[CustomerID]) AS [Orders] FROM [Customers] AS [c] UNION SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region], ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [c0].[CustomerID] = [o0].[CustomerID]) AS [Orders] + FROM [Orders] AS [o] + WHERE [c0].[CustomerID] = [o].[CustomerID]) AS [Orders] FROM [Customers] AS [c0]"); } @@ -468,9 +468,23 @@ public override async Task Union_over_different_projection_types(bool async, str } // Fix up right-side SQL as table aliases shift - rightSql = leftType == "ScalarSubquery" - ? rightSql.Replace("[o]", "[o1]").Replace("[o0]", "[o2]") - : rightSql.Replace("[o0]", "[o1]").Replace("[o]", "[o0]"); + if (leftType == "ScalarSubquery") + { + if (rightType == "ScalarSubquery") + { + leftSql = leftSql.Replace("[o0]", "[o2]"); + rightSql = rightSql.Replace("[o0]", "[o1]").Replace("[o]", "[o0]"); + } + else + { + leftSql = leftSql.Replace("[o0]", "[o1]"); + rightSql = rightSql.Replace("[o]", "[o0]"); + } + } + else + { + rightSql = rightSql.Replace("[o0]", "[o1]").Replace("[o]", "[o0]"); + } AssertSql(leftSql + Environment.NewLine + "UNION" + Environment.NewLine + rightSql); @@ -497,9 +511,9 @@ FROM [Orders] AS [o] case "ScalarSubquery": return @"SELECT ( SELECT COUNT(*) - FROM [Order Details] AS [o] - WHERE [o0].[OrderID] = [o].[OrderID]){Alias} -FROM [Orders] AS [o0]"; + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]){Alias} +FROM [Orders] AS [o]"; default: throw new ArgumentException("Unexpected type: " + expressionType); } @@ -528,6 +542,40 @@ ORDER BY [c0].[ContactName] ) AS [t0]"); } + public override async Task Collection_projection_after_set_operation(bool async) + { + await base.Collection_projection_after_set_operation(async); + + AssertSql( + @"SELECT [t].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] + FROM [Customers] AS [c] + WHERE [c].[City] = N'Seatte' + UNION + SELECT [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] + FROM [Customers] AS [c0] + WHERE [c0].[CustomerID] LIKE N'F%' +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] +ORDER BY [t].[CustomerID], [o].[OrderID]"); + } + + public override async Task Concat_with_one_side_being_GroupBy_aggregate(bool async) + { + await base.Concat_with_one_side_being_GroupBy_aggregate(async); + + AssertSql( + @"SELECT [o].[OrderDate] +FROM [Orders] AS [o] +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] +WHERE [c].[City] = N'Seatte' +UNION +SELECT MAX([o0].[OrderDate]) AS [OrderDate] +FROM [Orders] AS [o0] +GROUP BY [o0].[CustomerID]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeQuerySqlServerTest.cs index d17205753f4..4d9724ddde2 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSplitIncludeQuerySqlServerTest.cs @@ -1284,13 +1284,13 @@ public override async Task Include_with_complex_projection_does_not_change_order AssertSql( @"SELECT [c].[CustomerID] AS [Id], ( SELECT COUNT(*) - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID]) AS [TotalOrders] + FROM [Orders] AS [o0] + WHERE [c].[CustomerID] = [o0].[CustomerID]) AS [TotalOrders] FROM [Customers] AS [c] WHERE ([c].[ContactTitle] = N'Owner') AND (( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID]) > 2) + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID]) > 2) ORDER BY [c].[CustomerID]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs index 4740f844e90..9f0981c4d23 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindWhereQuerySqlServerTest.cs @@ -1832,14 +1832,14 @@ public override async Task Where_Queryable_ToList_Count(bool async) await base.Where_Queryable_ToList_Count(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + @"SELECT [c].[CustomerID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [o0].[CustomerID] = [c].[CustomerID]) = 0 -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE [o].[CustomerID] = [c].[CustomerID]) = 0 +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_Queryable_ToList_Contains(bool async) @@ -1847,14 +1847,14 @@ public override async Task Where_Queryable_ToList_Contains(bool async) await base.Where_Queryable_ToList_Contains(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[CustomerID], [o].[OrderID] + @"SELECT [c].[CustomerID], [o0].[CustomerID], [o0].[OrderID] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE EXISTS ( SELECT 1 - FROM [Orders] AS [o0] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND ([o0].[CustomerID] = N'ALFKI')) -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE ([o].[CustomerID] = [c].[CustomerID]) AND ([o].[CustomerID] = N'ALFKI')) +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_Queryable_ToArray_Count(bool async) @@ -1862,14 +1862,14 @@ public override async Task Where_Queryable_ToArray_Count(bool async) await base.Where_Queryable_ToArray_Count(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + @"SELECT [c].[CustomerID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [o0].[CustomerID] = [c].[CustomerID]) = 0 -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE [o].[CustomerID] = [c].[CustomerID]) = 0 +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_Queryable_ToArray_Contains(bool async) @@ -1877,14 +1877,14 @@ public override async Task Where_Queryable_ToArray_Contains(bool async) await base.Where_Queryable_ToArray_Contains(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[CustomerID], [o].[OrderID] + @"SELECT [c].[CustomerID], [o0].[CustomerID], [o0].[OrderID] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE EXISTS ( SELECT 1 - FROM [Orders] AS [o0] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND ([o0].[CustomerID] = N'ALFKI')) -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE ([o].[CustomerID] = [c].[CustomerID]) AND ([o].[CustomerID] = N'ALFKI')) +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_Queryable_AsEnumerable_Count(bool async) @@ -1892,14 +1892,14 @@ public override async Task Where_Queryable_AsEnumerable_Count(bool async) await base.Where_Queryable_AsEnumerable_Count(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + @"SELECT [c].[CustomerID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [o0].[CustomerID] = [c].[CustomerID]) = 0 -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE [o].[CustomerID] = [c].[CustomerID]) = 0 +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_Queryable_AsEnumerable_Contains(bool async) @@ -1907,14 +1907,14 @@ public override async Task Where_Queryable_AsEnumerable_Contains(bool async) await base.Where_Queryable_AsEnumerable_Contains(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[CustomerID], [o].[OrderID] + @"SELECT [c].[CustomerID], [o0].[CustomerID], [o0].[OrderID] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE EXISTS ( SELECT 1 - FROM [Orders] AS [o0] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND ([o0].[CustomerID] = N'ALFKI')) -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE ([o].[CustomerID] = [c].[CustomerID]) AND ([o].[CustomerID] = N'ALFKI')) +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_Queryable_AsEnumerable_Contains_negated(bool async) @@ -1922,14 +1922,14 @@ public override async Task Where_Queryable_AsEnumerable_Contains_negated(bool as await base.Where_Queryable_AsEnumerable_Contains_negated(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[CustomerID], [o].[OrderID] + @"SELECT [c].[CustomerID], [o0].[CustomerID], [o0].[OrderID] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE NOT (EXISTS ( SELECT 1 - FROM [Orders] AS [o0] - WHERE ([o0].[CustomerID] = [c].[CustomerID]) AND ([o0].[CustomerID] = N'ALFKI'))) -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE ([o].[CustomerID] = [c].[CustomerID]) AND ([o].[CustomerID] = N'ALFKI'))) +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_Queryable_ToList_Count_member(bool async) @@ -1937,14 +1937,14 @@ public override async Task Where_Queryable_ToList_Count_member(bool async) await base.Where_Queryable_ToList_Count_member(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + @"SELECT [c].[CustomerID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [o0].[CustomerID] = [c].[CustomerID]) = 0 -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE [o].[CustomerID] = [c].[CustomerID]) = 0 +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_Queryable_ToArray_Length_member(bool async) @@ -1952,14 +1952,14 @@ public override async Task Where_Queryable_ToArray_Length_member(bool async) await base.Where_Queryable_ToArray_Length_member(async); AssertSql( - @"SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + @"SELECT [c].[CustomerID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [o0].[CustomerID] = [c].[CustomerID]) = 0 -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE [o].[CustomerID] = [c].[CustomerID]) = 0 +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_collection_navigation_ToList_Count(bool async) @@ -1967,14 +1967,14 @@ public override async Task Where_collection_navigation_ToList_Count(bool async) await base.Where_collection_navigation_ToList_Count(async); AssertSql( - @"SELECT [o].[OrderID], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] + @"SELECT [o].[OrderID], [o1].[OrderID], [o1].[ProductID], [o1].[Discount], [o1].[Quantity], [o1].[UnitPrice] FROM [Orders] AS [o] -LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Order Details] AS [o1] ON [o].[OrderID] = [o1].[OrderID] WHERE ([o].[OrderID] < 10300) AND (( SELECT COUNT(*) - FROM [Order Details] AS [o1] - WHERE [o].[OrderID] = [o1].[OrderID]) = 0) -ORDER BY [o].[OrderID], [o0].[OrderID], [o0].[ProductID]"); + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) = 0) +ORDER BY [o].[OrderID], [o1].[OrderID], [o1].[ProductID]"); } public override async Task Where_collection_navigation_ToList_Contains(bool async) @@ -1984,14 +1984,14 @@ public override async Task Where_collection_navigation_ToList_Contains(bool asyn AssertSql( @"@__entity_equality_order_0_OrderID='10248' (Nullable = true) -SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +SELECT [c].[CustomerID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE EXISTS ( SELECT 1 - FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND ([o0].[OrderID] = @__entity_equality_order_0_OrderID)) -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] = @__entity_equality_order_0_OrderID)) +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_collection_navigation_ToArray_Count(bool async) @@ -1999,14 +1999,14 @@ public override async Task Where_collection_navigation_ToArray_Count(bool async) await base.Where_collection_navigation_ToArray_Count(async); AssertSql( - @"SELECT [o].[OrderID], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] + @"SELECT [o].[OrderID], [o1].[OrderID], [o1].[ProductID], [o1].[Discount], [o1].[Quantity], [o1].[UnitPrice] FROM [Orders] AS [o] -LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Order Details] AS [o1] ON [o].[OrderID] = [o1].[OrderID] WHERE ([o].[OrderID] < 10300) AND (( SELECT COUNT(*) - FROM [Order Details] AS [o1] - WHERE [o].[OrderID] = [o1].[OrderID]) = 0) -ORDER BY [o].[OrderID], [o0].[OrderID], [o0].[ProductID]"); + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) = 0) +ORDER BY [o].[OrderID], [o1].[OrderID], [o1].[ProductID]"); } public override async Task Where_collection_navigation_ToArray_Contains(bool async) @@ -2016,14 +2016,14 @@ public override async Task Where_collection_navigation_ToArray_Contains(bool asy AssertSql( @"@__entity_equality_order_0_OrderID='10248' (Nullable = true) -SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +SELECT [c].[CustomerID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE EXISTS ( SELECT 1 - FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND ([o0].[OrderID] = @__entity_equality_order_0_OrderID)) -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] = @__entity_equality_order_0_OrderID)) +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_collection_navigation_AsEnumerable_Count(bool async) @@ -2031,14 +2031,14 @@ public override async Task Where_collection_navigation_AsEnumerable_Count(bool a await base.Where_collection_navigation_AsEnumerable_Count(async); AssertSql( - @"SELECT [o].[OrderID], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] + @"SELECT [o].[OrderID], [o1].[OrderID], [o1].[ProductID], [o1].[Discount], [o1].[Quantity], [o1].[UnitPrice] FROM [Orders] AS [o] -LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Order Details] AS [o1] ON [o].[OrderID] = [o1].[OrderID] WHERE ([o].[OrderID] < 10300) AND (( SELECT COUNT(*) - FROM [Order Details] AS [o1] - WHERE [o].[OrderID] = [o1].[OrderID]) = 0) -ORDER BY [o].[OrderID], [o0].[OrderID], [o0].[ProductID]"); + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) = 0) +ORDER BY [o].[OrderID], [o1].[OrderID], [o1].[ProductID]"); } public override async Task Where_collection_navigation_AsEnumerable_Contains(bool async) @@ -2048,14 +2048,14 @@ public override async Task Where_collection_navigation_AsEnumerable_Contains(boo AssertSql( @"@__entity_equality_order_0_OrderID='10248' (Nullable = true) -SELECT [c].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +SELECT [c].[CustomerID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] -LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE EXISTS ( SELECT 1 - FROM [Orders] AS [o0] - WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND ([o0].[OrderID] = @__entity_equality_order_0_OrderID)) -ORDER BY [c].[CustomerID], [o].[OrderID]"); + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND ([o].[OrderID] = @__entity_equality_order_0_OrderID)) +ORDER BY [c].[CustomerID], [o0].[OrderID]"); } public override async Task Where_collection_navigation_ToList_Count_member(bool async) @@ -2063,14 +2063,14 @@ public override async Task Where_collection_navigation_ToList_Count_member(bool await base.Where_collection_navigation_ToList_Count_member(async); AssertSql( - @"SELECT [o].[OrderID], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] + @"SELECT [o].[OrderID], [o1].[OrderID], [o1].[ProductID], [o1].[Discount], [o1].[Quantity], [o1].[UnitPrice] FROM [Orders] AS [o] -LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Order Details] AS [o1] ON [o].[OrderID] = [o1].[OrderID] WHERE ([o].[OrderID] < 10300) AND (( SELECT COUNT(*) - FROM [Order Details] AS [o1] - WHERE [o].[OrderID] = [o1].[OrderID]) = 0) -ORDER BY [o].[OrderID], [o0].[OrderID], [o0].[ProductID]"); + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) = 0) +ORDER BY [o].[OrderID], [o1].[OrderID], [o1].[ProductID]"); } public override async Task Where_collection_navigation_ToArray_Length_member(bool async) @@ -2078,14 +2078,14 @@ public override async Task Where_collection_navigation_ToArray_Length_member(boo await base.Where_collection_navigation_ToArray_Length_member(async); AssertSql( - @"SELECT [o].[OrderID], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] + @"SELECT [o].[OrderID], [o1].[OrderID], [o1].[ProductID], [o1].[Discount], [o1].[Quantity], [o1].[UnitPrice] FROM [Orders] AS [o] -LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Order Details] AS [o1] ON [o].[OrderID] = [o1].[OrderID] WHERE ([o].[OrderID] < 10300) AND (( SELECT COUNT(*) - FROM [Order Details] AS [o1] - WHERE [o].[OrderID] = [o1].[OrderID]) = 0) -ORDER BY [o].[OrderID], [o0].[OrderID], [o0].[ProductID]"); + FROM [Order Details] AS [o0] + WHERE [o].[OrderID] = [o0].[OrderID]) = 0) +ORDER BY [o].[OrderID], [o1].[OrderID], [o1].[ProductID]"); } public override async Task Where_list_object_contains_over_value_type(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs index 50c4536e153..a139574fa46 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs @@ -170,14 +170,14 @@ public override async Task Navigation_rewrite_on_owned_collection(bool async) @"SELECT [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail] FROM [OwnedPerson] AS [o] LEFT JOIN ( - SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail] - FROM [Order] AS [o0] - LEFT JOIN [OrderDetail] AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) + SELECT [o1].[ClientId], [o1].[Id], [o1].[OrderDate], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id] AS [Id0], [o2].[Detail] + FROM [Order] AS [o1] + LEFT JOIN [OrderDetail] AS [o2] ON ([o1].[ClientId] = [o2].[OrderClientId]) AND ([o1].[Id] = [o2].[OrderId]) ) AS [t] ON [o].[Id] = [t].[ClientId] WHERE ( SELECT COUNT(*) - FROM [Order] AS [o2] - WHERE [o].[Id] = [o2].[ClientId]) > 0 + FROM [Order] AS [o0] + WHERE [o].[Id] = [o0].[ClientId]) > 0 ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId], [t].[Id0]"); } @@ -188,14 +188,14 @@ public override async Task Navigation_rewrite_on_owned_collection_with_compositi AssertSql( @"SELECT COALESCE(( SELECT TOP(1) CASE - WHEN [o].[Id] <> 42 THEN CAST(1 AS bit) + WHEN [o0].[Id] <> 42 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - FROM [Order] AS [o] - WHERE [o0].[Id] = [o].[ClientId] - ORDER BY [o].[Id]), CAST(0 AS bit)) -FROM [OwnedPerson] AS [o0] -ORDER BY [o0].[Id]"); + FROM [Order] AS [o0] + WHERE [o].[Id] = [o0].[ClientId] + ORDER BY [o0].[Id]), CAST(0 AS bit)) +FROM [OwnedPerson] AS [o] +ORDER BY [o].[Id]"); } public override async Task Navigation_rewrite_on_owned_collection_with_composition_complex(bool async) @@ -204,12 +204,12 @@ public override async Task Navigation_rewrite_on_owned_collection_with_compositi AssertSql( @"SELECT ( - SELECT TOP(1) [o0].[PersonAddress_Country_Name] - FROM [Order] AS [o] - LEFT JOIN [OwnedPerson] AS [o0] ON [o].[ClientId] = [o0].[Id] - WHERE [o1].[Id] = [o].[ClientId] - ORDER BY [o].[Id]) -FROM [OwnedPerson] AS [o1]"); + SELECT TOP(1) [o1].[PersonAddress_Country_Name] + FROM [Order] AS [o0] + LEFT JOIN [OwnedPerson] AS [o1] ON [o0].[ClientId] = [o1].[Id] + WHERE [o].[Id] = [o0].[ClientId] + ORDER BY [o0].[Id]) +FROM [OwnedPerson] AS [o]"); } public override async Task SelectMany_on_owned_collection(bool async) @@ -274,14 +274,14 @@ public override async Task Project_multiple_owned_navigations_with_expansion_on_ AssertSql( @"SELECT ( SELECT COUNT(*) - FROM [Order] AS [o] - LEFT JOIN [OwnedPerson] AS [o0] ON [o].[ClientId] = [o0].[Id] - LEFT JOIN [Planet] AS [p] ON [o0].[PersonAddress_Country_PlanetId] = [p].[Id] - LEFT JOIN [Star] AS [s] ON [p].[StarId] = [s].[Id] - WHERE ([o1].[Id] = [o].[ClientId]) AND (([s].[Id] <> 42) OR [s].[Id] IS NULL)) AS [Count], [p0].[Id], [p0].[StarId] -FROM [OwnedPerson] AS [o1] -LEFT JOIN [Planet] AS [p0] ON [o1].[PersonAddress_Country_PlanetId] = [p0].[Id] -ORDER BY [o1].[Id]"); + FROM [Order] AS [o0] + LEFT JOIN [OwnedPerson] AS [o1] ON [o0].[ClientId] = [o1].[Id] + LEFT JOIN [Planet] AS [p0] ON [o1].[PersonAddress_Country_PlanetId] = [p0].[Id] + LEFT JOIN [Star] AS [s] ON [p0].[StarId] = [s].[Id] + WHERE ([o].[Id] = [o0].[ClientId]) AND (([s].[Id] <> 42) OR [s].[Id] IS NULL)) AS [Count], [p].[Id], [p].[StarId] +FROM [OwnedPerson] AS [o] +LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +ORDER BY [o].[Id]"); } public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_filter(bool async) @@ -582,15 +582,15 @@ public override async Task Where_owned_collection_navigation_ToList_Count(bool a await base.Where_owned_collection_navigation_ToList_Count(async); AssertSql( - @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail] + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail] FROM [OwnedPerson] AS [o] INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] -LEFT JOIN [OrderDetail] AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +LEFT JOIN [OrderDetail] AS [o2] ON ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId]) WHERE ( SELECT COUNT(*) - FROM [OrderDetail] AS [o2] - WHERE ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) = 0 -ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id]"); + FROM [OrderDetail] AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id]"); } public override async Task Where_collection_navigation_ToArray_Count(bool async) @@ -598,15 +598,15 @@ public override async Task Where_collection_navigation_ToArray_Count(bool async) await base.Where_collection_navigation_ToArray_Count(async); AssertSql( - @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail] + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail] FROM [OwnedPerson] AS [o] INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] -LEFT JOIN [OrderDetail] AS [o1] ON (([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) AND (([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) +LEFT JOIN [OrderDetail] AS [o2] ON (([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) AND (([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) WHERE ( SELECT COUNT(*) - FROM [OrderDetail] AS [o2] - WHERE ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) = 0 -ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id]"); + FROM [OrderDetail] AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id]"); } public override async Task Where_collection_navigation_AsEnumerable_Count(bool async) @@ -614,15 +614,15 @@ public override async Task Where_collection_navigation_AsEnumerable_Count(bool a await base.Where_collection_navigation_AsEnumerable_Count(async); AssertSql( - @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail] + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail] FROM [OwnedPerson] AS [o] INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] -LEFT JOIN [OrderDetail] AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +LEFT JOIN [OrderDetail] AS [o2] ON ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId]) WHERE ( SELECT COUNT(*) - FROM [OrderDetail] AS [o2] - WHERE ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) = 0 -ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id]"); + FROM [OrderDetail] AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id]"); } public override async Task Where_collection_navigation_ToList_Count_member(bool async) @@ -630,15 +630,15 @@ public override async Task Where_collection_navigation_ToList_Count_member(bool await base.Where_collection_navigation_ToList_Count_member(async); AssertSql( - @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail] + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail] FROM [OwnedPerson] AS [o] INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] -LEFT JOIN [OrderDetail] AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +LEFT JOIN [OrderDetail] AS [o2] ON ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId]) WHERE ( SELECT COUNT(*) - FROM [OrderDetail] AS [o2] - WHERE ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) = 0 -ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id]"); + FROM [OrderDetail] AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id]"); } public override async Task Where_collection_navigation_ToArray_Length_member(bool async) @@ -646,15 +646,15 @@ public override async Task Where_collection_navigation_ToArray_Length_member(boo await base.Where_collection_navigation_ToArray_Length_member(async); AssertSql( - @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail] + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail] FROM [OwnedPerson] AS [o] INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] -LEFT JOIN [OrderDetail] AS [o1] ON (([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) AND (([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) +LEFT JOIN [OrderDetail] AS [o2] ON (([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) AND (([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) WHERE ( SELECT COUNT(*) - FROM [OrderDetail] AS [o2] - WHERE ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId])) = 0 -ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id]"); + FROM [OrderDetail] AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id]"); } public override async Task Can_query_on_indexer_properties(bool async) @@ -1105,7 +1105,7 @@ public override async Task Using_from_sql_on_owner_generates_join_with_table_for await base.Using_from_sql_on_owner_generates_join_with_table_for_owned_shared_dependents(async); AssertSql( - @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [t].[Id], [t].[PersonAddress_AddressLine], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[Id1], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t1].[Id], [t1].[BranchAddress_BranchName], [t1].[BranchAddress_PlaceType], [t1].[Id1], [t1].[BranchAddress_Country_Name], [t1].[BranchAddress_Country_PlanetId], [t3].[Id], [t3].[LeafBAddress_LeafBType], [t3].[LeafBAddress_PlaceType], [t3].[Id1], [t3].[LeafBAddress_Country_Name], [t3].[LeafBAddress_Country_PlanetId], [t5].[Id], [t5].[LeafAAddress_LeafType], [t5].[LeafAAddress_PlaceType], [t5].[Id1], [t5].[LeafAAddress_Country_Name], [t5].[LeafAAddress_Country_PlanetId], [t].[Id0], [t1].[Id0], [t3].[Id0], [t5].[Id0], [t6].[ClientId], [t6].[Id], [t6].[OrderDate], [t6].[OrderClientId], [t6].[OrderId], [t6].[Id0], [t6].[Detail] + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [t].[Id], [t].[PersonAddress_AddressLine], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[Id1], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t0].[Id], [t0].[BranchAddress_BranchName], [t0].[BranchAddress_PlaceType], [t0].[Id1], [t0].[BranchAddress_Country_Name], [t0].[BranchAddress_Country_PlanetId], [t2].[Id], [t2].[LeafBAddress_LeafBType], [t2].[LeafBAddress_PlaceType], [t2].[Id1], [t2].[LeafBAddress_Country_Name], [t2].[LeafBAddress_Country_PlanetId], [t4].[Id], [t4].[LeafAAddress_LeafType], [t4].[LeafAAddress_PlaceType], [t4].[Id1], [t4].[LeafAAddress_Country_Name], [t4].[LeafAAddress_Country_PlanetId], [t].[Id0], [t0].[Id0], [t2].[Id0], [t4].[Id0], [t6].[ClientId], [t6].[Id], [t6].[OrderDate], [t6].[OrderClientId], [t6].[OrderId], [t6].[Id0], [t6].[Detail] FROM ( SELECT * FROM ""OwnedPerson"" ) AS [o] @@ -1116,41 +1116,41 @@ FROM [OwnedPerson] AS [o0] WHERE [o0].[PersonAddress_ZipCode] IS NOT NULL ) AS [t] ON [o].[Id] = [t].[Id] LEFT JOIN ( - SELECT [o2].[Id], [o2].[BranchAddress_BranchName], [o2].[BranchAddress_PlaceType], [t0].[Id] AS [Id0], [o2].[Id] AS [Id1], [o2].[BranchAddress_Country_Name], [o2].[BranchAddress_Country_PlanetId] + SELECT [o2].[Id], [o2].[BranchAddress_BranchName], [o2].[BranchAddress_PlaceType], [t1].[Id] AS [Id0], [o2].[Id] AS [Id1], [o2].[BranchAddress_Country_Name], [o2].[BranchAddress_Country_PlanetId] FROM [OwnedPerson] AS [o2] INNER JOIN ( SELECT [o3].[Id] FROM [OwnedPerson] AS [o3] WHERE [o3].[Discriminator] IN (N'Branch', N'LeafA') - ) AS [t0] ON [o2].[Id] = [t0].[Id] + ) AS [t1] ON [o2].[Id] = [t1].[Id] WHERE [o2].[BranchAddress_PlaceType] IS NOT NULL OR [o2].[BranchAddress_BranchName] IS NOT NULL -) AS [t1] ON [o].[Id] = [t1].[Id] +) AS [t0] ON [o].[Id] = [t0].[Id] LEFT JOIN ( - SELECT [o4].[Id], [o4].[LeafBAddress_LeafBType], [o4].[LeafBAddress_PlaceType], [t2].[Id] AS [Id0], [o4].[Id] AS [Id1], [o4].[LeafBAddress_Country_Name], [o4].[LeafBAddress_Country_PlanetId] + SELECT [o4].[Id], [o4].[LeafBAddress_LeafBType], [o4].[LeafBAddress_PlaceType], [t3].[Id] AS [Id0], [o4].[Id] AS [Id1], [o4].[LeafBAddress_Country_Name], [o4].[LeafBAddress_Country_PlanetId] FROM [OwnedPerson] AS [o4] INNER JOIN ( SELECT [o5].[Id] FROM [OwnedPerson] AS [o5] WHERE [o5].[Discriminator] = N'LeafB' - ) AS [t2] ON [o4].[Id] = [t2].[Id] + ) AS [t3] ON [o4].[Id] = [t3].[Id] WHERE [o4].[LeafBAddress_PlaceType] IS NOT NULL OR [o4].[LeafBAddress_LeafBType] IS NOT NULL -) AS [t3] ON [o].[Id] = [t3].[Id] +) AS [t2] ON [o].[Id] = [t2].[Id] LEFT JOIN ( - SELECT [o6].[Id], [o6].[LeafAAddress_LeafType], [o6].[LeafAAddress_PlaceType], [t4].[Id] AS [Id0], [o6].[Id] AS [Id1], [o6].[LeafAAddress_Country_Name], [o6].[LeafAAddress_Country_PlanetId] + SELECT [o6].[Id], [o6].[LeafAAddress_LeafType], [o6].[LeafAAddress_PlaceType], [t5].[Id] AS [Id0], [o6].[Id] AS [Id1], [o6].[LeafAAddress_Country_Name], [o6].[LeafAAddress_Country_PlanetId] FROM [OwnedPerson] AS [o6] INNER JOIN ( SELECT [o7].[Id] FROM [OwnedPerson] AS [o7] WHERE [o7].[Discriminator] = N'LeafA' - ) AS [t4] ON [o6].[Id] = [t4].[Id] + ) AS [t5] ON [o6].[Id] = [t5].[Id] WHERE [o6].[LeafAAddress_LeafType] IS NOT NULL -) AS [t5] ON [o].[Id] = [t5].[Id] +) AS [t4] ON [o].[Id] = [t4].[Id] LEFT JOIN ( SELECT [o8].[ClientId], [o8].[Id], [o8].[OrderDate], [o9].[OrderClientId], [o9].[OrderId], [o9].[Id] AS [Id0], [o9].[Detail] FROM [Order] AS [o8] LEFT JOIN [OrderDetail] AS [o9] ON ([o8].[ClientId] = [o9].[OrderClientId]) AND ([o8].[Id] = [o9].[OrderId]) ) AS [t6] ON [o].[Id] = [t6].[ClientId] -ORDER BY [o].[Id], [t].[Id], [t].[Id0], [t1].[Id], [t1].[Id0], [t3].[Id], [t3].[Id0], [t5].[Id], [t5].[Id0], [t6].[ClientId], [t6].[Id], [t6].[OrderClientId], [t6].[OrderId], [t6].[Id0]"); +ORDER BY [o].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t2].[Id], [t2].[Id0], [t4].[Id], [t4].[Id0], [t6].[ClientId], [t6].[Id], [t6].[OrderClientId], [t6].[OrderId], [t6].[Id0]"); } public override async Task Projecting_collection_correlated_with_keyless_entity_after_navigation_works_using_parent_identifiers(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs index 1d917d23ddd..c9c074d59d5 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs @@ -2823,20 +2823,20 @@ from a in grouping.DefaultIfEmpty() Assert.Empty(query); AssertSql( - @"SELECT [t2].[AnotherEntity11818_Name] AS [Key], COUNT(*) + 5 AS [cnt] + @"SELECT [t1].[AnotherEntity11818_Name] AS [Key], COUNT(*) + 5 AS [cnt] FROM [Table] AS [t] LEFT JOIN ( SELECT [t0].[Id], [t0].[AnotherEntity11818_Name] FROM [Table] AS [t0] - INNER JOIN [Table] AS [t1] ON [t0].[Id] = [t1].[Id] + INNER JOIN [Table] AS [t2] ON [t0].[Id] = [t2].[Id] WHERE [t0].[AnotherEntity11818_Name] IS NOT NULL -) AS [t2] ON [t].[Id] = [t2].[Id] -GROUP BY [t2].[AnotherEntity11818_Name]"); - ClearLog(); +) AS [t1] ON [t].[Id] = [t1].[Id] +GROUP BY [t1].[AnotherEntity11818_Name]"); } using (var context = contextFactory.CreateContext()) { + ClearLog(); var query = (from e in context.Set() join a in context.Set() on e.Id equals a.Id into grouping @@ -2854,26 +2854,27 @@ from m in grouping2.DefaultIfEmpty() Assert.Empty(query); AssertSql( - @"SELECT [t2].[AnotherEntity11818_Name] AS [MyKey], COUNT(*) + 5 AS [cnt] + @"SELECT [t1].[AnotherEntity11818_Name] AS [MyKey], COUNT(*) + 5 AS [cnt] FROM [Table] AS [t] LEFT JOIN ( SELECT [t0].[Id], [t0].[AnotherEntity11818_Name] FROM [Table] AS [t0] - INNER JOIN [Table] AS [t1] ON [t0].[Id] = [t1].[Id] + INNER JOIN [Table] AS [t2] ON [t0].[Id] = [t2].[Id] WHERE [t0].[AnotherEntity11818_Name] IS NOT NULL -) AS [t2] ON [t].[Id] = [t2].[Id] +) AS [t1] ON [t].[Id] = [t1].[Id] LEFT JOIN ( - SELECT [t3].[Id], [t3].[MaumarEntity11818_Name] - FROM [Table] AS [t3] - INNER JOIN [Table] AS [t4] ON [t3].[Id] = [t4].[Id] - WHERE [t3].[MaumarEntity11818_Name] IS NOT NULL -) AS [t5] ON [t].[Id] = [t5].[Id] -GROUP BY [t2].[AnotherEntity11818_Name], [t5].[MaumarEntity11818_Name]"); - ClearLog(); + SELECT [t4].[Id], [t4].[MaumarEntity11818_Name] + FROM [Table] AS [t4] + INNER JOIN [Table] AS [t5] ON [t4].[Id] = [t5].[Id] + WHERE [t4].[MaumarEntity11818_Name] IS NOT NULL +) AS [t3] ON [t].[Id] = [t3].[Id] +GROUP BY [t1].[AnotherEntity11818_Name], [t3].[MaumarEntity11818_Name]"); } using (var context = contextFactory.CreateContext()) { + + ClearLog(); var query = (from e in context.Set() join a in context.Set() on e.Id equals a.Id into grouping @@ -2889,21 +2890,21 @@ from m in grouping2.DefaultIfEmpty() Assert.Null(query); AssertSql( - @"SELECT TOP(1) [t2].[AnotherEntity11818_Name] AS [MyKey], [t5].[MaumarEntity11818_Name] AS [cnt] + @"SELECT TOP(1) [t1].[AnotherEntity11818_Name] AS [MyKey], [t3].[MaumarEntity11818_Name] AS [cnt] FROM [Table] AS [t] LEFT JOIN ( SELECT [t0].[Id], [t0].[AnotherEntity11818_Name] FROM [Table] AS [t0] - INNER JOIN [Table] AS [t1] ON [t0].[Id] = [t1].[Id] + INNER JOIN [Table] AS [t2] ON [t0].[Id] = [t2].[Id] WHERE [t0].[AnotherEntity11818_Name] IS NOT NULL -) AS [t2] ON [t].[Id] = [t2].[Id] +) AS [t1] ON [t].[Id] = [t1].[Id] LEFT JOIN ( - SELECT [t3].[Id], [t3].[MaumarEntity11818_Name] - FROM [Table] AS [t3] - INNER JOIN [Table] AS [t4] ON [t3].[Id] = [t4].[Id] - WHERE [t3].[MaumarEntity11818_Name] IS NOT NULL -) AS [t5] ON [t].[Id] = [t5].[Id] -GROUP BY [t2].[AnotherEntity11818_Name], [t5].[MaumarEntity11818_Name]"); + SELECT [t4].[Id], [t4].[MaumarEntity11818_Name] + FROM [Table] AS [t4] + INNER JOIN [Table] AS [t5] ON [t4].[Id] = [t5].[Id] + WHERE [t4].[MaumarEntity11818_Name] IS NOT NULL +) AS [t3] ON [t].[Id] = [t3].[Id] +GROUP BY [t1].[AnotherEntity11818_Name], [t3].[MaumarEntity11818_Name]"); } } @@ -5481,7 +5482,7 @@ CROSS JOIN ( SELECT [t].[Id] FROM ( SELECT NULL AS [empty] - ) AS [empty] + ) AS [e] LEFT JOIN ( SELECT [o].[Id] FROM [Organisations] AS [o] @@ -5674,19 +5675,19 @@ FROM [CompetitionSeasons] AS [c1] }).ToList(); AssertSql( - @"SELECT [a0].[Id], [a0].[ActivityTypeId], [a0].[DateTime], [a0].[Points], ( + @"SELECT [a].[Id], [a].[ActivityTypeId], [a].[DateTime], [a].[Points], ( SELECT TOP(1) [c].[Id] FROM [CompetitionSeasons] AS [c] - WHERE ([c].[StartDate] <= [a0].[DateTime]) AND ([a0].[DateTime] < [c].[EndDate])) AS [CompetitionSeasonId], COALESCE([a0].[Points], COALESCE(( - SELECT TOP(1) [a].[Points] - FROM [ActivityTypePoints12456] AS [a] - INNER JOIN [CompetitionSeasons] AS [c0] ON [a].[CompetitionSeasonId] = [c0].[Id] - WHERE ([a1].[Id] = [a].[ActivityTypeId]) AND ([c0].[Id] = ( + WHERE ([c].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c].[EndDate])) AS [CompetitionSeasonId], COALESCE([a].[Points], COALESCE(( + SELECT TOP(1) [a1].[Points] + FROM [ActivityTypePoints12456] AS [a1] + INNER JOIN [CompetitionSeasons] AS [c0] ON [a1].[CompetitionSeasonId] = [c0].[Id] + WHERE ([a0].[Id] = [a1].[ActivityTypeId]) AND ([c0].[Id] = ( SELECT TOP(1) [c1].[Id] FROM [CompetitionSeasons] AS [c1] - WHERE ([c1].[StartDate] <= [a0].[DateTime]) AND ([a0].[DateTime] < [c1].[EndDate])))), 0)) AS [Points] -FROM [Activities] AS [a0] -INNER JOIN [ActivityType12456] AS [a1] ON [a0].[ActivityTypeId] = [a1].[Id]"); + WHERE ([c1].[StartDate] <= [a].[DateTime]) AND ([a].[DateTime] < [c1].[EndDate])))), 0)) AS [Points] +FROM [Activities] AS [a] +INNER JOIN [ActivityType12456] AS [a0] ON [a].[ActivityTypeId] = [a0].[Id]"); } } @@ -5779,22 +5780,22 @@ public virtual async Task Max_in_multi_level_nested_subquery() .SingleAsync(); AssertSql( - @"SELECT [t0].[Id], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[IsPastTradeDeadline] + @"SELECT [t0].[Id], [t1].[Id], [t1].[Id0] AS [Id], [t1].[Id1] AS [Id], [t1].[IsPastTradeDeadline] FROM ( SELECT TOP(2) [t].[Id] FROM [Trades] AS [t] ) AS [t0] LEFT JOIN ( - SELECT [d0].[Id], [d1].[Id] AS [Id0], [d2].[Id] AS [Id1], CASE + SELECT [d].[Id], [d0].[Id] AS [Id0], [d1].[Id] AS [Id1], CASE WHEN COALESCE(( - SELECT MAX([d].[GameNumber]) - FROM [DbGame] AS [d] - WHERE [d2].[Id] IS NOT NULL AND ([d2].[Id] = [d].[SeasonId])), 0) > 10 THEN CAST(1 AS bit) + SELECT MAX([d2].[GameNumber]) + FROM [DbGame] AS [d2] + WHERE [d1].[Id] IS NOT NULL AND ([d1].[Id] = [d2].[SeasonId])), 0) > 10 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) - END AS [IsPastTradeDeadline], [d0].[DbTradeId] - FROM [DbTradeAsset] AS [d0] - INNER JOIN [DbContract] AS [d1] ON [d0].[ContractId] = [d1].[Id] - LEFT JOIN [DbSeason] AS [d2] ON [d1].[SeasonId] = [d2].[Id] + END AS [IsPastTradeDeadline], [d].[DbTradeId] + FROM [DbTradeAsset] AS [d] + INNER JOIN [DbContract] AS [d0] ON [d].[ContractId] = [d0].[Id] + LEFT JOIN [DbSeason] AS [d1] ON [d0].[SeasonId] = [d1].[Id] ) AS [t1] ON [t0].[Id] = [t1].[DbTradeId] ORDER BY [t0].[Id], [t1].[Id], [t1].[Id0], [t1].[Id1]"); } @@ -7729,23 +7730,23 @@ public virtual async Task Owned_entity_multiple_level_in_aggregate() Assert.Equal(20, aggregate.FirstValueObject.SecondValueObjects[0].ThirdValueObjects[0].FourthValueObject.FifthValueObjects[0].AnyValue); AssertSql( - @"SELECT [t].[Id], [t3].[Id], [t3].[AggregateId], [t3].[Id0], [t3].[AnyValue], [t3].[SecondValueObjectId], [t3].[Id1], [t3].[SecondValueObjectId0], [t3].[Id00], [t3].[AnyValue0], [t3].[ThirdValueObjectId] + @"SELECT [t].[Id], [t2].[Id], [t2].[AggregateId], [t2].[Id0], [t2].[AnyValue], [t2].[SecondValueObjectId], [t2].[Id1], [t2].[SecondValueObjectId0], [t2].[Id00], [t2].[AnyValue0], [t2].[ThirdValueObjectId] FROM ( SELECT TOP(1) [a].[Id] FROM [Aggregates] AS [a] ORDER BY [a].[Id] DESC ) AS [t] LEFT JOIN ( - SELECT [s].[Id], [s].[AggregateId], [f].[Id] AS [Id0], [f].[AnyValue], [f].[SecondValueObjectId], [t2].[Id] AS [Id1], [t2].[SecondValueObjectId] AS [SecondValueObjectId0], [t2].[Id0] AS [Id00], [t2].[AnyValue] AS [AnyValue0], [t2].[ThirdValueObjectId] + SELECT [s].[Id], [s].[AggregateId], [f].[Id] AS [Id0], [f].[AnyValue], [f].[SecondValueObjectId], [t1].[Id] AS [Id1], [t1].[SecondValueObjectId] AS [SecondValueObjectId0], [t1].[Id0] AS [Id00], [t1].[AnyValue] AS [AnyValue0], [t1].[ThirdValueObjectId] FROM [SecondValueObjects] AS [s] LEFT JOIN [FourthFifthValueObjects] AS [f] ON [s].[Id] = [f].[SecondValueObjectId] LEFT JOIN ( - SELECT [t0].[Id], [t0].[SecondValueObjectId], [t1].[Id] AS [Id0], [t1].[AnyValue], [t1].[ThirdValueObjectId] + SELECT [t0].[Id], [t0].[SecondValueObjectId], [t3].[Id] AS [Id0], [t3].[AnyValue], [t3].[ThirdValueObjectId] FROM [ThirdValueObjects] AS [t0] - LEFT JOIN [ThirdFifthValueObjects] AS [t1] ON [t0].[Id] = [t1].[ThirdValueObjectId] - ) AS [t2] ON [s].[Id] = [t2].[SecondValueObjectId] -) AS [t3] ON [t].[Id] = [t3].[AggregateId] -ORDER BY [t].[Id] DESC, [t3].[Id], [t3].[Id0], [t3].[Id1], [t3].[Id00]"); + LEFT JOIN [ThirdFifthValueObjects] AS [t3] ON [t0].[Id] = [t3].[ThirdValueObjectId] + ) AS [t1] ON [s].[Id] = [t1].[SecondValueObjectId] +) AS [t2] ON [t].[Id] = [t2].[AggregateId] +ORDER BY [t].[Id] DESC, [t2].[Id], [t2].[Id0], [t2].[Id1], [t2].[Id00]"); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index e66d65dd413..9c397182074 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -696,14 +696,14 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) WHERE ([g].[Rank] & COALESCE(( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId]), 0)) = COALESCE(( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId]), 0)", + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]), 0)) = COALESCE(( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]), 0)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' @@ -711,14 +711,14 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) WHERE (2 & COALESCE(( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId]), 0)) = COALESCE(( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId]), 0)"); + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]), 0)) = COALESCE(( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]), 0)"); } public override async Task Where_enum_has_flag_subquery_with_pushdown(bool async) @@ -732,18 +732,22 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) WHERE (([g].[Rank] & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL", + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId])) = ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId])) OR (( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL AND ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL)", // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' @@ -751,18 +755,22 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) WHERE ((2 & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL"); + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId])) = ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId])) OR (( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL AND ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL)"); } public override async Task Where_enum_has_flag_subquery_client_eval(bool async) @@ -776,18 +784,22 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) WHERE (([g].[Rank] & ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId])) OR ( - SELECT TOP(1) [g0].[Rank] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL"); + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId])) = ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId])) OR (( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL AND ( + SELECT TOP(1) [g1].[Rank] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + ORDER BY [g1].[Nickname], [g1].[SquadId]) IS NULL)"); } public override async Task Where_enum_has_flag_with_non_nullable_parameter(bool async) @@ -2014,23 +2026,23 @@ public override async Task Union_with_collection_navigations(bool async) @"SELECT ( SELECT COUNT(*) FROM ( - SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE - WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' - END AS [Discriminator] - FROM [Gears] AS [g] - LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) - WHERE ([g1].[Nickname] = [g].[LeaderNickname]) AND ([g1].[SquadId] = [g].[LeaderSquadId]) - UNION SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], CASE WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - WHERE ([g1].[Nickname] = [g0].[LeaderNickname]) AND ([g1].[SquadId] = [g0].[LeaderSquadId]) + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId]) + UNION + SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank], CASE + WHEN [o1].[Nickname] IS NOT NULL THEN N'Officer' + END AS [Discriminator] + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + WHERE ([g].[Nickname] = [g1].[LeaderNickname]) AND ([g].[SquadId] = [g1].[LeaderSquadId]) ) AS [t]) -FROM [Gears] AS [g1] -LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) -WHERE [o1].[Nickname] IS NOT NULL"); +FROM [Gears] AS [g] +LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) +WHERE [o].[Nickname] IS NOT NULL"); } public override async Task Select_subquery_distinct_firstordefault(bool async) @@ -3712,12 +3724,12 @@ public override async Task Collection_navigation_access_on_derived_entity_using_ AssertSql( @"SELECT [f].[Name], ( SELECT COUNT(*) - FROM [LocustLeaders] AS [l] - LEFT JOIN [LocustCommanders] AS [l0] ON [l].[Name] = [l0].[Name] - WHERE [f].[Id] = [l].[LocustHordeId]) AS [LeadersCount] + FROM [LocustLeaders] AS [l0] + LEFT JOIN [LocustCommanders] AS [l1] ON [l0].[Name] = [l1].[Name] + WHERE [f].[Id] = [l0].[LocustHordeId]) AS [LeadersCount] FROM [Factions] AS [f] -LEFT JOIN [LocustHordes] AS [l1] ON [f].[Id] = [l1].[Id] -WHERE [l1].[Id] IS NOT NULL +LEFT JOIN [LocustHordes] AS [l] ON [f].[Id] = [l].[Id] +WHERE [l].[Id] IS NOT NULL ORDER BY [f].[Name]"); } @@ -4744,28 +4756,28 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery(async); AssertSql( - @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[Id], [t2].[AmmunitionType], [t2].[IsAutomatic], [t2].[Name], [t2].[OwnerFullName], [t2].[SynergyWithId], [t2].[Nickname], [t2].[SquadId] + @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId], [t1].[Nickname], [t1].[SquadId] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN ( - SELECT [g0].[Nickname], [g0].[SquadId], [g0].[FullName] - FROM [Gears] AS [g0] + SELECT [g1].[Nickname], [g1].[SquadId], [g1].[FullName] + FROM [Gears] AS [g1] ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( - SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t1].[Nickname], [t1].[SquadId] + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t2].[Nickname], [t2].[SquadId] FROM [Weapons] AS [w] LEFT JOIN ( - SELECT [g1].[Nickname], [g1].[SquadId], [g1].[FullName] - FROM [Gears] AS [g1] - ) AS [t1] ON [w].[OwnerFullName] = [t1].[FullName] -) AS [t2] ON [t0].[FullName] = [t2].[OwnerFullName] + SELECT [g2].[Nickname], [g2].[SquadId], [g2].[FullName] + FROM [Gears] AS [g2] + ) AS [t2] ON [w].[OwnerFullName] = [t2].[FullName] +) AS [t1] ON [t0].[FullName] = [t1].[OwnerFullName] WHERE [o].[Nickname] IS NOT NULL AND EXISTS ( SELECT 1 - FROM [Gears] AS [g2] - LEFT JOIN [Officers] AS [o2] ON ([g2].[Nickname] = [o2].[Nickname]) AND ([g2].[SquadId] = [o2].[SquadId]) - WHERE ([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId])) -ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[IsAutomatic], [t2].[Nickname] DESC, [t2].[Id], [t2].[SquadId]"); + FROM [Gears] AS [g0] + LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) +ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[IsAutomatic], [t1].[Nickname] DESC, [t1].[Id], [t1].[SquadId]"); } public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_duplicated_orderings( @@ -4774,28 +4786,28 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_duplicated_orderings(async); AssertSql( - @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[Id], [t2].[AmmunitionType], [t2].[IsAutomatic], [t2].[Name], [t2].[OwnerFullName], [t2].[SynergyWithId], [t2].[Nickname], [t2].[SquadId] + @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId], [t1].[Nickname], [t1].[SquadId] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN ( - SELECT [g0].[Nickname], [g0].[SquadId], [g0].[FullName] - FROM [Gears] AS [g0] + SELECT [g1].[Nickname], [g1].[SquadId], [g1].[FullName] + FROM [Gears] AS [g1] ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( - SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t1].[Nickname], [t1].[SquadId] + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t2].[Nickname], [t2].[SquadId] FROM [Weapons] AS [w] LEFT JOIN ( - SELECT [g1].[Nickname], [g1].[SquadId], [g1].[FullName] - FROM [Gears] AS [g1] - ) AS [t1] ON [w].[OwnerFullName] = [t1].[FullName] -) AS [t2] ON [t0].[FullName] = [t2].[OwnerFullName] + SELECT [g2].[Nickname], [g2].[SquadId], [g2].[FullName] + FROM [Gears] AS [g2] + ) AS [t2] ON [w].[OwnerFullName] = [t2].[FullName] +) AS [t1] ON [t0].[FullName] = [t1].[OwnerFullName] WHERE [o].[Nickname] IS NOT NULL AND EXISTS ( SELECT 1 - FROM [Gears] AS [g2] - LEFT JOIN [Officers] AS [o2] ON ([g2].[Nickname] = [o2].[Nickname]) AND ([g2].[SquadId] = [o2].[SquadId]) - WHERE ([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId])) -ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[IsAutomatic], [t2].[Nickname] DESC, [t2].[Id], [t2].[SquadId]"); + FROM [Gears] AS [g0] + LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) +ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[IsAutomatic], [t1].[Nickname] DESC, [t1].[Id], [t1].[SquadId]"); } public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings( @@ -4804,31 +4816,31 @@ public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_ await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings(async); AssertSql( - @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[Id], [t2].[AmmunitionType], [t2].[IsAutomatic], [t2].[Name], [t2].[OwnerFullName], [t2].[SynergyWithId], [t2].[Nickname], [t2].[SquadId] + @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId], [t1].[Nickname], [t1].[SquadId] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN ( - SELECT [g0].[Nickname], [g0].[SquadId], [g0].[FullName] - FROM [Gears] AS [g0] + SELECT [g1].[Nickname], [g1].[SquadId], [g1].[FullName] + FROM [Gears] AS [g1] ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( - SELECT [w0].[Id], [w0].[AmmunitionType], [w0].[IsAutomatic], [w0].[Name], [w0].[OwnerFullName], [w0].[SynergyWithId], [t1].[Nickname], [t1].[SquadId], ( + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t2].[Nickname], [t2].[SquadId], ( SELECT COUNT(*) - FROM [Weapons] AS [w] - WHERE [t1].[FullName] IS NOT NULL AND ([t1].[FullName] = [w].[OwnerFullName])) AS [c] - FROM [Weapons] AS [w0] + FROM [Weapons] AS [w0] + WHERE [t2].[FullName] IS NOT NULL AND ([t2].[FullName] = [w0].[OwnerFullName])) AS [c] + FROM [Weapons] AS [w] LEFT JOIN ( - SELECT [g1].[Nickname], [g1].[SquadId], [g1].[FullName] - FROM [Gears] AS [g1] - ) AS [t1] ON [w0].[OwnerFullName] = [t1].[FullName] -) AS [t2] ON [t0].[FullName] = [t2].[OwnerFullName] + SELECT [g2].[Nickname], [g2].[SquadId], [g2].[FullName] + FROM [Gears] AS [g2] + ) AS [t2] ON [w].[OwnerFullName] = [t2].[FullName] +) AS [t1] ON [t0].[FullName] = [t1].[OwnerFullName] WHERE [o].[Nickname] IS NOT NULL AND EXISTS ( SELECT 1 - FROM [Gears] AS [g2] - LEFT JOIN [Officers] AS [o2] ON ([g2].[Nickname] = [o2].[Nickname]) AND ([g2].[SquadId] = [o2].[SquadId]) - WHERE ([g].[Nickname] = [g2].[LeaderNickname]) AND ([g].[SquadId] = [g2].[LeaderSquadId])) -ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[Id] DESC, [t2].[c], [t2].[Nickname], [t2].[SquadId]"); + FROM [Gears] AS [g0] + LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) +ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[Id] DESC, [t1].[c], [t1].[Nickname], [t1].[SquadId]"); } public override async Task Correlated_collections_multiple_nested_complex_collections(bool async) @@ -4836,48 +4848,48 @@ public override async Task Correlated_collections_multiple_nested_complex_collec await base.Correlated_collections_multiple_nested_complex_collections(async); AssertSql( - @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t4].[FullName], [t4].[Nickname], [t4].[SquadId], [t4].[Id], [t4].[Nickname0], [t4].[SquadId0], [t4].[Id0], [t4].[Name], [t4].[IsAutomatic], [t4].[Id1], [t4].[Nickname00], [t4].[HasSoulPatch], [t4].[SquadId00], [t6].[Id], [t6].[AmmunitionType], [t6].[IsAutomatic], [t6].[Name], [t6].[OwnerFullName], [t6].[SynergyWithId], [t6].[Nickname], [t6].[SquadId] + @"SELECT [g].[FullName], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[FullName], [t2].[Nickname], [t2].[SquadId], [t2].[Id], [t2].[Nickname0], [t2].[SquadId0], [t2].[Id0], [t2].[Name], [t2].[IsAutomatic], [t2].[Id1], [t2].[Nickname00], [t2].[HasSoulPatch], [t2].[SquadId00], [t5].[Id], [t5].[AmmunitionType], [t5].[IsAutomatic], [t5].[Name], [t5].[OwnerFullName], [t5].[SynergyWithId], [t5].[Nickname], [t5].[SquadId] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) LEFT JOIN [Tags] AS [t] ON ([g].[Nickname] = [t].[GearNickName]) AND ([g].[SquadId] = [t].[GearSquadId]) LEFT JOIN ( - SELECT [g0].[Nickname], [g0].[SquadId], [g0].[FullName] - FROM [Gears] AS [g0] + SELECT [g1].[Nickname], [g1].[SquadId], [g1].[FullName] + FROM [Gears] AS [g1] ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( - SELECT [g1].[FullName], [g1].[Nickname], [g1].[SquadId], [t3].[Id], [t3].[Nickname] AS [Nickname0], [t3].[SquadId] AS [SquadId0], [t3].[Id0], [t3].[Name], [t3].[IsAutomatic], [t3].[Id1], [t3].[Nickname0] AS [Nickname00], [t3].[HasSoulPatch], [t3].[SquadId0] AS [SquadId00], [g1].[Rank], [t3].[IsAutomatic0], [g1].[LeaderNickname], [g1].[LeaderSquadId] - FROM [Gears] AS [g1] + SELECT [g2].[FullName], [g2].[Nickname], [g2].[SquadId], [t1].[Id], [t1].[Nickname] AS [Nickname0], [t1].[SquadId] AS [SquadId0], [t1].[Id0], [t1].[Name], [t1].[IsAutomatic], [t1].[Id1], [t1].[Nickname0] AS [Nickname00], [t1].[HasSoulPatch], [t1].[SquadId0] AS [SquadId00], [g2].[Rank], [t1].[IsAutomatic0], [g2].[LeaderNickname], [g2].[LeaderSquadId] + FROM [Gears] AS [g2] LEFT JOIN ( - SELECT [w].[Id], [t1].[Nickname], [t1].[SquadId], [s].[Id] AS [Id0], [w0].[Name], [w0].[IsAutomatic], [w0].[Id] AS [Id1], [t2].[Nickname] AS [Nickname0], [t2].[HasSoulPatch], [t2].[SquadId] AS [SquadId0], [w].[IsAutomatic] AS [IsAutomatic0], [w].[OwnerFullName] + SELECT [w].[Id], [t3].[Nickname], [t3].[SquadId], [s].[Id] AS [Id0], [w0].[Name], [w0].[IsAutomatic], [w0].[Id] AS [Id1], [t4].[Nickname] AS [Nickname0], [t4].[HasSoulPatch], [t4].[SquadId] AS [SquadId0], [w].[IsAutomatic] AS [IsAutomatic0], [w].[OwnerFullName] FROM [Weapons] AS [w] LEFT JOIN ( - SELECT [g2].[Nickname], [g2].[SquadId], [g2].[FullName] - FROM [Gears] AS [g2] - ) AS [t1] ON [w].[OwnerFullName] = [t1].[FullName] - LEFT JOIN [Squads] AS [s] ON [t1].[SquadId] = [s].[Id] - LEFT JOIN [Weapons] AS [w0] ON [t1].[FullName] = [w0].[OwnerFullName] - LEFT JOIN ( - SELECT [g3].[Nickname], [g3].[HasSoulPatch], [g3].[SquadId] + SELECT [g3].[Nickname], [g3].[SquadId], [g3].[FullName] FROM [Gears] AS [g3] - ) AS [t2] ON [s].[Id] = [t2].[SquadId] + ) AS [t3] ON [w].[OwnerFullName] = [t3].[FullName] + LEFT JOIN [Squads] AS [s] ON [t3].[SquadId] = [s].[Id] + LEFT JOIN [Weapons] AS [w0] ON [t3].[FullName] = [w0].[OwnerFullName] + LEFT JOIN ( + SELECT [g4].[Nickname], [g4].[HasSoulPatch], [g4].[SquadId] + FROM [Gears] AS [g4] + ) AS [t4] ON [s].[Id] = [t4].[SquadId] WHERE ([w].[Name] <> N'Bar') OR [w].[Name] IS NULL - ) AS [t3] ON [g1].[FullName] = [t3].[OwnerFullName] - WHERE [g1].[FullName] <> N'Foo' -) AS [t4] ON ([g].[Nickname] = [t4].[LeaderNickname]) AND ([g].[SquadId] = [t4].[LeaderSquadId]) + ) AS [t1] ON [g2].[FullName] = [t1].[OwnerFullName] + WHERE [g2].[FullName] <> N'Foo' +) AS [t2] ON ([g].[Nickname] = [t2].[LeaderNickname]) AND ([g].[SquadId] = [t2].[LeaderSquadId]) LEFT JOIN ( - SELECT [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[SynergyWithId], [t5].[Nickname], [t5].[SquadId] + SELECT [w1].[Id], [w1].[AmmunitionType], [w1].[IsAutomatic], [w1].[Name], [w1].[OwnerFullName], [w1].[SynergyWithId], [t6].[Nickname], [t6].[SquadId] FROM [Weapons] AS [w1] LEFT JOIN ( - SELECT [g4].[Nickname], [g4].[SquadId], [g4].[FullName] - FROM [Gears] AS [g4] - ) AS [t5] ON [w1].[OwnerFullName] = [t5].[FullName] -) AS [t6] ON [t0].[FullName] = [t6].[OwnerFullName] + SELECT [g5].[Nickname], [g5].[SquadId], [g5].[FullName] + FROM [Gears] AS [g5] + ) AS [t6] ON [w1].[OwnerFullName] = [t6].[FullName] +) AS [t5] ON [t0].[FullName] = [t5].[OwnerFullName] WHERE [o].[Nickname] IS NOT NULL AND EXISTS ( SELECT 1 - FROM [Gears] AS [g5] - LEFT JOIN [Officers] AS [o5] ON ([g5].[Nickname] = [o5].[Nickname]) AND ([g5].[SquadId] = [o5].[SquadId]) - WHERE ([g].[Nickname] = [g5].[LeaderNickname]) AND ([g].[SquadId] = [g5].[LeaderSquadId])) -ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t4].[Rank], [t4].[Nickname], [t4].[SquadId], [t4].[IsAutomatic0], [t4].[Id], [t4].[Nickname0], [t4].[SquadId0], [t4].[Id0], [t4].[Id1], [t4].[Nickname00], [t4].[SquadId00], [t6].[IsAutomatic], [t6].[Nickname] DESC, [t6].[Id], [t6].[SquadId]"); + FROM [Gears] AS [g0] + LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) + WHERE ([g].[Nickname] = [g0].[LeaderNickname]) AND ([g].[SquadId] = [g0].[LeaderSquadId])) +ORDER BY [g].[HasSoulPatch] DESC, [t].[Note], [g].[Nickname], [g].[SquadId], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[Rank], [t2].[Nickname], [t2].[SquadId], [t2].[IsAutomatic0], [t2].[Id], [t2].[Nickname0], [t2].[SquadId0], [t2].[Id0], [t2].[Id1], [t2].[Nickname00], [t2].[SquadId00], [t5].[IsAutomatic], [t5].[Nickname] DESC, [t5].[Id], [t5].[SquadId]"); } public override async Task Correlated_collections_inner_subquery_selector_references_outer_qsre(bool async) @@ -5127,7 +5139,7 @@ public override async Task Correlated_collections_deeply_nested_left_join(bool a await base.Correlated_collections_deeply_nested_left_join(async); AssertSql( - @"SELECT [t].[Id], [t0].[Nickname], [t0].[SquadId], [s].[Id], [t2].[Nickname], [t2].[SquadId], [t2].[Id], [t2].[AmmunitionType], [t2].[IsAutomatic], [t2].[Name], [t2].[OwnerFullName], [t2].[SynergyWithId] + @"SELECT [t].[Id], [t0].[Nickname], [t0].[SquadId], [s].[Id], [t1].[Nickname], [t1].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId] FROM [Tags] AS [t] LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId] @@ -5135,16 +5147,16 @@ FROM [Gears] AS [g] ) AS [t0] ON [t].[GearNickName] = [t0].[Nickname] LEFT JOIN [Squads] AS [s] ON [t0].[SquadId] = [s].[Id] LEFT JOIN ( - SELECT [g0].[Nickname], [g0].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId] + SELECT [g0].[Nickname], [g0].[SquadId], [t2].[Id], [t2].[AmmunitionType], [t2].[IsAutomatic], [t2].[Name], [t2].[OwnerFullName], [t2].[SynergyWithId] FROM [Gears] AS [g0] LEFT JOIN ( SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] FROM [Weapons] AS [w] WHERE [w].[IsAutomatic] = CAST(1 AS bit) - ) AS [t1] ON [g0].[FullName] = [t1].[OwnerFullName] + ) AS [t2] ON [g0].[FullName] = [t2].[OwnerFullName] WHERE [g0].[HasSoulPatch] = CAST(1 AS bit) -) AS [t2] ON [s].[Id] = [t2].[SquadId] -ORDER BY [t].[Note], [t0].[Nickname] DESC, [t].[Id], [t0].[SquadId], [s].[Id], [t2].[Nickname], [t2].[SquadId], [t2].[Id]"); +) AS [t1] ON [s].[Id] = [t1].[SquadId] +ORDER BY [t].[Note], [t0].[Nickname] DESC, [t].[Id], [t0].[SquadId], [s].[Id], [t1].[Nickname], [t1].[SquadId], [t1].[Id]"); } public override async Task Correlated_collections_from_left_join_with_additional_elements_projected_of_that_join(bool async) @@ -5152,7 +5164,7 @@ public override async Task Correlated_collections_from_left_join_with_additional await base.Correlated_collections_from_left_join_with_additional_elements_projected_of_that_join(async); AssertSql( - @"SELECT [w].[Id], [t].[Nickname], [t].[SquadId], [s].[Id], [t1].[Rank], [t1].[Nickname], [t1].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId] + @"SELECT [w].[Id], [t].[Nickname], [t].[SquadId], [s].[Id], [t0].[Rank], [t0].[Nickname], [t0].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId] FROM [Weapons] AS [w] LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[FullName] @@ -5160,15 +5172,15 @@ FROM [Gears] AS [g] ) AS [t] ON [w].[OwnerFullName] = [t].[FullName] LEFT JOIN [Squads] AS [s] ON [t].[SquadId] = [s].[Id] LEFT JOIN ( - SELECT [g0].[Rank], [g0].[Nickname], [g0].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId], [g0].[FullName] + SELECT [g0].[Rank], [g0].[Nickname], [g0].[SquadId], [t1].[Id], [t1].[AmmunitionType], [t1].[IsAutomatic], [t1].[Name], [t1].[OwnerFullName], [t1].[SynergyWithId], [g0].[FullName] FROM [Gears] AS [g0] LEFT JOIN ( SELECT [w0].[Id], [w0].[AmmunitionType], [w0].[IsAutomatic], [w0].[Name], [w0].[OwnerFullName], [w0].[SynergyWithId] FROM [Weapons] AS [w0] WHERE [w0].[IsAutomatic] = CAST(0 AS bit) - ) AS [t0] ON [g0].[FullName] = [t0].[OwnerFullName] -) AS [t1] ON [s].[Id] = [t1].[SquadId] -ORDER BY [w].[Name], [w].[Id], [t].[Nickname], [t].[SquadId], [s].[Id], [t1].[FullName] DESC, [t1].[Nickname], [t1].[SquadId], [t1].[Id]"); + ) AS [t1] ON [g0].[FullName] = [t1].[OwnerFullName] +) AS [t0] ON [s].[Id] = [t0].[SquadId] +ORDER BY [w].[Name], [w].[Id], [t].[Nickname], [t].[SquadId], [s].[Id], [t0].[FullName] DESC, [t0].[Nickname], [t0].[SquadId], [t0].[Id]"); } public override async Task Correlated_collections_complex_scenario1(bool async) @@ -6006,22 +6018,22 @@ public override async Task Correlated_collection_with_very_complex_order_by(bool FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) LEFT JOIN ( - SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], CASE - WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer' + SELECT [g1].[Nickname], [g1].[SquadId], [g1].[AssignedCityName], [g1].[CityOfBirthName], [g1].[FullName], [g1].[HasSoulPatch], [g1].[LeaderNickname], [g1].[LeaderSquadId], [g1].[Rank], CASE + WHEN [o1].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator] - FROM [Gears] AS [g0] - LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - WHERE [g0].[HasSoulPatch] = CAST(0 AS bit) + FROM [Gears] AS [g1] + LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) + WHERE [g1].[HasSoulPatch] = CAST(0 AS bit) ) AS [t] ON ([g].[Nickname] = [t].[LeaderNickname]) AND ([g].[SquadId] = [t].[LeaderSquadId]) WHERE [o].[Nickname] IS NOT NULL ORDER BY ( SELECT COUNT(*) FROM [Weapons] AS [w] WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[IsAutomatic] = COALESCE(( - SELECT TOP(1) [g1].[HasSoulPatch] - FROM [Gears] AS [g1] - LEFT JOIN [Officers] AS [o1] ON ([g1].[Nickname] = [o1].[Nickname]) AND ([g1].[SquadId] = [o1].[SquadId]) - WHERE [g1].[Nickname] = N'Marcus'), CAST(0 AS bit)))), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); + SELECT TOP(1) [g0].[HasSoulPatch] + FROM [Gears] AS [g0] + LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) + WHERE [g0].[Nickname] = N'Marcus'), CAST(0 AS bit)))), [g].[Nickname], [g].[SquadId], [t].[Nickname], [t].[SquadId]"); } public override async Task Cast_to_derived_type_after_OfType_works(bool async) @@ -6896,14 +6908,14 @@ public override async Task Include_with_complex_order_by(bool async) AssertSql( @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' -END AS [Discriminator], [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] +END AS [Discriminator], [w0].[Id], [w0].[AmmunitionType], [w0].[IsAutomatic], [w0].[Name], [w0].[OwnerFullName], [w0].[SynergyWithId] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) -LEFT JOIN [Weapons] AS [w] ON [g].[FullName] = [w].[OwnerFullName] +LEFT JOIN [Weapons] AS [w0] ON [g].[FullName] = [w0].[OwnerFullName] ORDER BY ( - SELECT TOP(1) [w0].[Name] - FROM [Weapons] AS [w0] - WHERE ([g].[FullName] = [w0].[OwnerFullName]) AND ([w0].[Name] LIKE N'%Gnasher%')), [g].[Nickname], [g].[SquadId], [w].[Id]"); + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE ([g].[FullName] = [w].[OwnerFullName]) AND ([w].[Name] LIKE N'%Gnasher%')), [g].[Nickname], [g].[SquadId], [w0].[Id]"); } public override async Task Anonymous_projection_take_followed_by_projecting_single_element_from_collection_navigation(bool async) @@ -7000,7 +7012,7 @@ public override async Task Project_collection_navigation_nested_with_take_compos await base.Project_collection_navigation_nested_with_take_composite_key(async); AssertSql( - @"SELECT [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[Nickname], [t2].[SquadId], [t2].[AssignedCityName], [t2].[CityOfBirthName], [t2].[FullName], [t2].[HasSoulPatch], [t2].[LeaderNickname], [t2].[LeaderSquadId], [t2].[Rank], [t2].[Discriminator] + @"SELECT [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[Nickname], [t1].[SquadId], [t1].[AssignedCityName], [t1].[CityOfBirthName], [t1].[FullName], [t1].[HasSoulPatch], [t1].[LeaderNickname], [t1].[LeaderSquadId], [t1].[Rank], [t1].[Discriminator] FROM [Tags] AS [t] LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], CASE @@ -7010,18 +7022,18 @@ FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( - SELECT [t1].[Nickname], [t1].[SquadId], [t1].[AssignedCityName], [t1].[CityOfBirthName], [t1].[FullName], [t1].[HasSoulPatch], [t1].[LeaderNickname], [t1].[LeaderSquadId], [t1].[Rank], [t1].[Discriminator] + SELECT [t2].[Nickname], [t2].[SquadId], [t2].[AssignedCityName], [t2].[CityOfBirthName], [t2].[FullName], [t2].[HasSoulPatch], [t2].[LeaderNickname], [t2].[LeaderSquadId], [t2].[Rank], [t2].[Discriminator] FROM ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], CASE WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer' END AS [Discriminator], ROW_NUMBER() OVER(PARTITION BY [g0].[LeaderNickname], [g0].[LeaderSquadId] ORDER BY [g0].[Nickname], [g0].[SquadId]) AS [row] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) - ) AS [t1] - WHERE [t1].[row] <= 50 -) AS [t2] ON (([t0].[Nickname] = [t2].[LeaderNickname]) OR ([t0].[Nickname] IS NULL AND [t2].[LeaderNickname] IS NULL)) AND ([t0].[SquadId] = [t2].[LeaderSquadId]) + ) AS [t2] + WHERE [t2].[row] <= 50 +) AS [t1] ON (([t0].[Nickname] = [t1].[LeaderNickname]) OR ([t0].[Nickname] IS NULL AND [t1].[LeaderNickname] IS NULL)) AND ([t0].[SquadId] = [t1].[LeaderSquadId]) WHERE [t0].[Discriminator] = N'Officer' -ORDER BY [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[LeaderNickname], [t2].[LeaderSquadId], [t2].[Nickname], [t2].[SquadId]"); +ORDER BY [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[LeaderNickname], [t1].[LeaderSquadId], [t1].[Nickname], [t1].[SquadId]"); } public override async Task Project_collection_navigation_nested_composite_key(bool async) @@ -7278,21 +7290,21 @@ public override async Task Accessing_property_of_optional_navigation_in_child_pr @"SELECT CASE WHEN [t0].[Nickname] IS NOT NULL AND [t0].[SquadId] IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) -END, [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[Nickname], [t2].[Id], [t2].[SquadId] +END, [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[Nickname], [t1].[Id], [t1].[SquadId] FROM [Tags] AS [t] LEFT JOIN ( SELECT [g].[Nickname], [g].[SquadId], [g].[FullName] FROM [Gears] AS [g] ) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) LEFT JOIN ( - SELECT [t1].[Nickname], [w].[Id], [t1].[SquadId], [w].[OwnerFullName] + SELECT [t2].[Nickname], [w].[Id], [t2].[SquadId], [w].[OwnerFullName] FROM [Weapons] AS [w] LEFT JOIN ( SELECT [g0].[Nickname], [g0].[SquadId], [g0].[FullName] FROM [Gears] AS [g0] - ) AS [t1] ON [w].[OwnerFullName] = [t1].[FullName] -) AS [t2] ON [t0].[FullName] = [t2].[OwnerFullName] -ORDER BY [t].[Note], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t2].[Id], [t2].[Nickname], [t2].[SquadId]"); + ) AS [t2] ON [w].[OwnerFullName] = [t2].[FullName] +) AS [t1] ON [t0].[FullName] = [t1].[OwnerFullName] +ORDER BY [t].[Note], [t].[Id], [t0].[Nickname], [t0].[SquadId], [t1].[Id], [t1].[Nickname], [t1].[SquadId]"); } public override async Task Collection_navigation_ofType_filter_works(bool async) @@ -7409,16 +7421,16 @@ public override async Task Complex_GroupBy_after_set_operator(bool async) FROM ( SELECT [c].[Name], ( SELECT COUNT(*) - FROM [Weapons] AS [w] - WHERE [g].[FullName] = [w].[OwnerFullName]) AS [Count] + FROM [Weapons] AS [w0] + WHERE [g].[FullName] = [w0].[OwnerFullName]) AS [Count] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] UNION ALL SELECT [c0].[Name], ( SELECT COUNT(*) - FROM [Weapons] AS [w0] - WHERE [g0].[FullName] = [w0].[OwnerFullName]) AS [Count] + FROM [Weapons] AS [w] + WHERE [g0].[FullName] = [w].[OwnerFullName]) AS [Count] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) INNER JOIN [Cities] AS [c0] ON [g0].[CityOfBirthName] = [c0].[Name] @@ -7435,16 +7447,16 @@ public override async Task Complex_GroupBy_after_set_operator_using_result_selec FROM ( SELECT [c].[Name], ( SELECT COUNT(*) - FROM [Weapons] AS [w] - WHERE [g].[FullName] = [w].[OwnerFullName]) AS [Count] + FROM [Weapons] AS [w0] + WHERE [g].[FullName] = [w0].[OwnerFullName]) AS [Count] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) LEFT JOIN [Cities] AS [c] ON [g].[AssignedCityName] = [c].[Name] UNION ALL SELECT [c0].[Name], ( SELECT COUNT(*) - FROM [Weapons] AS [w0] - WHERE [g0].[FullName] = [w0].[OwnerFullName]) AS [Count] + FROM [Weapons] AS [w] + WHERE [g0].[FullName] = [w].[OwnerFullName]) AS [Count] FROM [Gears] AS [g0] LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) INNER JOIN [Cities] AS [c0] ON [g0].[CityOfBirthName] = [c0].[Name] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs index 3dd85358021..befa603bc6b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs @@ -218,11 +218,11 @@ public override async Task Skip_navigation_select_subquery_max(bool async) AssertSql( @"SELECT ( - SELECT MAX([e].[Id]) + SELECT MAX([e0].[Id]) FROM [JoinOneToTwo] AS [j] - INNER JOIN [EntityOnes] AS [e] ON [j].[OneId] = [e].[Id] - WHERE [e0].[Id] = [j].[TwoId]) -FROM [EntityTwos] AS [e0]"); + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e].[Id] = [j].[TwoId]) +FROM [EntityTwos] AS [e]"); } public override async Task Skip_navigation_select_subquery_min(bool async) @@ -231,11 +231,11 @@ public override async Task Skip_navigation_select_subquery_min(bool async) AssertSql( @"SELECT ( - SELECT MIN([e].[Id]) + SELECT MIN([e0].[Id]) FROM [JoinOneToThreePayloadFull] AS [j] - INNER JOIN [EntityOnes] AS [e] ON [j].[OneId] = [e].[Id] - WHERE [e0].[Id] = [j].[ThreeId]) -FROM [EntityThrees] AS [e0]"); + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e].[Id] = [j].[ThreeId]) +FROM [EntityThrees] AS [e]"); } public override async Task Skip_navigation_select_subquery_sum(bool async) @@ -244,11 +244,11 @@ public override async Task Skip_navigation_select_subquery_sum(bool async) AssertSql( @"SELECT ( - SELECT COALESCE(SUM([e0].[Id]), 0) - FROM [EntityOneEntityTwo] AS [e] - INNER JOIN [EntityOnes] AS [e0] ON [e].[EntityOneId] = [e0].[Id] - WHERE [e1].[Id] = [e].[EntityTwoId]) -FROM [EntityTwos] AS [e1]"); + SELECT COALESCE(SUM([e1].[Id]), 0) + FROM [EntityOneEntityTwo] AS [e0] + INNER JOIN [EntityOnes] AS [e1] ON [e0].[EntityOneId] = [e1].[Id] + WHERE [e].[Id] = [e0].[EntityTwoId]) +FROM [EntityTwos] AS [e]"); } public override async Task Skip_navigation_order_by_first_or_default(bool async) @@ -936,7 +936,7 @@ public override async Task Filter_include_on_skip_navigation_combined_with_filte @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId], [t3].[Id], [t3].[Name], [t3].[OneId], [t3].[ThreeId], [t3].[Id0], [t3].[CollectionInverseId], [t3].[Name0], [t3].[ReferenceInverseId], [t3].[OneId0], [t3].[TwoId], [t3].[Id1], [t3].[Name1], [t3].[Number], [t3].[IsGreen], [t3].[Discriminator], [t3].[EntityBranchId], [t3].[EntityOneId] FROM [EntityThrees] AS [e] LEFT JOIN ( - SELECT [e0].[Id], [e0].[Name], [j].[OneId], [j].[ThreeId], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t0].[OneId] AS [OneId0], [t0].[TwoId], [t2].[Id] AS [Id1], [t2].[Name] AS [Name1], [t2].[Number], [t2].[IsGreen], [t2].[Discriminator], [t2].[EntityBranchId], [t2].[EntityOneId] + SELECT [e0].[Id], [e0].[Name], [j].[OneId], [j].[ThreeId], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t0].[OneId] AS [OneId0], [t0].[TwoId], [t1].[Id] AS [Id1], [t1].[Name] AS [Name1], [t1].[Number], [t1].[IsGreen], [t1].[Discriminator], [t1].[EntityBranchId], [t1].[EntityOneId] FROM [JoinOneToThreePayloadFull] AS [j] INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] LEFT JOIN ( @@ -949,7 +949,7 @@ FROM [JoinOneToTwo] AS [j0] WHERE (1 < [t].[row]) AND ([t].[row] <= 3) ) AS [t0] ON [e0].[Id] = [t0].[OneId] LEFT JOIN ( - SELECT [t1].[Id], [t1].[Name], [t1].[Number], [t1].[IsGreen], [t1].[Discriminator], [j1].[EntityBranchId], [j1].[EntityOneId] + SELECT [t2].[Id], [t2].[Name], [t2].[Number], [t2].[IsGreen], [t2].[Discriminator], [j1].[EntityBranchId], [j1].[EntityOneId] FROM [JoinOneToBranch] AS [j1] INNER JOIN ( SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE @@ -958,9 +958,9 @@ END AS [Discriminator] FROM [Roots] AS [r] INNER JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] - ) AS [t1] ON [j1].[EntityBranchId] = [t1].[Id] - WHERE [t1].[Id] < 20 - ) AS [t2] ON [e0].[Id] = [t2].[EntityOneId] + ) AS [t2] ON [j1].[EntityBranchId] = [t2].[Id] + WHERE [t2].[Id] < 20 + ) AS [t1] ON [e0].[Id] = [t1].[EntityOneId] WHERE [e0].[Id] < 10 ) AS [t3] ON [e].[Id] = [t3].[ThreeId] ORDER BY [e].[Id], [t3].[OneId], [t3].[ThreeId], [t3].[Id], [t3].[OneId0], [t3].[Id0], [t3].[TwoId], [t3].[EntityBranchId], [t3].[EntityOneId], [t3].[Id1]"); @@ -1342,7 +1342,7 @@ INNER JOIN [EntityCompositeKeys] AS [e] ON (([j].[CompositeId1] = [e].[Key1]) AN ) AS [t] ON [r].[Id] = [t].[RootId] ORDER BY [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3]", // - @"SELECT [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3] + @"SELECT [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3] FROM [Roots] AS [r] INNER JOIN ( SELECT [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3], [j].[RootId], [e].[Key1], [e].[Key2], [e].[Key3] @@ -1350,15 +1350,15 @@ FROM [JoinCompositeKeyToRootShared] AS [j] INNER JOIN [EntityCompositeKeys] AS [e] ON (([j].[CompositeId1] = [e].[Key1]) AND ([j].[CompositeId2] = [e].[Key2])) AND ([j].[CompositeId3] = [e].[Key3]) ) AS [t] ON [r].[Id] = [t].[RootId] INNER JOIN ( - SELECT [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[CompositeId1], [j0].[CompositeId2], [j0].[CompositeId3], [e0].[Id] AS [Id0], [e0].[CollectionInverseId], [e0].[Name], [e0].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[CompositeId1], [j0].[CompositeId2], [j0].[CompositeId3] ORDER BY [e0].[Id]) AS [row] FROM [JoinThreeToCompositeKeyFull] AS [j0] INNER JOIN [EntityThrees] AS [e0] ON [j0].[ThreeId] = [e0].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON (([t].[Key1] = [t1].[CompositeId1]) AND ([t].[Key2] = [t1].[CompositeId2])) AND ([t].[Key3] = [t1].[CompositeId3]) -ORDER BY [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id0]"); + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON (([t].[Key1] = [t0].[CompositeId1]) AND ([t].[Key2] = [t0].[CompositeId2])) AND ([t].[Key3] = [t0].[CompositeId3]) +ORDER BY [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0]"); } public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_split(bool async) @@ -1463,7 +1463,7 @@ WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id]", // - @"SELECT [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [e0].[Id] @@ -1472,15 +1472,15 @@ FROM [JoinOneToTwo] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] INNER JOIN ( - SELECT [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[TwoId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[TwoId] ORDER BY [e1].[Id]) AS [row] FROM [JoinTwoToThree] AS [j0] INNER JOIN [EntityThrees] AS [e1] ON [j0].[ThreeId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON [t].[Id] = [t1].[TwoId] -ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t1].[TwoId], [t1].[Id]"); + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON [t].[Id] = [t0].[TwoId] +ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t0].[TwoId], [t0].[Id]"); } public override async Task Filter_include_on_skip_navigation_combined_split(bool async) @@ -1535,7 +1535,7 @@ WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]", // - @"SELECT [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1544,17 +1544,17 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] INNER JOIN ( - SELECT [t0].[OneId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[OneId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[OneId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[OneId] ORDER BY [e1].[Id]) AS [row] FROM [JoinOneToTwo] AS [j0] INNER JOIN [EntityTwos] AS [e1] ON [j0].[TwoId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON [t].[Id] = [t1].[OneId] -ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t1].[OneId], [t1].[Id]", + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON [t].[Id] = [t0].[OneId] +ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t0].[OneId], [t0].[Id]", // - @"SELECT [t1].[Id], [t1].[Name], [t1].[Number], [t1].[IsGreen], [t1].[Discriminator], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1563,7 +1563,7 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] INNER JOIN ( - SELECT [j0].[EntityOneId], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator] + SELECT [j0].[EntityOneId], [t1].[Id], [t1].[Name], [t1].[Number], [t1].[IsGreen], [t1].[Discriminator] FROM [JoinOneToBranch] AS [j0] INNER JOIN ( SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE @@ -1572,9 +1572,9 @@ END AS [Discriminator] FROM [Roots] AS [r] INNER JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] - ) AS [t0] ON [j0].[EntityBranchId] = [t0].[Id] - WHERE [t0].[Id] < 20 -) AS [t1] ON [t].[Id] = [t1].[EntityOneId] + ) AS [t1] ON [j0].[EntityBranchId] = [t1].[Id] + WHERE [t1].[Id] < 20 +) AS [t0] ON [t].[Id] = [t0].[EntityOneId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs index 5f4b1e27d74..8e62f865aa8 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs @@ -217,11 +217,11 @@ public override async Task Skip_navigation_select_subquery_max(bool async) AssertSql( @"SELECT ( - SELECT MAX([e].[Id]) + SELECT MAX([e0].[Id]) FROM [JoinOneToTwo] AS [j] - INNER JOIN [EntityOnes] AS [e] ON [j].[OneId] = [e].[Id] - WHERE [e0].[Id] = [j].[TwoId]) -FROM [EntityTwos] AS [e0]"); + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e].[Id] = [j].[TwoId]) +FROM [EntityTwos] AS [e]"); } public override async Task Skip_navigation_select_subquery_min(bool async) @@ -230,11 +230,11 @@ public override async Task Skip_navigation_select_subquery_min(bool async) AssertSql( @"SELECT ( - SELECT MIN([e].[Id]) + SELECT MIN([e0].[Id]) FROM [JoinOneToThreePayloadFull] AS [j] - INNER JOIN [EntityOnes] AS [e] ON [j].[OneId] = [e].[Id] - WHERE [e0].[Id] = [j].[ThreeId]) -FROM [EntityThrees] AS [e0]"); + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e].[Id] = [j].[ThreeId]) +FROM [EntityThrees] AS [e]"); } public override async Task Skip_navigation_select_subquery_sum(bool async) @@ -243,11 +243,11 @@ public override async Task Skip_navigation_select_subquery_sum(bool async) AssertSql( @"SELECT ( - SELECT COALESCE(SUM([e0].[Id]), 0) - FROM [EntityOneEntityTwo] AS [e] - INNER JOIN [EntityOnes] AS [e0] ON [e].[EntityOneId] = [e0].[Id] - WHERE [e1].[Id] = [e].[EntityTwoId]) -FROM [EntityTwos] AS [e1]"); + SELECT COALESCE(SUM([e1].[Id]), 0) + FROM [EntityOneEntityTwo] AS [e0] + INNER JOIN [EntityOnes] AS [e1] ON [e0].[EntityOneId] = [e1].[Id] + WHERE [e].[Id] = [e0].[EntityTwoId]) +FROM [EntityTwos] AS [e]"); } public override async Task Skip_navigation_order_by_first_or_default(bool async) @@ -935,7 +935,7 @@ public override async Task Filter_include_on_skip_navigation_combined_with_filte @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId], [t3].[OneId], [t3].[ThreeId], [t3].[Payload], [t3].[Id], [t3].[Name], [t3].[OneId0], [t3].[TwoId], [t3].[Id0], [t3].[CollectionInverseId], [t3].[Name0], [t3].[ReferenceInverseId], [t3].[EntityBranchId], [t3].[EntityOneId], [t3].[Id1], [t3].[Name1], [t3].[Number], [t3].[IsGreen], [t3].[Discriminator] FROM [EntityThrees] AS [e] LEFT JOIN ( - SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name], [t0].[OneId] AS [OneId0], [t0].[TwoId], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t2].[EntityBranchId], [t2].[EntityOneId], [t2].[Id] AS [Id1], [t2].[Name] AS [Name1], [t2].[Number], [t2].[IsGreen], [t2].[Discriminator] + SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name], [t0].[OneId] AS [OneId0], [t0].[TwoId], [t0].[Id] AS [Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t1].[EntityBranchId], [t1].[EntityOneId], [t1].[Id] AS [Id1], [t1].[Name] AS [Name1], [t1].[Number], [t1].[IsGreen], [t1].[Discriminator] FROM [JoinOneToThreePayloadFull] AS [j] INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] LEFT JOIN ( @@ -948,7 +948,7 @@ FROM [JoinOneToTwo] AS [j0] WHERE (1 < [t].[row]) AND ([t].[row] <= 3) ) AS [t0] ON [e0].[Id] = [t0].[OneId] LEFT JOIN ( - SELECT [j1].[EntityBranchId], [j1].[EntityOneId], [t1].[Id], [t1].[Name], [t1].[Number], [t1].[IsGreen], [t1].[Discriminator] + SELECT [j1].[EntityBranchId], [j1].[EntityOneId], [t2].[Id], [t2].[Name], [t2].[Number], [t2].[IsGreen], [t2].[Discriminator] FROM [JoinOneToBranch] AS [j1] INNER JOIN ( SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE @@ -957,9 +957,9 @@ END AS [Discriminator] FROM [Roots] AS [r] INNER JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] - ) AS [t1] ON [j1].[EntityBranchId] = [t1].[Id] - WHERE [t1].[Id] < 20 - ) AS [t2] ON [e0].[Id] = [t2].[EntityOneId] + ) AS [t2] ON [j1].[EntityBranchId] = [t2].[Id] + WHERE [t2].[Id] < 20 + ) AS [t1] ON [e0].[Id] = [t1].[EntityOneId] WHERE [e0].[Id] < 10 ) AS [t3] ON [e].[Id] = [t3].[ThreeId] ORDER BY [e].[Id], [t3].[OneId], [t3].[ThreeId], [t3].[Id], [t3].[OneId0], [t3].[Id0], [t3].[TwoId], [t3].[EntityBranchId], [t3].[EntityOneId], [t3].[Id1]"); @@ -1341,7 +1341,7 @@ INNER JOIN [EntityCompositeKeys] AS [e] ON (([j].[CompositeId1] = [e].[Key1]) AN ) AS [t] ON [r].[Id] = [t].[RootId] ORDER BY [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3]", // - @"SELECT [t1].[Id], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[ThreeId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3] + @"SELECT [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3] FROM [Roots] AS [r] INNER JOIN ( SELECT [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3], [j].[RootId], [e].[Key1], [e].[Key2], [e].[Key3] @@ -1349,15 +1349,15 @@ FROM [JoinCompositeKeyToRootShared] AS [j] INNER JOIN [EntityCompositeKeys] AS [e] ON (([j].[CompositeId1] = [e].[Key1]) AND ([j].[CompositeId2] = [e].[Key2])) AND ([j].[CompositeId3] = [e].[Key3]) ) AS [t] ON [r].[Id] = [t].[RootId] INNER JOIN ( - SELECT [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[Id], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[ThreeId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[Id], [j0].[CompositeId1], [j0].[CompositeId2], [j0].[CompositeId3], [j0].[ThreeId], [e0].[Id] AS [Id0], [e0].[CollectionInverseId], [e0].[Name], [e0].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[CompositeId1], [j0].[CompositeId2], [j0].[CompositeId3] ORDER BY [e0].[Id]) AS [row] FROM [JoinThreeToCompositeKeyFull] AS [j0] INNER JOIN [EntityThrees] AS [e0] ON [j0].[ThreeId] = [e0].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON (([t].[Key1] = [t1].[CompositeId1]) AND ([t].[Key2] = [t1].[CompositeId2])) AND ([t].[Key3] = [t1].[CompositeId3]) -ORDER BY [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id0]"); + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON (([t].[Key1] = [t0].[CompositeId1]) AND ([t].[Key2] = [t0].[CompositeId2])) AND ([t].[Key3] = [t0].[CompositeId3]) +ORDER BY [r].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[RootId], [t].[Key1], [t].[Key2], [t].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0]"); } public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_split(bool async) @@ -1462,7 +1462,7 @@ WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id]", // - @"SELECT [t1].[ThreeId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] + @"SELECT [t0].[ThreeId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [e0].[Id] @@ -1471,15 +1471,15 @@ FROM [JoinOneToTwo] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] INNER JOIN ( - SELECT [t0].[ThreeId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[ThreeId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[ThreeId], [j0].[TwoId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[TwoId] ORDER BY [e1].[Id]) AS [row] FROM [JoinTwoToThree] AS [j0] INNER JOIN [EntityThrees] AS [e1] ON [j0].[ThreeId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON [t].[Id] = [t1].[TwoId] -ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t1].[TwoId], [t1].[Id]"); + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON [t].[Id] = [t0].[TwoId] +ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t0].[TwoId], [t0].[Id]"); } public override async Task Filter_include_on_skip_navigation_combined_split(bool async) @@ -1534,7 +1534,7 @@ WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]", // - @"SELECT [t1].[OneId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + @"SELECT [t0].[OneId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1543,17 +1543,17 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] INNER JOIN ( - SELECT [t0].[OneId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] + SELECT [t1].[OneId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId] FROM ( SELECT [j0].[OneId], [j0].[TwoId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [j0].[OneId] ORDER BY [e1].[Id]) AS [row] FROM [JoinOneToTwo] AS [j0] INNER JOIN [EntityTwos] AS [e1] ON [j0].[TwoId] = [e1].[Id] - ) AS [t0] - WHERE (1 < [t0].[row]) AND ([t0].[row] <= 3) -) AS [t1] ON [t].[Id] = [t1].[OneId] -ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t1].[OneId], [t1].[Id]", + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 3) +) AS [t0] ON [t].[Id] = [t0].[OneId] +ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t0].[OneId], [t0].[Id]", // - @"SELECT [t1].[EntityBranchId], [t1].[EntityOneId], [t1].[Id], [t1].[Name], [t1].[Number], [t1].[IsGreen], [t1].[Discriminator], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + @"SELECT [t0].[EntityBranchId], [t0].[EntityOneId], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1562,7 +1562,7 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] INNER JOIN ( - SELECT [j0].[EntityBranchId], [j0].[EntityOneId], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator] + SELECT [j0].[EntityBranchId], [j0].[EntityOneId], [t1].[Id], [t1].[Name], [t1].[Number], [t1].[IsGreen], [t1].[Discriminator] FROM [JoinOneToBranch] AS [j0] INNER JOIN ( SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE @@ -1571,9 +1571,9 @@ END AS [Discriminator] FROM [Roots] AS [r] INNER JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] - ) AS [t0] ON [j0].[EntityBranchId] = [t0].[Id] - WHERE [t0].[Id] < 20 -) AS [t1] ON [t].[Id] = [t1].[EntityOneId] + ) AS [t1] ON [j0].[EntityBranchId] = [t1].[Id] + WHERE [t1].[Id] < 20 +) AS [t0] ON [t].[Id] = [t0].[EntityOneId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs index 8a126279dbf..a0dcdf2c10a 100644 --- a/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/TPTTableSplittingSqlServerTest.cs @@ -25,7 +25,7 @@ public override async Task Can_use_with_redundant_relationships() @"SELECT [v].[Name], [v].[SeatingCapacity], [c].[AttachedVehicleName], CASE WHEN [c].[Name] IS NOT NULL THEN N'CompositeVehicle' WHEN [p].[Name] IS NOT NULL THEN N'PoweredVehicle' -END AS [Discriminator], [t0].[Name], [t0].[Operator_Name], [t0].[LicenseType], [t0].[Discriminator], [t3].[Name], [t3].[Type], [t5].[Name], [t5].[Computed], [t5].[Description], [t5].[Discriminator], [t7].[VehicleName], [t7].[Capacity], [t7].[FuelType], [t7].[GrainGeometry], [t7].[Discriminator] +END AS [Discriminator], [t0].[Name], [t0].[Operator_Name], [t0].[LicenseType], [t0].[Discriminator], [t1].[Name], [t1].[Type], [t4].[Name], [t4].[Computed], [t4].[Description], [t4].[Discriminator], [t6].[VehicleName], [t6].[Capacity], [t6].[FuelType], [t6].[GrainGeometry], [t6].[Discriminator] FROM [Vehicles] AS [v] LEFT JOIN [PoweredVehicles] AS [p] ON [v].[Name] = [p].[Name] LEFT JOIN [CompositeVehicles] AS [c] ON [v].[Name] = [c].[Name] @@ -49,10 +49,10 @@ FROM [Vehicles] AS [v3] INNER JOIN ( SELECT [v4].[Name] FROM [Vehicles] AS [v4] - ) AS [t1] ON [v3].[Name] = [t1].[Name] + ) AS [t3] ON [v3].[Name] = [t3].[Name] ) AS [t2] ON [v2].[Name] = [t2].[Name] WHERE [v2].[Type] IS NOT NULL -) AS [t3] ON [t0].[Name] = [t3].[Name] +) AS [t1] ON [t0].[Name] = [t1].[Name] LEFT JOIN ( SELECT [p2].[Name], [p2].[Computed], [p2].[Description], CASE WHEN [s].[VehicleName] IS NOT NULL THEN N'SolidRocket' @@ -67,9 +67,9 @@ INNER JOIN ( SELECT [v5].[Name] FROM [Vehicles] AS [v5] INNER JOIN [PoweredVehicles] AS [p3] ON [v5].[Name] = [p3].[Name] - ) AS [t4] ON [p2].[Name] = [t4].[Name] + ) AS [t5] ON [p2].[Name] = [t5].[Name] WHERE [p2].[Computed] IS NOT NULL -) AS [t5] ON [v].[Name] = [t5].[Name] +) AS [t4] ON [v].[Name] = [t4].[Name] LEFT JOIN ( SELECT [c5].[VehicleName], [c5].[Capacity], [c5].[FuelType], [s0].[GrainGeometry], CASE WHEN [s0].[VehicleName] IS NOT NULL THEN N'SolidFuelTank' @@ -80,9 +80,9 @@ INNER JOIN ( SELECT [p4].[Name] FROM [PoweredVehicles] AS [p4] INNER JOIN [CombustionEngines] AS [c6] ON [p4].[Name] = [c6].[VehicleName] - ) AS [t6] ON [c5].[VehicleName] = [t6].[Name] + ) AS [t7] ON [c5].[VehicleName] = [t7].[Name] WHERE [c5].[FuelType] IS NOT NULL OR [c5].[Capacity] IS NOT NULL -) AS [t7] ON [t5].[Name] = [t7].[VehicleName] +) AS [t6] ON [t4].[Name] = [t6].[VehicleName] ORDER BY [v].[Name]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/TableSplittingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/TableSplittingSqlServerTest.cs index 975faf955ae..9a0a4c58f9c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/TableSplittingSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/TableSplittingSqlServerTest.cs @@ -24,7 +24,7 @@ public override async Task Can_use_with_redundant_relationships() // TODO: [Name] shouldn't be selected multiple times and no joins are needed AssertSql( - @"SELECT [v].[Name], [v].[Discriminator], [v].[SeatingCapacity], [v].[AttachedVehicleName], [t].[Name], [t].[Operator_Discriminator], [t].[Operator_Name], [t].[LicenseType], [t1].[Name], [t1].[Type], [t3].[Name], [t3].[Computed], [t3].[Description], [t3].[Engine_Discriminator], [t7].[Name], [t7].[Capacity], [t7].[FuelTank_Discriminator], [t7].[FuelType], [t7].[GrainGeometry] + @"SELECT [v].[Name], [v].[Discriminator], [v].[SeatingCapacity], [v].[AttachedVehicleName], [t].[Name], [t].[Operator_Discriminator], [t].[Operator_Name], [t].[LicenseType], [t0].[Name], [t0].[Type], [t2].[Name], [t2].[Computed], [t2].[Description], [t2].[Engine_Discriminator], [t4].[Name], [t4].[Capacity], [t4].[FuelTank_Discriminator], [t4].[FuelType], [t4].[GrainGeometry] FROM [Vehicles] AS [v] LEFT JOIN ( SELECT [v0].[Name], [v0].[Operator_Discriminator], [v0].[Operator_Name], [v0].[LicenseType] @@ -38,9 +38,9 @@ INNER JOIN ( SELECT [v3].[Name] FROM [Vehicles] AS [v3] INNER JOIN [Vehicles] AS [v4] ON [v3].[Name] = [v4].[Name] - ) AS [t0] ON [v2].[Name] = [t0].[Name] + ) AS [t1] ON [v2].[Name] = [t1].[Name] WHERE [v2].[Type] IS NOT NULL -) AS [t1] ON [t].[Name] = [t1].[Name] +) AS [t0] ON [t].[Name] = [t0].[Name] LEFT JOIN ( SELECT [v5].[Name], [v5].[Computed], [v5].[Description], [v5].[Engine_Discriminator] FROM [Vehicles] AS [v5] @@ -48,9 +48,9 @@ INNER JOIN ( SELECT [v6].[Name] FROM [Vehicles] AS [v6] WHERE [v6].[Discriminator] IN (N'PoweredVehicle', N'CompositeVehicle') - ) AS [t2] ON [v5].[Name] = [t2].[Name] + ) AS [t3] ON [v5].[Name] = [t3].[Name] WHERE [v5].[Engine_Discriminator] IS NOT NULL AND [v5].[Computed] IS NOT NULL -) AS [t3] ON [v].[Name] = [t3].[Name] +) AS [t2] ON [v].[Name] = [t2].[Name] LEFT JOIN ( SELECT [v7].[Name], [v7].[Capacity], [v7].[FuelTank_Discriminator], [v7].[FuelType], [v7].[GrainGeometry] FROM [Vehicles] AS [v7] @@ -58,23 +58,23 @@ INNER JOIN ( SELECT [v8].[Name], [v8].[Discriminator], [v8].[SeatingCapacity], [v8].[AttachedVehicleName] FROM [Vehicles] AS [v8] WHERE [v8].[Discriminator] IN (N'PoweredVehicle', N'CompositeVehicle') - ) AS [t4] ON [v7].[Name] = [t4].[Name] + ) AS [t5] ON [v7].[Name] = [t5].[Name] WHERE [v7].[FuelTank_Discriminator] IS NOT NULL UNION SELECT [v9].[Name], [v9].[Capacity], [v9].[FuelTank_Discriminator], [v9].[FuelType], [v9].[GrainGeometry] FROM [Vehicles] AS [v9] INNER JOIN ( - SELECT [v10].[Name], [v10].[Computed], [v10].[Description], [v10].[Engine_Discriminator], [t5].[Name] AS [Name0] + SELECT [v10].[Name], [v10].[Computed], [v10].[Description], [v10].[Engine_Discriminator], [t7].[Name] AS [Name0] FROM [Vehicles] AS [v10] INNER JOIN ( SELECT [v11].[Name], [v11].[Discriminator], [v11].[SeatingCapacity], [v11].[AttachedVehicleName] FROM [Vehicles] AS [v11] WHERE [v11].[Discriminator] IN (N'PoweredVehicle', N'CompositeVehicle') - ) AS [t5] ON [v10].[Name] = [t5].[Name] + ) AS [t7] ON [v10].[Name] = [t7].[Name] WHERE [v10].[Engine_Discriminator] IN (N'ContinuousCombustionEngine', N'IntermittentCombustionEngine', N'SolidRocket') ) AS [t6] ON [v9].[Name] = [t6].[Name] WHERE [v9].[FuelTank_Discriminator] IS NOT NULL -) AS [t7] ON [t3].[Name] = [t7].[Name] +) AS [t4] ON [t2].[Name] = [t4].[Name] ORDER BY [v].[Name]"); } @@ -125,15 +125,15 @@ WHERE [v].[FuelTank_Discriminator] IS NOT NULL SELECT [v1].[Name], [v1].[Capacity], [v1].[FuelTank_Discriminator], [v1].[FuelType], [v1].[GrainGeometry] FROM [Vehicles] AS [v1] INNER JOIN ( - SELECT [v2].[Name], [v2].[Computed], [v2].[Description], [v2].[Engine_Discriminator], [t0].[Name] AS [Name0] + SELECT [v2].[Name], [v2].[Computed], [v2].[Description], [v2].[Engine_Discriminator], [t1].[Name] AS [Name0] FROM [Vehicles] AS [v2] INNER JOIN ( SELECT [v3].[Name], [v3].[Discriminator], [v3].[SeatingCapacity], [v3].[AttachedVehicleName] FROM [Vehicles] AS [v3] WHERE [v3].[Discriminator] IN (N'PoweredVehicle', N'CompositeVehicle') - ) AS [t0] ON [v2].[Name] = [t0].[Name] + ) AS [t1] ON [v2].[Name] = [t1].[Name] WHERE [v2].[Engine_Discriminator] IN (N'ContinuousCombustionEngine', N'IntermittentCombustionEngine', N'SolidRocket') -) AS [t1] ON [v1].[Name] = [t1].[Name] +) AS [t0] ON [v1].[Name] = [t0].[Name] WHERE [v1].[FuelTank_Discriminator] IS NOT NULL"); } @@ -154,15 +154,15 @@ WHERE [v].[FuelType] IS NOT NULL OR [v].[Capacity] IS NOT NULL SELECT [v1].[Name], [v1].[Capacity], [v1].[FuelType] FROM [Vehicles] AS [v1] INNER JOIN ( - SELECT [v2].[Name], [v2].[Computed], [v2].[Description], [v2].[Engine_Discriminator], [t0].[Name] AS [Name0] + SELECT [v2].[Name], [v2].[Computed], [v2].[Description], [v2].[Engine_Discriminator], [t1].[Name] AS [Name0] FROM [Vehicles] AS [v2] INNER JOIN ( SELECT [v3].[Name], [v3].[Discriminator], [v3].[SeatingCapacity], [v3].[AttachedVehicleName] FROM [Vehicles] AS [v3] WHERE [v3].[Discriminator] IN (N'PoweredVehicle', N'CompositeVehicle') - ) AS [t0] ON [v2].[Name] = [t0].[Name] + ) AS [t1] ON [v2].[Name] = [t1].[Name] WHERE [v2].[Engine_Discriminator] IN (N'ContinuousCombustionEngine', N'IntermittentCombustionEngine', N'SolidRocket') -) AS [t1] ON [v1].[Name] = [t1].[Name] +) AS [t0] ON [v1].[Name] = [t0].[Name] WHERE [v1].[FuelType] IS NOT NULL OR [v1].[Capacity] IS NOT NULL"); } @@ -183,15 +183,15 @@ WHERE [v].[FuelType] IS NOT NULL AND [v].[Capacity] IS NOT NULL SELECT [v1].[Name], [v1].[Capacity], [v1].[FuelType] FROM [Vehicles] AS [v1] INNER JOIN ( - SELECT [v2].[Name], [v2].[Computed], [v2].[Description], [v2].[Engine_Discriminator], [t0].[Name] AS [Name0] + SELECT [v2].[Name], [v2].[Computed], [v2].[Description], [v2].[Engine_Discriminator], [t1].[Name] AS [Name0] FROM [Vehicles] AS [v2] INNER JOIN ( SELECT [v3].[Name], [v3].[Discriminator], [v3].[SeatingCapacity], [v3].[AttachedVehicleName] FROM [Vehicles] AS [v3] WHERE [v3].[Discriminator] IN (N'PoweredVehicle', N'CompositeVehicle') - ) AS [t0] ON [v2].[Name] = [t0].[Name] + ) AS [t1] ON [v2].[Name] = [t1].[Name] WHERE [v2].[Engine_Discriminator] IN (N'ContinuousCombustionEngine', N'IntermittentCombustionEngine', N'SolidRocket') -) AS [t1] ON [v1].[Name] = [t1].[Name] +) AS [t0] ON [v1].[Name] = [t0].[Name] WHERE [v1].[FuelType] IS NOT NULL AND [v1].[Capacity] IS NOT NULL"); } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/SpatialQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/SpatialQuerySqliteTest.cs index 7b4b702f28d..aaa7a8d69cd 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/SpatialQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/SpatialQuerySqliteTest.cs @@ -416,11 +416,11 @@ public override async Task GetGeometryN_with_null_argument(bool async) await base.GetGeometryN_with_null_argument(async); AssertSql( - @"SELECT ""m0"".""Id"", GeometryN(""m0"".""MultiLineString"", ( - SELECT MAX(""m"".""Id"") - FROM ""MultiLineStringEntity"" AS ""m"" + @"SELECT ""m"".""Id"", GeometryN(""m"".""MultiLineString"", ( + SELECT MAX(""m0"".""Id"") + FROM ""MultiLineStringEntity"" AS ""m0"" WHERE 0) + 1) AS ""Geometry0"" -FROM ""MultiLineStringEntity"" AS ""m0"""); +FROM ""MultiLineStringEntity"" AS ""m"""); } public override async Task GetInteriorRingN(bool async)