diff --git a/src/EFCore.Relational/Query/Pipeline/AsyncQueryingEnumerable.cs b/src/EFCore.Relational/Query/Pipeline/AsyncQueryingEnumerable.cs index f347778fb19..4cd1ef79f98 100644 --- a/src/EFCore.Relational/Query/Pipeline/AsyncQueryingEnumerable.cs +++ b/src/EFCore.Relational/Query/Pipeline/AsyncQueryingEnumerable.cs @@ -20,7 +20,7 @@ private class AsyncQueryingEnumerable : IAsyncEnumerable { private readonly RelationalQueryContext _relationalQueryContext; private readonly SelectExpression _selectExpression; - private readonly Func _shaper; + private readonly Func _shaper; private readonly IQuerySqlGeneratorFactory _querySqlGeneratorFactory; private readonly Type _contextType; private readonly IDiagnosticsLogger _logger; @@ -33,7 +33,7 @@ public AsyncQueryingEnumerable( ISqlExpressionFactory sqlExpressionFactory, IParameterNameGeneratorFactory parameterNameGeneratorFactory, SelectExpression selectExpression, - Func shaper, + Func shaper, Type contextType, IDiagnosticsLogger logger) { @@ -57,7 +57,7 @@ private sealed class AsyncEnumerator : IAsyncEnumerator private ResultCoordinator _resultCoordinator; private readonly RelationalQueryContext _relationalQueryContext; private readonly SelectExpression _selectExpression; - private readonly Func _shaper; + private readonly Func _shaper; private readonly IQuerySqlGeneratorFactory _querySqlGeneratorFactory; private readonly Type _contextType; private readonly IDiagnosticsLogger _logger; @@ -136,13 +136,29 @@ public async ValueTask MoveNextAsync() _resultCoordinator = new ResultCoordinator(); } - var hasNext = _resultCoordinator.HasNext ?? await _dataReader.ReadAsync(_cancellationToken); - _resultCoordinator.HasNext = null; + var hasNext = _resultCoordinator.HasNext ?? await _dataReader.ReadAsync(); + Current = default; - Current - = hasNext - ? _shaper(_relationalQueryContext, _dataReader.DbDataReader, _indexMap, _resultCoordinator) - : default; + if (hasNext) + { + while (true) + { + _resultCoordinator.ResultReady = true; + _resultCoordinator.HasNext = null; + Current = _shaper(_relationalQueryContext, _dataReader.DbDataReader, Current, _indexMap, _resultCoordinator); + if (_resultCoordinator.ResultReady) + { + break; + } + + if (!await _dataReader.ReadAsync()) + { + _resultCoordinator.HasNext = false; + + break; + } + } + } return hasNext; } diff --git a/src/EFCore.Relational/Query/Pipeline/IncludeCompilingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/IncludeCompilingExpressionVisitor.cs index 31d3e798278..6cb4d1589c0 100644 --- a/src/EFCore.Relational/Query/Pipeline/IncludeCompilingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/IncludeCompilingExpressionVisitor.cs @@ -4,7 +4,9 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Data.Common; +using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -20,13 +22,13 @@ namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline { public partial class RelationalShapedQueryCompilingExpressionVisitor { - private class IncludeCompilingExpressionVisitor : ExpressionVisitor + private class CollectionMaterializingExpressionVisitor : ExpressionVisitor { private readonly ParameterExpression _dbDataReaderParameter; private readonly ParameterExpression _resultCoordinatorParameter; private readonly bool _tracking; - public IncludeCompilingExpressionVisitor( + public CollectionMaterializingExpressionVisitor( ParameterExpression dbDataReaderParameter, ParameterExpression resultCoordinatorParameter, bool tracking) @@ -37,26 +39,22 @@ public IncludeCompilingExpressionVisitor( } private static readonly MethodInfo _includeReferenceMethodInfo - = typeof(IncludeCompilingExpressionVisitor).GetTypeInfo() + = typeof(CollectionMaterializingExpressionVisitor).GetTypeInfo() .GetDeclaredMethod(nameof(IncludeReference)); private static void IncludeReference( QueryContext queryContext, - DbDataReader dbDataReader, TEntity entity, - Func innerShaper, + TIncludedEntity relatedEntity, INavigation navigation, INavigation inverseNavigation, Action fixup, - bool trackingQuery, - ResultCoordinator resultCoordinator) + bool trackingQuery) { - var relatedEntity = innerShaper(queryContext, dbDataReader, resultCoordinator); - if (trackingQuery) { // For non-null relatedEntity StateManager will set the flag - if (ReferenceEquals(relatedEntity, null)) + if (relatedEntity == null) { queryContext.StateManager.TryGetEntry(entity).SetIsLoaded(navigation); } @@ -64,7 +62,7 @@ private static void IncludeReference( else { SetIsLoadedNoTracking(entity, navigation); - if (!ReferenceEquals(relatedEntity, null)) + if (relatedEntity is object) { fixup(entity, relatedEntity); if (inverseNavigation != null && !inverseNavigation.IsCollection()) @@ -75,44 +73,57 @@ private static void IncludeReference( } } - private static readonly MethodInfo _includeCollectionMethodInfo - = typeof(IncludeCompilingExpressionVisitor).GetTypeInfo() - .GetDeclaredMethod(nameof(IncludeCollection)); + private static readonly MethodInfo _populateCollectionMethodInfo + = typeof(CollectionMaterializingExpressionVisitor).GetTypeInfo() + .GetDeclaredMethod(nameof(PopulateCollection)); - private static void IncludeCollection( + private static void PopulateCollection( + int collectionId, QueryContext queryContext, DbDataReader dbDataReader, - TEntity entity, - Func outerKeySelector, - Func innerKeySelector, - Func innerShaper, - INavigation navigation, + Func outerIdentifier, + Func selfIdentifier, + Func innerShaper, INavigation inverseNavigation, Action fixup, bool trackingQuery, ResultCoordinator resultCoordinator) { + var collectionMaterializationContext = resultCoordinator.Collections[collectionId]; + + var entity = (TEntity)collectionMaterializationContext.Parent; if (entity is null) { + // non-include case return; } - if (trackingQuery) + var outerKey = outerIdentifier(queryContext, dbDataReader); + if (!StructuralComparisons.StructuralEqualityComparer.Equals( + outerKey, collectionMaterializationContext.OuterIdentifier)) { - queryContext.StateManager.TryGetEntry(entity).SetIsLoaded(navigation); + resultCoordinator.HasNext = true; + + return; + } + + var innerKey = selfIdentifier(queryContext, dbDataReader); + TIncludedEntity current; + if (StructuralComparisons.StructuralEqualityComparer.Equals( + innerKey, collectionMaterializationContext.SelfIdentifier)) + { + current = (TIncludedEntity)collectionMaterializationContext.Current; } else { - SetIsLoadedNoTracking(entity, navigation); + current = default; + collectionMaterializationContext.SelfIdentifier = innerKey; } - var innerKey = innerKeySelector(queryContext, dbDataReader); - var outerKey = outerKeySelector(queryContext, dbDataReader); - var relatedEntity = innerShaper(queryContext, dbDataReader, resultCoordinator); - - if (ReferenceEquals(relatedEntity, null)) + var relatedEntity = innerShaper(queryContext, dbDataReader, current, resultCoordinator); + collectionMaterializationContext.UpdateCurrent(relatedEntity); + if (relatedEntity is null) { - navigation.GetCollectionAccessor().GetOrCreate(entity); return; } @@ -125,37 +136,51 @@ private static void IncludeCollection( } } - var hasNext = resultCoordinator.HasNext ?? dbDataReader.Read(); - while (hasNext) - { - resultCoordinator.HasNext = null; - var currentOuterKey = outerKeySelector(queryContext, dbDataReader); - if (!StructuralComparisons.StructuralEqualityComparer.Equals(outerKey, currentOuterKey)) - { - resultCoordinator.HasNext = true; - break; - } + resultCoordinator.ResultReady = false; + } + + private static readonly MethodInfo _initializeCollectionIncludeMethodInfo + = typeof(CollectionMaterializingExpressionVisitor).GetTypeInfo() + .GetDeclaredMethod(nameof(InitializeCollectionInclude)); - var currentInnerKey = innerKeySelector(queryContext, dbDataReader); - if (StructuralComparisons.StructuralEqualityComparer.Equals(innerKey, currentInnerKey)) + private static void InitializeCollectionInclude( + int collectionId, + QueryContext queryContext, + DbDataReader dbDataReader, + ResultCoordinator resultCoordinator, + TEntity entity, + Func outerIdentifier, + INavigation navigation, + IClrCollectionAccessor clrCollectionAccessor, + bool trackingQuery) + { + object collection = null; + if (!(entity is null)) + { + // Include case + if (trackingQuery) { - continue; + queryContext.StateManager.TryGetEntry(entity).SetIsLoaded(navigation); } - - relatedEntity = innerShaper(queryContext, dbDataReader, resultCoordinator); - if (!trackingQuery) + else { - fixup(entity, relatedEntity); - if (inverseNavigation != null && !inverseNavigation.IsCollection()) - { - SetIsLoadedNoTracking(relatedEntity, inverseNavigation); - } + SetIsLoadedNoTracking(entity, navigation); } - hasNext = resultCoordinator.HasNext ?? dbDataReader.Read(); + collection = clrCollectionAccessor.GetOrCreate(entity); } - resultCoordinator.HasNext = hasNext; + var outerKey = outerIdentifier(queryContext, dbDataReader); + + var collectionMaterializationContext = new CollectionMaterializationContext(entity, collection, outerKey); + if (resultCoordinator.Collections.Count == collectionId) + { + resultCoordinator.Collections.Add(collectionMaterializationContext); + } + else + { + resultCoordinator.Collections[collectionId] = collectionMaterializationContext; + } } private static void SetIsLoadedNoTracking(object entity, INavigation navigation) @@ -170,66 +195,75 @@ protected override Expression VisitExtension(Expression extensionExpression) { if (extensionExpression is IncludeExpression includeExpression) { - if (includeExpression.Navigation.IsCollection()) - { - var entityClrType = includeExpression.EntityExpression.Type; - var relatedEntityClrType = includeExpression.NavigationExpression.Type.TryGetSequenceType(); - var inverseNavigation = includeExpression.Navigation.FindInverse(); - var collectionShaper = (RelationalCollectionShaperExpression)includeExpression.NavigationExpression; - var innerShaper = Visit(collectionShaper.InnerShaper); - return Expression.Call( - _includeCollectionMethodInfo.MakeGenericMethod(entityClrType, relatedEntityClrType), - QueryCompilationContext.QueryContextParameter, - _dbDataReaderParameter, - // We don't need to visit entityExpression since it is supposed to be a parameterExpression only - includeExpression.EntityExpression, - Expression.Constant( - Expression.Lambda( - collectionShaper.OuterKeySelector, - QueryCompilationContext.QueryContextParameter, - _dbDataReaderParameter).Compile()), - Expression.Constant( - Expression.Lambda( - collectionShaper.InnerKeySelector, - QueryCompilationContext.QueryContextParameter, - _dbDataReaderParameter).Compile()), - Expression.Constant( - Expression.Lambda( - innerShaper, - QueryCompilationContext.QueryContextParameter, - _dbDataReaderParameter, - _resultCoordinatorParameter).Compile()), - Expression.Constant(includeExpression.Navigation), - Expression.Constant(inverseNavigation, typeof(INavigation)), - Expression.Constant( - GenerateFixup(entityClrType, relatedEntityClrType, includeExpression.Navigation, inverseNavigation).Compile()), - Expression.Constant(_tracking), - _resultCoordinatorParameter); - } - else - { - var entityClrType = includeExpression.EntityExpression.Type; - var relatedEntityClrType = includeExpression.NavigationExpression.Type; - var inverseNavigation = includeExpression.Navigation.FindInverse(); - return Expression.Call( - _includeReferenceMethodInfo.MakeGenericMethod(entityClrType, relatedEntityClrType), - QueryCompilationContext.QueryContextParameter, - _dbDataReaderParameter, - // We don't need to visit entityExpression since it is supposed to be a parameterExpression only - includeExpression.EntityExpression, - Expression.Constant( - Expression.Lambda( - Visit(includeExpression.NavigationExpression), - QueryCompilationContext.QueryContextParameter, - _dbDataReaderParameter, - _resultCoordinatorParameter).Compile()), - Expression.Constant(includeExpression.Navigation), - Expression.Constant(inverseNavigation, typeof(INavigation)), - Expression.Constant( - GenerateFixup(entityClrType, relatedEntityClrType, includeExpression.Navigation, inverseNavigation).Compile()), - Expression.Constant(_tracking), - _resultCoordinatorParameter); - } + Debug.Assert(!includeExpression.Navigation.IsCollection(), + "Only reference include should be present in tree"); + + var entityClrType = includeExpression.EntityExpression.Type; + var inverseNavigation = includeExpression.Navigation.FindInverse(); + var relatedEntityClrType = includeExpression.Navigation.GetTargetType().ClrType; + + return Expression.Call( + _includeReferenceMethodInfo.MakeGenericMethod(entityClrType, relatedEntityClrType), + QueryCompilationContext.QueryContextParameter, + // We don't need to visit entityExpression since it is supposed to be a parameterExpression only + includeExpression.EntityExpression, + includeExpression.NavigationExpression, + Expression.Constant(includeExpression.Navigation), + Expression.Constant(inverseNavigation, typeof(INavigation)), + Expression.Constant( + GenerateFixup(entityClrType, relatedEntityClrType, includeExpression.Navigation, inverseNavigation).Compile()), + Expression.Constant(_tracking)); + } + + if (extensionExpression is CollectionInitializingExperssion collectionInitializingExperssion) + { + return Expression.Call( + _initializeCollectionIncludeMethodInfo.MakeGenericMethod(collectionInitializingExperssion.Parent.Type), + Expression.Constant(collectionInitializingExperssion.CollectionId), + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter, + _resultCoordinatorParameter, + collectionInitializingExperssion.Parent, + Expression.Constant( + Expression.Lambda( + collectionInitializingExperssion.OuterIdentifier, + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter).Compile()), + Expression.Constant(collectionInitializingExperssion.Navigation), + Expression.Constant(collectionInitializingExperssion.Navigation.GetCollectionAccessor()), + Expression.Constant(_tracking)); + } + + if (extensionExpression is CollectionPopulatingExpression collectionPopulatingExpression) + { + var collectionShaper = collectionPopulatingExpression.Parent; + var entityClrType = collectionShaper.Navigation.DeclaringEntityType.ClrType; + var relatedEntityClrType = collectionShaper.Navigation.GetTargetType().ClrType; + var inverseNavigation = collectionShaper.Navigation.FindInverse(); + var innerShaper = Visit(collectionShaper.InnerShaper); + innerShaper = Expression.Constant(((LambdaExpression)innerShaper).Compile()); + + return Expression.Call( + _populateCollectionMethodInfo.MakeGenericMethod(entityClrType, relatedEntityClrType), + Expression.Constant(collectionShaper.CollectionId), + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter, + Expression.Constant( + Expression.Lambda( + collectionShaper.OuterIdentifier, + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter).Compile()), + Expression.Constant( + Expression.Lambda( + collectionShaper.SelfIdentifier, + QueryCompilationContext.QueryContextParameter, + _dbDataReaderParameter).Compile()), + innerShaper, + Expression.Constant(inverseNavigation, typeof(INavigation)), + Expression.Constant( + GenerateFixup(entityClrType, relatedEntityClrType, collectionShaper.Navigation, inverseNavigation).Compile()), + Expression.Constant(_tracking), + _resultCoordinatorParameter); } return base.VisitExtension(extensionExpression); diff --git a/src/EFCore.Relational/Query/Pipeline/QueryingEnumerable.cs b/src/EFCore.Relational/Query/Pipeline/QueryingEnumerable.cs index 69806e6746a..e6093f20fce 100644 --- a/src/EFCore.Relational/Query/Pipeline/QueryingEnumerable.cs +++ b/src/EFCore.Relational/Query/Pipeline/QueryingEnumerable.cs @@ -19,7 +19,7 @@ private class QueryingEnumerable : IEnumerable { private readonly RelationalQueryContext _relationalQueryContext; private readonly SelectExpression _selectExpression; - private readonly Func _shaper; + private readonly Func _shaper; private readonly IQuerySqlGeneratorFactory _querySqlGeneratorFactory; private readonly Type _contextType; private readonly IDiagnosticsLogger _logger; @@ -31,7 +31,7 @@ public QueryingEnumerable(RelationalQueryContext relationalQueryContext, ISqlExpressionFactory sqlExpressionFactory, IParameterNameGeneratorFactory parameterNameGeneratorFactory, SelectExpression selectExpression, - Func shaper, + Func shaper, Type contextType, IDiagnosticsLogger logger) { @@ -55,7 +55,7 @@ private sealed class Enumerator : IEnumerator private ResultCoordinator _resultCoordinator; private readonly RelationalQueryContext _relationalQueryContext; private readonly SelectExpression _selectExpression; - private readonly Func _shaper; + private readonly Func _shaper; private readonly IQuerySqlGeneratorFactory _querySqlGeneratorFactory; private readonly Type _contextType; private readonly IDiagnosticsLogger _logger; @@ -132,12 +132,28 @@ public bool MoveNext() } var hasNext = _resultCoordinator.HasNext ?? _dataReader.Read(); - _resultCoordinator.HasNext = null; + Current = default; - Current - = hasNext - ? _shaper(_relationalQueryContext, _dataReader.DbDataReader, _indexMap, _resultCoordinator) - : default; + if (hasNext) + { + while (true) + { + _resultCoordinator.ResultReady = true; + _resultCoordinator.HasNext = null; + Current = _shaper(_relationalQueryContext, _dataReader.DbDataReader, Current, _indexMap, _resultCoordinator); + if (_resultCoordinator.ResultReady) + { + break; + } + + if (!_dataReader.Read()) + { + _resultCoordinator.HasNext = false; + + break; + } + } + } return hasNext; } diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalCollectionShaperExpression.cs b/src/EFCore.Relational/Query/Pipeline/RelationalCollectionShaperExpression.cs index 0086e572905..15898d23f89 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalCollectionShaperExpression.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalCollectionShaperExpression.cs @@ -1,47 +1,88 @@ // 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.Linq.Expressions; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query.Expressions.Internal; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.Pipeline; namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline { - public class RelationalCollectionShaperExpression : CollectionShaperExpression + public class RelationalCollectionShaperExpression : Expression, IPrintable { public RelationalCollectionShaperExpression( - int collectionIndex, - Expression outerKeySelector, - Expression innerKeySelector, + int collectionId, + Expression parentIdentifier, + Expression outerIdentifier, + Expression selfIdentifier, Expression innerShaper, INavigation navigation) - : base(null, innerShaper, navigation) { - CollectionIndex = collectionIndex; - OuterKeySelector = outerKeySelector; - InnerKeySelector = innerKeySelector; + CollectionId = collectionId; + ParentIdentifier = parentIdentifier; + OuterIdentifier = outerIdentifier; + SelfIdentifier = selfIdentifier; + InnerShaper = innerShaper; + Navigation = navigation; } - public int CollectionIndex { get; } - public Expression OuterKeySelector { get; } - public Expression InnerKeySelector { get; } + public int CollectionId { get; } + public Expression ParentIdentifier { get; } + public Expression OuterIdentifier { get; } + public Expression SelfIdentifier { get; } + public Expression InnerShaper { get; } + public INavigation Navigation { get; } + + public override Type Type => typeof(IEnumerable<>).MakeGenericType(InnerShaper.Type); + public override ExpressionType NodeType => ExpressionType.Extension; protected override Expression VisitChildren(ExpressionVisitor visitor) { // Projection is always null so we do not need to visit it. - var outerKeySelector = visitor.Visit(OuterKeySelector); - var innerKeySelector = visitor.Visit(InnerKeySelector); + var parentIdentifier = visitor.Visit(ParentIdentifier); + var outerIdentifier = visitor.Visit(OuterIdentifier); + var selfIdentifier = visitor.Visit(SelfIdentifier); var innerShaper = visitor.Visit(InnerShaper); - return Update(outerKeySelector, innerKeySelector, innerShaper); + return Update(parentIdentifier, outerIdentifier, selfIdentifier, innerShaper); } public RelationalCollectionShaperExpression Update( - Expression outerKeySelector, Expression innerKeySelector, Expression innerShaper) + Expression parentIdentifier, Expression outerIdentifier, Expression selfIdentifier, Expression innerShaper) { - return outerKeySelector != OuterKeySelector || innerKeySelector != InnerKeySelector || innerShaper != InnerShaper - ? new RelationalCollectionShaperExpression(CollectionIndex, outerKeySelector, innerKeySelector, innerShaper, Navigation) + return parentIdentifier != ParentIdentifier + || outerIdentifier != OuterIdentifier + || selfIdentifier != SelfIdentifier + || innerShaper != InnerShaper + ? new RelationalCollectionShaperExpression( + CollectionId, parentIdentifier, outerIdentifier, selfIdentifier, innerShaper, Navigation) : this; } + + public void Print(ExpressionPrinter expressionPrinter) + { + expressionPrinter.StringBuilder.AppendLine("RelationalCollectionShaper:"); + using (expressionPrinter.StringBuilder.Indent()) + { + expressionPrinter.StringBuilder.AppendLine($"CollectionId: {CollectionId}"); + expressionPrinter.StringBuilder.Append("ParentIdentifier:"); + expressionPrinter.Visit(ParentIdentifier); + expressionPrinter.StringBuilder.AppendLine(); + expressionPrinter.StringBuilder.Append("OuterIdentifier:"); + expressionPrinter.Visit(OuterIdentifier); + expressionPrinter.StringBuilder.AppendLine(); + expressionPrinter.StringBuilder.Append("SelfIdentifier:"); + expressionPrinter.Visit(SelfIdentifier); + expressionPrinter.StringBuilder.AppendLine(); + expressionPrinter.StringBuilder.Append("InnerShaper:"); + expressionPrinter.Visit(InnerShaper); + expressionPrinter.StringBuilder.AppendLine(); + expressionPrinter.StringBuilder.AppendLine($"Navigation: {Navigation.Name}"); + + } + } } } diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs index 05b384abc43..1c2e302abad 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs @@ -106,16 +106,6 @@ protected override Expression VisitExtension(Expression extensionExpression) projectionBindingExpression.Type); } - if (extensionExpression is RelationalCollectionShaperExpression relationalCollectionShaperExpression) - { - return new RelationalCollectionShaperExpression( - relationalCollectionShaperExpression.CollectionIndex, - Visit(relationalCollectionShaperExpression.OuterKeySelector), - Visit(relationalCollectionShaperExpression.InnerKeySelector), - Visit(relationalCollectionShaperExpression.InnerShaper), - relationalCollectionShaperExpression.Navigation); - } - return base.VisitExtension(extensionExpression); } diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryCompilingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryCompilingExpressionVisitor.cs index b2398f86061..1fb72448c44 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryCompilingExpressionVisitor.cs @@ -2,6 +2,7 @@ // 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.Data.Common; using System.Linq; using System.Linq.Expressions; @@ -42,30 +43,33 @@ public RelationalShapedQueryCompilingExpressionVisitor( protected override Expression VisitShapedQueryExpression(ShapedQueryExpression shapedQueryExpression) { - var shaperBody = InjectEntityMaterializer(shapedQueryExpression.ShaperExpression); - var selectExpression = (SelectExpression)shapedQueryExpression.QueryExpression; var dataReaderParameter = Expression.Parameter(typeof(DbDataReader), "dataReader"); - var indexMapParameter = Expression.Parameter(typeof(int[]), "indexMap"); var resultCoordinatorParameter = Expression.Parameter(typeof(ResultCoordinator), "resultCoordinator"); + var indexMapParameter = Expression.Parameter(typeof(int[]), "indexMap"); + + var shaper = new ShaperExpressionProcessingExpressionVisitor( + selectExpression, + dataReaderParameter, + resultCoordinatorParameter, + indexMapParameter) + .Inject(shapedQueryExpression.ShaperExpression); + + shaper = InjectEntityMaterializer(shaper); - shaperBody = new RelationalProjectionBindingRemovingExpressionVisitor(selectExpression, dataReaderParameter) - .Visit(shaperBody); - shaperBody = new IncludeCompilingExpressionVisitor(dataReaderParameter, resultCoordinatorParameter, TrackQueryResults) - .Visit(shaperBody); + shaper = new RelationalProjectionBindingRemovingExpressionVisitor(selectExpression, dataReaderParameter) + .Visit(shaper); + shaper = new CollectionMaterializingExpressionVisitor( + dataReaderParameter, resultCoordinatorParameter, TrackQueryResults) + .Visit(shaper); if (selectExpression.IsNonComposedFromSql()) { - shaperBody = new IndexMapInjectingExpressionVisitor(indexMapParameter).Visit(shaperBody); + shaper = new IndexMapInjectingExpressionVisitor(indexMapParameter).Visit(shaper); } - var shaperLambda = Expression.Lambda( - shaperBody, - QueryCompilationContext.QueryContextParameter, - dataReaderParameter, - indexMapParameter, - resultCoordinatorParameter); + var shaperLambda = (LambdaExpression)shaper; return Expression.New( (Async @@ -110,8 +114,32 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp private class ResultCoordinator { + public bool ResultReady { get; set; } public bool? HasNext { get; set; } - public object[] KeyValues { get; set; } + public IList Collections { get; } = new List(); + public object[] OuterKeyValues { get; set; } + public object[] InnerKeyValues { get; set; } + } + + private class CollectionMaterializationContext + { + public CollectionMaterializationContext(object parent, object collection, object[] outerIdentifier) + { + Parent = parent; + Collection = collection; + OuterIdentifier = outerIdentifier; + } + + public object Parent { get; } + public object Collection { get; } + public object Current { get; private set; } + public object[] OuterIdentifier { get; } + public object[] SelfIdentifier { get; set; } + + public void UpdateCurrent(object current) + { + Current = current; + } } } } diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryOptimizingExpressionVisitors.cs b/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryOptimizingExpressionVisitors.cs index 5347bc748e3..90f391d4c82 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryOptimizingExpressionVisitors.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryOptimizingExpressionVisitors.cs @@ -36,28 +36,26 @@ public override Expression Visit(Expression query) query = new SqlExpressionOptimizingVisitor(SqlExpressionFactory, UseRelationalNulls).Visit(query); query = new NullComparisonTransformingExpressionVisitor().Visit(query); - if (query is ShapedQueryExpression shapedQueryExpression) - { - shapedQueryExpression.ShaperExpression - = new ShaperExpressionProcessingExpressionVisitor((SelectExpression)shapedQueryExpression.QueryExpression) - .Inject(shapedQueryExpression.ShaperExpression); - } - return query; } } public class CollectionJoinApplyingExpressionVisitor : ExpressionVisitor { + private int _collectionId; + protected override Expression VisitExtension(Expression extensionExpression) { if (extensionExpression is CollectionShaperExpression collectionShaperExpression) { + var collectionId = _collectionId++; + var innerShaper = Visit(collectionShaperExpression.InnerShaper); var selectExpression = (SelectExpression)collectionShaperExpression.Projection.QueryExpression; return selectExpression.ApplyCollectionJoin( collectionShaperExpression.Projection.Index.Value, + collectionId, innerShaper, collectionShaperExpression.Navigation); } diff --git a/src/EFCore.Relational/Query/Pipeline/ShaperExpressionDedupingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/ShaperExpressionDedupingExpressionVisitor.cs index df04912f8c3..71150cb1715 100644 --- a/src/EFCore.Relational/Query/Pipeline/ShaperExpressionDedupingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/ShaperExpressionDedupingExpressionVisitor.cs @@ -1,8 +1,14 @@ // 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; +using System.Linq; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query.Expressions.Internal; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.NavigationExpansion; using Microsoft.EntityFrameworkCore.Query.Pipeline; using Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions; @@ -12,23 +18,78 @@ namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline public class ShaperExpressionProcessingExpressionVisitor : ExpressionVisitor { private readonly SelectExpression _selectExpression; + private readonly ParameterExpression _dataReaderParameter; + private readonly ParameterExpression _resultCoordinatorParameter; + private readonly ParameterExpression _indexMapParameter; private IDictionary _mapping = new Dictionary(); private List _variables = new List(); private List _expressions = new List(); - private List _collectionIncludes = new List(); + private List _collectionPopulatingExpressions = new List(); - public ShaperExpressionProcessingExpressionVisitor(SelectExpression selectExpression) + public ShaperExpressionProcessingExpressionVisitor( + SelectExpression selectExpression, + ParameterExpression dataReaderParameter, + ParameterExpression resultCoordinatorParameter, + ParameterExpression indexMapParameter) { _selectExpression = selectExpression; + _dataReaderParameter = dataReaderParameter; + _resultCoordinatorParameter = resultCoordinatorParameter; + _indexMapParameter = indexMapParameter; } - public BlockExpression Inject(Expression expression) + public Expression Inject(Expression expression) { var result = Visit(expression); - _expressions.AddRange(_collectionIncludes); - _expressions.Add(result); - return Expression.Block(_variables, _expressions); + if (_collectionPopulatingExpressions.Count > 0) + { + _expressions.Add(result); + result = Expression.Block(_variables, _expressions); + _expressions.Clear(); + _variables.Clear(); + + var resultParameter = Expression.Parameter(result.Type, "result"); + + _expressions.Add( + Expression.IfThen( + Expression.Equal(resultParameter, Expression.Default(result.Type)), + Expression.Assign(resultParameter, result))); + _expressions.AddRange(_collectionPopulatingExpressions); + _expressions.Add(resultParameter); + + return ConvertToLambda(Expression.Block(_expressions), resultParameter); + } + else if (_expressions.All(e => e.NodeType == ExpressionType.Assign)) + { + result = new ReplacingExpressionVisitor(_expressions.Cast() + .ToDictionary(e => e.Left, e => e.Right)).Visit(result); + } + else + { + _expressions.Add(result); + result = Expression.Block(_variables, _expressions); + } + + return ConvertToLambda(result, Expression.Parameter(result.Type, "result")); + } + + private LambdaExpression ConvertToLambda(Expression result, ParameterExpression resultParameter) + { + return _indexMapParameter != null + ? Expression.Lambda( + result, + QueryCompilationContext.QueryContextParameter, + _dataReaderParameter, + resultParameter, + _indexMapParameter, + _resultCoordinatorParameter) + : Expression.Lambda( + result, + QueryCompilationContext.QueryContextParameter, + _dataReaderParameter, + resultParameter, + _resultCoordinatorParameter); } protected override Expression VisitExtension(Expression extensionExpression) @@ -66,20 +127,29 @@ protected override Expression VisitExtension(Expression extensionExpression) var entity = Visit(includeExpression.EntityExpression); if (includeExpression.NavigationExpression is RelationalCollectionShaperExpression relationalCollectionShaperExpression) { - _collectionIncludes.Add(includeExpression.Update( + var innerShaper = new ShaperExpressionProcessingExpressionVisitor( + _selectExpression, _dataReaderParameter, _resultCoordinatorParameter, null) + .Inject(relationalCollectionShaperExpression.InnerShaper); + + _expressions.Add(new CollectionInitializingExperssion( + relationalCollectionShaperExpression.CollectionId, entity, - relationalCollectionShaperExpression.Update( - relationalCollectionShaperExpression.OuterKeySelector, - relationalCollectionShaperExpression.InnerKeySelector, - new ShaperExpressionProcessingExpressionVisitor(_selectExpression) - .Inject(relationalCollectionShaperExpression.InnerShaper)))); + relationalCollectionShaperExpression.OuterIdentifier, + includeExpression.Navigation)); + + _collectionPopulatingExpressions.Add(new CollectionPopulatingExpression( + relationalCollectionShaperExpression.Update( + relationalCollectionShaperExpression.ParentIdentifier, + relationalCollectionShaperExpression.OuterIdentifier, + relationalCollectionShaperExpression.SelfIdentifier, + innerShaper), + true)); } else { _expressions.Add(includeExpression.Update( entity, - new ShaperExpressionProcessingExpressionVisitor(_selectExpression) - .Inject(includeExpression.NavigationExpression))); + Visit(includeExpression.NavigationExpression))); } return entity; @@ -95,4 +165,84 @@ private Expression GenerateKey(ProjectionBindingExpression projectionBindingExpr : projectionBindingExpression; } } + + public class CollectionInitializingExperssion : Expression, IPrintable + { + public CollectionInitializingExperssion(int collectionId, Expression parent, Expression outerIdentifier, INavigation navigation) + { + CollectionId = collectionId; + Parent = parent; + OuterIdentifier = outerIdentifier; + Navigation = navigation; + } + + protected override Expression VisitChildren(ExpressionVisitor visitor) + { + var parent = visitor.Visit(Parent); + var outerIdentifier = visitor.Visit(OuterIdentifier); + + return parent != Parent || outerIdentifier != OuterIdentifier + ? new CollectionInitializingExperssion(CollectionId, parent, outerIdentifier, Navigation) + : this; + } + + public void Print(ExpressionPrinter expressionPrinter) + { + expressionPrinter.StringBuilder.AppendLine("InitializeCollection:"); + using (expressionPrinter.StringBuilder.Indent()) + { + expressionPrinter.StringBuilder.AppendLine($"CollectionId: {CollectionId}"); + expressionPrinter.StringBuilder.AppendLine($"Navigation: {Navigation.Name}"); + expressionPrinter.StringBuilder.Append("Parent:"); + expressionPrinter.Visit(Parent); + expressionPrinter.StringBuilder.AppendLine(); + expressionPrinter.StringBuilder.Append("OuterIdentifier:"); + expressionPrinter.Visit(OuterIdentifier); + expressionPrinter.StringBuilder.AppendLine(); + } + } + + public override Type Type => Navigation.ClrType; + + public override ExpressionType NodeType => ExpressionType.Extension; + + public int CollectionId { get; } + public Expression Parent { get; } + public Expression OuterIdentifier { get; } + public INavigation Navigation { get; } + } + + public class CollectionPopulatingExpression : Expression, IPrintable + { + public CollectionPopulatingExpression(RelationalCollectionShaperExpression parent, bool include) + { + Parent = parent; + Include = include; + } + + protected override Expression VisitChildren(ExpressionVisitor visitor) + { + var parent = (RelationalCollectionShaperExpression)visitor.Visit(Parent); + + return parent != Parent + ? new CollectionPopulatingExpression(parent, Include) + : this; + } + + public void Print(ExpressionPrinter expressionPrinter) + { + expressionPrinter.StringBuilder.AppendLine("PopulateCollection:"); + using (expressionPrinter.StringBuilder.Indent()) + { + expressionPrinter.StringBuilder.Append("Parent:"); + expressionPrinter.Visit(Parent); + } + } + + public override Type Type => typeof(void); + + public override ExpressionType NodeType => ExpressionType.Extension; + public RelationalCollectionShaperExpression Parent { get; } + public bool Include { get; } + } } diff --git a/src/EFCore.Relational/Query/Pipeline/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/Pipeline/SqlExpressions/SelectExpression.cs index 552a4a400f6..78f93efd586 100644 --- a/src/EFCore.Relational/Query/Pipeline/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/Pipeline/SqlExpressions/SelectExpression.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Data.SqlTypes; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -25,8 +26,7 @@ private readonly IDictionary _orderings = new List(); private readonly List _identifyingProjection = new List(); - private readonly List<(List outerKey, List innerKey, SelectExpression innerSelectExpression)> _pendingCollectionJoins - = new List<(List outerKey, List innerKey, SelectExpression innerSelectExpression)>(); + private readonly List _pendingCollectionJoins = new List(); public IReadOnlyList Projection => _projection; public IReadOnlyList Tables => _tables; @@ -435,10 +435,7 @@ private static bool IsNullableProjection(ProjectionExpression projection) public CollectionShaperExpression AddCollectionProjection(ShapedQueryExpression shapedQueryExpression, INavigation navigation) { var innerSelectExpression = (SelectExpression)shapedQueryExpression.QueryExpression; - _pendingCollectionJoins.Add( - (GetIdentifyingProjection(), - innerSelectExpression.GetIdentifyingProjection(), - innerSelectExpression)); + _pendingCollectionJoins.Add(innerSelectExpression); return new CollectionShaperExpression( new ProjectionBindingExpression(this, _pendingCollectionJoins.Count - 1, typeof(object)), @@ -446,37 +443,34 @@ public CollectionShaperExpression AddCollectionProjection(ShapedQueryExpression navigation); } - public RelationalCollectionShaperExpression ApplyCollectionJoin(int collectionId, Expression shaperExpression, INavigation navigation) + public RelationalCollectionShaperExpression ApplyCollectionJoin( + int collectionIndex, int collectionId, Expression shaperExpression, INavigation navigation) { - var snapshot = _pendingCollectionJoins[collectionId]; - var outerKey = ConvertKeyExpressions(snapshot.outerKey); - var innerSelectExpression = snapshot.innerSelectExpression; + var innerSelectExpression = _pendingCollectionJoins[collectionIndex]; + var outerIdentifier = GetUniqueIdentifier(); innerSelectExpression.ApplyProjection(); - var innerKey = innerSelectExpression.ConvertKeyExpressions(snapshot.innerKey); - var boolTypeMapping = innerSelectExpression.Predicate.TypeMapping; - foreach (var orderingKey in snapshot.outerKey) + var selfIdentifier = innerSelectExpression.GetUniqueIdentifier(); + //var boolTypeMapping = innerSelectExpression.Predicate.TypeMapping; + foreach (var orderingKey in _identifyingProjection) { AppendOrdering(new OrderingExpression(orderingKey, ascending: true)); } - if (collectionId > 0) - { - foreach (var orderingKey in _pendingCollectionJoins[collectionId - 1].innerKey) - { - AppendOrdering(new OrderingExpression(orderingKey, ascending: true)); - } + //_identifyingProjection.AddRange(innerSelectExpression._identifyingProjection); - outerKey = ConvertKeyExpressions(snapshot.outerKey.Concat(_pendingCollectionJoins[collectionId - 1].innerKey).ToList()); - } - - var (outer, inner) = TryExtractJoinKey(innerSelectExpression); - if (outer != null) + var joinPredicate = TryExtractJoinKey(innerSelectExpression); + if (joinPredicate != null) { if (IsDistinct || Limit != null || Offset != null) { - outer = new SqlRemappingVisitor(PushdownIntoSubquery()).Remap(outer); + var remappingVisitor = new SqlRemappingVisitor(PushdownIntoSubquery()); + joinPredicate = remappingVisitor.Remap(joinPredicate); + for (var i = collectionIndex + 1; i < _pendingCollectionJoins.Count; i++) + { + _pendingCollectionJoins[i] = remappingVisitor.Remap(_pendingCollectionJoins[i]); + } } if (innerSelectExpression.Offset != null @@ -485,12 +479,11 @@ public RelationalCollectionShaperExpression ApplyCollectionJoin(int collectionId || innerSelectExpression.Predicate != null || innerSelectExpression.Tables.Count > 1) { - inner = new SqlRemappingVisitor(innerSelectExpression.PushdownIntoSubquery()) - .Remap(inner); + joinPredicate = new SqlRemappingVisitor(innerSelectExpression.PushdownIntoSubquery()) + .Remap(joinPredicate); } - var leftJoinExpression = new LeftJoinExpression(innerSelectExpression.Tables.Single(), - new SqlBinaryExpression(ExpressionType.Equal, outer, inner, typeof(bool), boolTypeMapping)); + var leftJoinExpression = new LeftJoinExpression(innerSelectExpression.Tables.Single(), joinPredicate); _tables.Add(leftJoinExpression); var indexOffset = _projection.Count; foreach (var projection in innerSelectExpression.Projection) @@ -505,24 +498,24 @@ public RelationalCollectionShaperExpression ApplyCollectionJoin(int collectionId var shaperRemapper = new ShaperRemappingExpressionVisitor(this, innerSelectExpression, indexOffset); var innerShaper = shaperRemapper.Visit(shaperExpression); - innerKey = shaperRemapper.Visit(innerKey); + selfIdentifier = shaperRemapper.Visit(selfIdentifier); return new RelationalCollectionShaperExpression( collectionId, - outerKey, - innerKey, + null, + outerIdentifier, + selfIdentifier, innerShaper, navigation); - } throw new NotImplementedException(); } - private Expression ConvertKeyExpressions(List keyExpressions) + private Expression GetUniqueIdentifier() { var updatedExpressions = new List(); - foreach (var keyExpression in keyExpressions) + foreach (var keyExpression in _identifyingProjection) { var index = AddToProjection(keyExpression); var projectionBindingExpression = new ProjectionBindingExpression(this, index, keyExpression.Type); @@ -538,11 +531,6 @@ private Expression ConvertKeyExpressions(List keyExpressions) updatedExpressions); } - private List GetIdentifyingProjection() - { - return _identifyingProjection.ToList(); - } - private class ShaperRemappingExpressionVisitor : ExpressionVisitor { private readonly SelectExpression _queryExpression; @@ -593,49 +581,51 @@ private object GetProjectionIndex(ProjectionBindingExpression projectionBindingE } } - private (SqlExpression outer, SqlExpression inner) TryExtractJoinKey(SelectExpression inner) + private SqlExpression TryExtractJoinKey(SelectExpression inner) { if (inner.Predicate is SqlBinaryExpression sqlBinaryExpression) { // TODO: Handle composite key case var keyComparison = ValidateKeyComparison(inner, sqlBinaryExpression); - if (keyComparison.outer != null) + if (keyComparison != null) { inner.Predicate = null; return keyComparison; } } - return (null, null); + return null; } - private (SqlExpression outer, SqlExpression inner) ValidateKeyComparison(SelectExpression inner, SqlBinaryExpression sqlBinaryExpression) + private SqlBinaryExpression ValidateKeyComparison(SelectExpression inner, SqlBinaryExpression sqlBinaryExpression) { if (sqlBinaryExpression.OperatorType == ExpressionType.Equal) { if (sqlBinaryExpression.Left is ColumnExpression leftColumn && sqlBinaryExpression.Right is ColumnExpression rightColumn) { - if (ContainsTableReference(this, leftColumn.Table) - && ContainsTableReference(inner, rightColumn.Table)) + if (ContainsTableReference(leftColumn.Table) + && inner.ContainsTableReference(rightColumn.Table)) { - return (leftColumn, rightColumn); + return sqlBinaryExpression; } - if (ContainsTableReference(this, rightColumn.Table) - && ContainsTableReference(inner, leftColumn.Table)) + if (ContainsTableReference(rightColumn.Table) + && inner.ContainsTableReference(leftColumn.Table)) { - return (rightColumn, leftColumn); + return sqlBinaryExpression.Update( + sqlBinaryExpression.Right, + sqlBinaryExpression.Left); } } } - return (null, null); + return null; } - private static bool ContainsTableReference(SelectExpression selectExpression, TableExpressionBase table) + private bool ContainsTableReference(TableExpressionBase table) { - return selectExpression.Tables.Any(te => ReferenceEquals(te is JoinExpressionBase jeb ? jeb.Table : te, table)); + return _tables.Any(te => ReferenceEquals(te is JoinExpressionBase jeb ? jeb.Table : te, table)); } public void AddInnerJoin(SelectExpression innerSelectExpression, SqlExpression joinPredicate, Type transparentIdentifierType) @@ -772,6 +762,7 @@ public SqlRemappingVisitor(IDictionary mappings } public SqlExpression Remap(SqlExpression sqlExpression) => (SqlExpression)Visit(sqlExpression); + public SelectExpression Remap(SelectExpression sqlExpression) => (SelectExpression)Visit(sqlExpression); public override Expression Visit(Expression expression) { diff --git a/src/EFCore/Query/Pipeline/ShapedQueryExpressionVisitor.cs b/src/EFCore/Query/Pipeline/ShapedQueryExpressionVisitor.cs index 6cb257adbd2..63a2af98cfe 100644 --- a/src/EFCore/Query/Pipeline/ShapedQueryExpressionVisitor.cs +++ b/src/EFCore/Query/Pipeline/ShapedQueryExpressionVisitor.cs @@ -166,9 +166,6 @@ private static readonly MethodInfo _startTrackingMethodInfo private readonly IEntityMaterializerSource _entityMaterializerSource; private readonly bool _trackQueryResults; - - private readonly List _variables = new List(); - private readonly List _expressions = new List(); private int _currentEntityIndex; public EntityMaterializerInjectingExpressionVisitor( @@ -180,9 +177,7 @@ public EntityMaterializerInjectingExpressionVisitor( public Expression Inject(Expression expression) { - _expressions.Add(Visit(expression)); - - return Expression.Block(_variables, _expressions); + return Visit(expression); } protected override Expression VisitExtension(Expression extensionExpression) diff --git a/test/EFCore.Specification.Tests/Query/IncludeAsyncTestBase.cs b/test/EFCore.Specification.Tests/Query/IncludeAsyncTestBase.cs index c9f1a69aba7..fdf03a5f9ed 100644 --- a/test/EFCore.Specification.Tests/Query/IncludeAsyncTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/IncludeAsyncTestBase.cs @@ -20,7 +20,7 @@ public abstract class IncludeAsyncTestBase : IClassFixture protected TFixture Fixture { get; } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection() { using (var context = CreateContext()) @@ -37,7 +37,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_order_by_subquery() { using (var context = CreateContext()) @@ -55,7 +55,7 @@ var customer } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_closes_reader() { using (var context = CreateContext()) @@ -68,7 +68,7 @@ public virtual async Task Include_closes_reader() } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_alias_generation() { using (var context = CreateContext()) @@ -82,7 +82,7 @@ var orders } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_and_reference() { using (var context = CreateContext()) @@ -97,7 +97,7 @@ var orders } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_as_no_tracking() { using (var context = CreateContext()) @@ -115,7 +115,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_as_no_tracking2() { using (var context = CreateContext()) @@ -135,7 +135,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_dependent_already_tracked() { using (var context = CreateContext()) @@ -159,7 +159,7 @@ var customer } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_dependent_already_tracked_as_no_tracking() { using (var context = CreateContext()) @@ -184,7 +184,7 @@ var customer } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_on_additional_from_clause() { using (var context = CreateContext()) @@ -202,7 +202,7 @@ from c2 in context.Set().Include(c => c.Orders) } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_on_additional_from_clause_no_tracking() { using (var context = CreateContext()) @@ -220,7 +220,7 @@ from c2 in context.Set().AsNoTracking().Include(c => c.Orders) } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_on_additional_from_clause_with_filter() { using (var context = CreateContext()) @@ -240,7 +240,7 @@ from c2 in context.Set() } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_on_additional_from_clause2() { using (var context = CreateContext()) @@ -257,7 +257,7 @@ from c2 in context.Set().Include(c => c.Orders) } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_on_join_clause_with_filter() { using (var context = CreateContext()) @@ -276,7 +276,7 @@ join o in context.Set() on c.CustomerID equals o.CustomerID } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_on_join_clause_with_order_by_and_filter() { using (var context = CreateContext()) @@ -319,7 +319,7 @@ join o in context.Set() on c.CustomerID equals o.CustomerID into g } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact(Skip = "issue #15711")] public virtual async Task Include_collection_on_inner_group_join_clause_with_filter() { using (var context = CreateContext()) @@ -360,7 +360,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_order_by_key() { using (var context = CreateContext()) @@ -378,7 +378,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_order_by_non_key() { using (var context = CreateContext()) @@ -396,7 +396,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_principal_already_tracked() { using (var context = CreateContext()) @@ -419,7 +419,7 @@ var customer2 } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_principal_already_tracked_as_no_tracking() { using (var context = CreateContext()) @@ -443,7 +443,7 @@ var customer2 } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_single_or_default_no_result() { using (var context = CreateContext()) @@ -457,7 +457,7 @@ var customer } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_when_projection() { using (var context = CreateContext()) @@ -473,7 +473,7 @@ var productIds } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_with_filter() { using (var context = CreateContext()) @@ -491,7 +491,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_with_filter_reordered() { using (var context = CreateContext()) @@ -509,7 +509,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_duplicate_collection() { using (var context = CreateContext()) @@ -540,7 +540,7 @@ from c2 in context.Set() } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_duplicate_collection_result_operator() { using (var context = CreateContext()) @@ -572,7 +572,7 @@ from c2 in context.Set() } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_duplicate_collection_result_operator2() { using (var context = CreateContext()) @@ -693,7 +693,7 @@ from o2 in context.Set() } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_multi_level_reference_and_collection_predicate() { using (var context = CreateContext()) @@ -728,7 +728,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_multi_level_collection_and_then_include_reference_predicate() { using (var context = CreateContext()) @@ -763,7 +763,7 @@ var orderDetails } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_multiple_references_and_collection_multi_level() { using (var context = CreateContext()) @@ -780,7 +780,7 @@ var orderDetails } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_multiple_references_and_collection_multi_level_reverse() { using (var context = CreateContext()) @@ -860,7 +860,7 @@ var orders } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_reference_and_collection() { using (var context = CreateContext()) @@ -981,7 +981,7 @@ var orders } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_references_and_collection_multi_level() { using (var context = CreateContext()) @@ -997,7 +997,7 @@ var orderDetails } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_then_include_collection() { using (var context = CreateContext()) @@ -1013,7 +1013,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_then_include_collection_then_include_reference() { using (var context = CreateContext()) @@ -1029,7 +1029,7 @@ var customers } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_collection_then_include_collection_predicate() { using (var context = CreateContext()) @@ -1045,7 +1045,7 @@ var customer } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_references_and_collection_multi_level_predicate() { using (var context = CreateContext()) @@ -1077,7 +1077,7 @@ var orderDetails } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_multi_level_reference_then_include_collection_predicate() { using (var context = CreateContext()) @@ -1092,7 +1092,7 @@ var order } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_multiple_references_then_include_collection_multi_level() { using (var context = CreateContext()) @@ -1109,7 +1109,7 @@ var orderDetails } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_multiple_references_then_include_collection_multi_level_reverse() { using (var context = CreateContext()) @@ -1158,7 +1158,7 @@ var orderDetails } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_references_then_include_collection_multi_level() { using (var context = CreateContext()) @@ -1174,7 +1174,7 @@ var orderDetails } } - [ConditionalFact(Skip = "issue #15064")] + [ConditionalFact] public virtual async Task Include_references_then_include_collection_multi_level_predicate() { using (var context = CreateContext()) diff --git a/test/EFCore.Specification.Tests/Query/IncludeTestBase.cs b/test/EFCore.Specification.Tests/Query/IncludeTestBase.cs index 576efba30fc..4fea65ad523 100644 --- a/test/EFCore.Specification.Tests/Query/IncludeTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/IncludeTestBase.cs @@ -1570,7 +1570,7 @@ var customers } } - [ConditionalTheory(Skip = "Issue#15871")] + [ConditionalTheory] [InlineData(false)] [InlineData(true)] public virtual void Include_duplicate_collection(bool useString) @@ -1639,7 +1639,7 @@ from c2 in context.Set() } } - [ConditionalTheory(Skip = "Issue#15871")] + [ConditionalTheory] [InlineData(false)] [InlineData(true)] public virtual void Include_duplicate_collection_result_operator(bool useString) @@ -2122,7 +2122,7 @@ var orderDetails } } - [ConditionalTheory(Skip = "Issue#15871")] + [ConditionalTheory] [InlineData(false)] [InlineData(true)] public virtual void Include_multiple_references_and_collection_multi_level(bool useString) @@ -2849,7 +2849,7 @@ var order } } - [ConditionalTheory(Skip = "Issue#15871")] + [ConditionalTheory] [InlineData(false)] [InlineData(true)] public virtual void Include_multiple_references_then_include_collection_multi_level(bool useString) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs index 4d03bee11e9..848c8a4f2eb 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AsyncSimpleQuerySqlServerTest.cs @@ -63,7 +63,7 @@ orderby o2.OrderID return Task.WhenAll(tasks); } - [ConditionalFact] + [ConditionalFact(Skip = "Issue#16218")] public Task Race_when_context_disposed_before_query_termination() { DbSet task; @@ -185,5 +185,17 @@ await context.Database.ExecuteSqlRawAsync( } } } + + [ConditionalFact(Skip = "Issue#16218")] + public override Task Select_bitwise_and_with_logical_and() + { + return base.Select_bitwise_and_with_logical_and(); + } + + [ConditionalFact(Skip = "Issue#16218")] + public override Task Mixed_sync_async_in_query_cache() + { + return base.Mixed_sync_async_in_query_cache(); + } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/IncludeAsyncSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/IncludeAsyncSqlServerTest.cs index 4b85d516c34..d996452137a 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/IncludeAsyncSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/IncludeAsyncSqlServerTest.cs @@ -21,34 +21,22 @@ public override async Task Include_collection_order_by_subquery() await base.Include_collection_order_by_subquery(); AssertSql( - @"SELECT TOP(1) [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].[CustomerID] = N'ALFKI' -ORDER BY ( - SELECT TOP(1) [o].[OrderDate] - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID] - ORDER BY [o].[EmployeeID] -), [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID], ( - SELECT TOP(1) [o1].[OrderDate] - FROM [Orders] AS [o1] - WHERE [c0].[CustomerID] = [o1].[CustomerID] - ORDER BY [o1].[EmployeeID] - ) AS [c] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] +FROM ( + SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( + SELECT TOP(1) [o].[OrderDate] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + ORDER BY [o].[EmployeeID]) AS [c] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] = N'ALFKI' ORDER BY ( - SELECT TOP(1) [o0].[OrderDate] - FROM [Orders] AS [o0] - WHERE [c0].[CustomerID] = [o0].[CustomerID] - ORDER BY [o0].[EmployeeID] - ), [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + SELECT TOP(1) [o].[OrderDate] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + ORDER BY [o].[EmployeeID]), [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o0] ON [t].[CustomerID] = [o0].[CustomerID] ORDER BY [t].[c], [t].[CustomerID]"); } @@ -57,29 +45,14 @@ public override async Task Include_collection_then_include_collection() await base.Include_collection_then_include_collection(); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t].[OrderID0], [t].[ProductID], [t].[Discount], [t].[Quantity], [t].[UnitPrice] FROM [Customers] AS [c] -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID], [c.Orders].[OrderID]", - // - @"SELECT [c.Orders.OrderDetails].[OrderID], [c.Orders.OrderDetails].[ProductID], [c.Orders.OrderDetails].[Discount], [c.Orders.OrderDetails].[Quantity], [c.Orders.OrderDetails].[UnitPrice] -FROM [Order Details] AS [c.Orders.OrderDetails] -INNER JOIN ( - SELECT DISTINCT [c.Orders0].[OrderID], [t0].[CustomerID] - FROM [Orders] AS [c.Orders0] - INNER JOIN ( - SELECT [c1].[CustomerID] - FROM [Customers] AS [c1] - ) AS [t0] ON [c.Orders0].[CustomerID] = [t0].[CustomerID] -) AS [t1] ON [c.Orders.OrderDetails].[OrderID] = [t1].[OrderID] -ORDER BY [t1].[CustomerID], [t1].[OrderID]"); +LEFT JOIN ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o0].[OrderID] AS [OrderID0], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] + FROM [Orders] AS [o] + LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +) AS [t] ON [c].[CustomerID] = [t].[CustomerID] +ORDER BY [c].[CustomerID]"); } [SqlServerCondition(SqlServerCondition.SupportsOffset)] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/IncludeSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/IncludeSqlServerTest.cs index e52374dd9a0..9ed036af2af 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/IncludeSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/IncludeSqlServerTest.cs @@ -23,18 +23,14 @@ public override void Include_list(bool useString) base.Include_list(useString); AssertSql( - @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] + @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock], [t].[OrderID], [t].[ProductID], [t].[Discount], [t].[Quantity], [t].[UnitPrice], [t].[OrderID0], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate] FROM [Products] AS [p] -ORDER BY [p].[ProductID]", - // - @"SELECT [p.OrderDetails].[OrderID], [p.OrderDetails].[ProductID], [p.OrderDetails].[Discount], [p.OrderDetails].[Quantity], [p.OrderDetails].[UnitPrice], [o.Order].[OrderID], [o.Order].[CustomerID], [o.Order].[EmployeeID], [o.Order].[OrderDate] -FROM [Order Details] AS [p.OrderDetails] -INNER JOIN [Orders] AS [o.Order] ON [p.OrderDetails].[OrderID] = [o.Order].[OrderID] -INNER JOIN ( - SELECT [p0].[ProductID] - FROM [Products] AS [p0] -) AS [t] ON [p.OrderDetails].[ProductID] = [t].[ProductID] -ORDER BY [t].[ProductID]"); +LEFT JOIN ( + SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o0].[OrderID] AS [OrderID0], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] + FROM [Order Details] AS [o] + INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +) AS [t] ON [p].[ProductID] = [t].[ProductID] +ORDER BY [p].[ProductID]"); } public override void Include_reference(bool useString) @@ -42,9 +38,9 @@ public override void Include_reference(bool useString) base.Include_reference(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region] + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [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] -LEFT JOIN [Customers] AS [o.Customer] ON [o].[CustomerID] = [o.Customer].[CustomerID]"); +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]"); } @@ -53,7 +49,12 @@ public override void Include_when_result_operator(bool useString) base.Include_when_result_operator(useString); AssertSql( - @""); + @"SELECT CASE + WHEN EXISTS ( + SELECT 1 + FROM [Customers] AS [c]) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END"); } public override void Include_collection(bool useString) @@ -61,17 +62,10 @@ public override void Include_collection(bool useString) base.Include_collection(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID]"); +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +ORDER BY [c].[CustomerID]"); } public override void Include_collection_with_last(bool useString) @@ -79,18 +73,14 @@ public override void Include_collection_with_last(bool useString) base.Include_collection_with_last(useString); AssertSql( - @"SELECT TOP(1) [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] -ORDER BY [c].[CompanyName] DESC, [c].[CustomerID] DESC", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID], [c0].[CompanyName] - FROM [Customers] AS [c0] - ORDER BY [c0].[CompanyName] DESC, [c0].[CustomerID] DESC -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CompanyName] DESC, [t].[CustomerID] DESC"); + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(1) [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] + ORDER BY [c].[CompanyName] DESC, [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] +ORDER BY [t].[CompanyName] DESC, [t].[CustomerID]"); } public override void Include_collection_with_last_no_orderby(bool useString) @@ -121,21 +111,14 @@ public override void Include_collection_skip_no_order_by(bool useString) AssertSql( @"@__p_0='10' -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] -ORDER BY [c].[CustomerID] -OFFSET @__p_0 ROWS", - // - @"@__p_0='10' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] - ORDER BY [c0].[CustomerID] +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [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] + ORDER BY [c].[CustomerID] OFFSET @__p_0 ROWS -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } } @@ -149,19 +132,13 @@ public override void Include_collection_take_no_order_by(bool useString) AssertSql( @"@__p_0='10' -SELECT TOP(@__p_0) [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] -ORDER BY [c].[CustomerID]", - // - @"@__p_0='10' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(@__p_0) [c0].[CustomerID] - FROM [Customers] AS [c0] - ORDER BY [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(@__p_0) [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] + ORDER BY [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } } @@ -176,22 +153,14 @@ public override void Include_collection_skip_take_no_order_by(bool useString) @"@__p_0='10' @__p_1='5' -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] -ORDER BY [c].[CustomerID] -OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY", - // - @"@__p_0='10' -@__p_1='5' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] - ORDER BY [c0].[CustomerID] +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [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] + ORDER BY [c].[CustomerID] OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } } @@ -201,19 +170,11 @@ public override void Include_reference_and_collection(bool useString) base.Include_reference_and_collection(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region] + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] FROM [Orders] AS [o] -LEFT JOIN [Customers] AS [o.Customer] ON [o].[CustomerID] = [o.Customer].[CustomerID] -ORDER BY [o].[OrderID]", - // - @"SELECT [o.OrderDetails].[OrderID], [o.OrderDetails].[ProductID], [o.OrderDetails].[Discount], [o.OrderDetails].[Quantity], [o.OrderDetails].[UnitPrice] -FROM [Order Details] AS [o.OrderDetails] -INNER JOIN ( - SELECT DISTINCT [o0].[OrderID] - FROM [Orders] AS [o0] - LEFT JOIN [Customers] AS [o.Customer0] ON [o0].[CustomerID] = [o.Customer0].[CustomerID] -) AS [t] ON [o.OrderDetails].[OrderID] = [t].[OrderID] -ORDER BY [t].[OrderID]"); +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] +LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +ORDER BY [o].[OrderID]"); } public override void Include_references_multi_level(bool useString) @@ -221,10 +182,10 @@ public override void Include_references_multi_level(bool useString) base.Include_references_multi_level(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o.Order].[OrderID], [o.Order].[CustomerID], [o.Order].[EmployeeID], [o.Order].[OrderDate], [o.Order.Customer].[CustomerID], [o.Order.Customer].[Address], [o.Order.Customer].[City], [o.Order.Customer].[CompanyName], [o.Order.Customer].[ContactName], [o.Order.Customer].[ContactTitle], [o.Order.Customer].[Country], [o.Order.Customer].[Fax], [o.Order.Customer].[Phone], [o.Order.Customer].[PostalCode], [o.Order.Customer].[Region] + @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Order Details] AS [o] -INNER JOIN [Orders] AS [o.Order] ON [o].[OrderID] = [o.Order].[OrderID] -LEFT JOIN [Customers] AS [o.Order.Customer] ON [o.Order].[CustomerID] = [o.Order.Customer].[CustomerID]"); +INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID]"); } public override void Include_multiple_references_multi_level(bool useString) @@ -232,11 +193,11 @@ public override void Include_multiple_references_multi_level(bool useString) base.Include_multiple_references_multi_level(useString); AssertSql( - @"SELECT [od].[OrderID], [od].[ProductID], [od].[Discount], [od].[Quantity], [od].[UnitPrice], [od.Order].[OrderID], [od.Order].[CustomerID], [od.Order].[EmployeeID], [od.Order].[OrderDate], [od.Order.Customer].[CustomerID], [od.Order.Customer].[Address], [od.Order.Customer].[City], [od.Order.Customer].[CompanyName], [od.Order.Customer].[ContactName], [od.Order.Customer].[ContactTitle], [od.Order.Customer].[Country], [od.Order.Customer].[Fax], [od.Order.Customer].[Phone], [od.Order.Customer].[PostalCode], [od.Order.Customer].[Region], [od.Order.Customer.Product].[ProductID], [od.Order.Customer.Product].[Discontinued], [od.Order.Customer.Product].[ProductName], [od.Order.Customer.Product].[SupplierID], [od.Order.Customer.Product].[UnitPrice], [od.Order.Customer.Product].[UnitsInStock] -FROM [Order Details] AS [od] -INNER JOIN [Orders] AS [od.Order] ON [od].[OrderID] = [od.Order].[OrderID] -LEFT JOIN [Customers] AS [od.Order.Customer] ON [od.Order].[CustomerID] = [od.Order.Customer].[CustomerID] -INNER JOIN [Products] AS [od.Order.Customer.Product] ON [od].[ProductID] = [od.Order.Customer.Product].[ProductID]"); + @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] +FROM [Order Details] AS [o] +INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID] +INNER JOIN [Products] AS [p] ON [o].[ProductID] = [p].[ProductID]"); } public override void Include_multiple_references_multi_level_reverse(bool useString) @@ -244,11 +205,11 @@ public override void Include_multiple_references_multi_level_reverse(bool useStr base.Include_multiple_references_multi_level_reverse(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o.Order].[OrderID], [o.Order].[CustomerID], [o.Order].[EmployeeID], [o.Order].[OrderDate], [o.Order.Customer].[CustomerID], [o.Order.Customer].[Address], [o.Order.Customer].[City], [o.Order.Customer].[CompanyName], [o.Order.Customer].[ContactName], [o.Order.Customer].[ContactTitle], [o.Order.Customer].[Country], [o.Order.Customer].[Fax], [o.Order.Customer].[Phone], [o.Order.Customer].[PostalCode], [o.Order.Customer].[Region], [o.Product].[ProductID], [o.Product].[Discontinued], [o.Product].[ProductName], [o.Product].[SupplierID], [o.Product].[UnitPrice], [o.Product].[UnitsInStock] + @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM [Order Details] AS [o] -INNER JOIN [Orders] AS [o.Order] ON [o].[OrderID] = [o.Order].[OrderID] -LEFT JOIN [Customers] AS [o.Order.Customer] ON [o.Order].[CustomerID] = [o.Order.Customer].[CustomerID] -INNER JOIN [Products] AS [o.Product] ON [o].[ProductID] = [o.Product].[ProductID]"); +INNER JOIN [Products] AS [p] ON [o].[ProductID] = [p].[ProductID] +INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID]"); } public override void Include_references_and_collection_multi_level(bool useString) @@ -256,21 +217,12 @@ public override void Include_references_and_collection_multi_level(bool useStrin base.Include_references_and_collection_multi_level(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o.Order].[OrderID], [o.Order].[CustomerID], [o.Order].[EmployeeID], [o.Order].[OrderDate], [o.Order.Customer].[CustomerID], [o.Order.Customer].[Address], [o.Order.Customer].[City], [o.Order.Customer].[CompanyName], [o.Order.Customer].[ContactName], [o.Order.Customer].[ContactTitle], [o.Order.Customer].[Country], [o.Order.Customer].[Fax], [o.Order.Customer].[Phone], [o.Order.Customer].[PostalCode], [o.Order.Customer].[Region] + @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o1].[OrderID], [o1].[CustomerID], [o1].[EmployeeID], [o1].[OrderDate] FROM [Order Details] AS [o] -INNER JOIN [Orders] AS [o.Order] ON [o].[OrderID] = [o.Order].[OrderID] -LEFT JOIN [Customers] AS [o.Order.Customer] ON [o.Order].[CustomerID] = [o.Order.Customer].[CustomerID] -ORDER BY [o.Order.Customer].[CustomerID]", - // - @"SELECT [o.Order.Customer.Orders].[OrderID], [o.Order.Customer.Orders].[CustomerID], [o.Order.Customer.Orders].[EmployeeID], [o.Order.Customer.Orders].[OrderDate] -FROM [Orders] AS [o.Order.Customer.Orders] -INNER JOIN ( - SELECT DISTINCT [o.Order.Customer0].[CustomerID] - FROM [Order Details] AS [o0] - INNER JOIN [Orders] AS [o.Order0] ON [o0].[OrderID] = [o.Order0].[OrderID] - LEFT JOIN [Customers] AS [o.Order.Customer0] ON [o.Order0].[CustomerID] = [o.Order.Customer0].[CustomerID] -) AS [t] ON [o.Order.Customer.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID]"); +INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +LEFT JOIN [Customers] AS [c] ON [o0].[CustomerID] = [c].[CustomerID] +LEFT JOIN [Orders] AS [o1] ON [c].[CustomerID] = [o1].[CustomerID] +ORDER BY [o].[OrderID], [o].[ProductID], [o0].[OrderID]"); } public override void Include_multi_level_reference_and_collection_predicate(bool useString) @@ -278,25 +230,16 @@ public override void Include_multi_level_reference_and_collection_predicate(bool base.Include_multi_level_reference_and_collection_predicate(useString); AssertSql( - @"SELECT TOP(2) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region] -FROM [Orders] AS [o] -LEFT JOIN [Customers] AS [o.Customer] ON [o].[CustomerID] = [o.Customer].[CustomerID] -WHERE [o].[OrderID] = 10248 -ORDER BY [o.Customer].[CustomerID]", - // - @"SELECT [o.Customer.Orders].[OrderID], [o.Customer.Orders].[CustomerID], [o.Customer.Orders].[EmployeeID], [o.Customer.Orders].[OrderDate] -FROM [Orders] AS [o.Customer.Orders] -INNER JOIN ( - SELECT DISTINCT [t].* - FROM ( - SELECT TOP(1) [o.Customer0].[CustomerID] - FROM [Orders] AS [o0] - LEFT JOIN [Customers] AS [o.Customer0] ON [o0].[CustomerID] = [o.Customer0].[CustomerID] - WHERE [o0].[OrderID] = 10248 - ORDER BY [o.Customer0].[CustomerID] - ) AS [t] -) AS [t0] ON [o.Customer.Orders].[CustomerID] = [t0].[CustomerID] -ORDER BY [t0].[CustomerID]"); + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t].[CustomerID0], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] +FROM ( + SELECT TOP(2) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [c].[CustomerID] AS [CustomerID0], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] + FROM [Orders] AS [o] + LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] + WHERE [o].[OrderID] = 10248 + ORDER BY [o].[OrderID] +) AS [t] +LEFT JOIN [Orders] AS [o0] ON [t].[CustomerID0] = [o0].[CustomerID] +ORDER BY [t].[OrderID]"); } public override void Include_multi_level_collection_and_then_include_reference_predicate(bool useString) @@ -304,20 +247,18 @@ public override void Include_multi_level_collection_and_then_include_reference_p base.Include_multi_level_collection_and_then_include_reference_predicate(useString); AssertSql( - @"SELECT TOP(2) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -FROM [Orders] AS [o] -WHERE [o].[OrderID] = 10248 -ORDER BY [o].[OrderID]", - // - @"SELECT [o.OrderDetails].[OrderID], [o.OrderDetails].[ProductID], [o.OrderDetails].[Discount], [o.OrderDetails].[Quantity], [o.OrderDetails].[UnitPrice], [o.Product].[ProductID], [o.Product].[Discontinued], [o.Product].[ProductName], [o.Product].[SupplierID], [o.Product].[UnitPrice], [o.Product].[UnitsInStock] -FROM [Order Details] AS [o.OrderDetails] -INNER JOIN [Products] AS [o.Product] ON [o.OrderDetails].[ProductID] = [o.Product].[ProductID] -INNER JOIN ( - SELECT TOP(1) [o0].[OrderID] - FROM [Orders] AS [o0] - WHERE [o0].[OrderID] = 10248 - ORDER BY [o0].[OrderID] -) AS [t] ON [o.OrderDetails].[OrderID] = [t].[OrderID] + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t0].[OrderID], [t0].[ProductID], [t0].[Discount], [t0].[Quantity], [t0].[UnitPrice], [t0].[ProductID0], [t0].[Discontinued], [t0].[ProductName], [t0].[SupplierID], [t0].[UnitPrice0], [t0].[UnitsInStock] +FROM ( + SELECT TOP(2) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + FROM [Orders] AS [o] + WHERE [o].[OrderID] = 10248 + ORDER BY [o].[OrderID] +) AS [t] +LEFT JOIN ( + SELECT [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice], [p].[ProductID] AS [ProductID0], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice] AS [UnitPrice0], [p].[UnitsInStock] + FROM [Order Details] AS [o0] + INNER JOIN [Products] AS [p] ON [o0].[ProductID] = [p].[ProductID] +) AS [t0] ON [t].[OrderID] = [t0].[OrderID] ORDER BY [t].[OrderID]"); } @@ -326,17 +267,10 @@ public override void Include_collection_alias_generation(bool useString) base.Include_collection_alias_generation(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] FROM [Orders] AS [o] -ORDER BY [o].[OrderID]", - // - @"SELECT [o.OrderDetails].[OrderID], [o.OrderDetails].[ProductID], [o.OrderDetails].[Discount], [o.OrderDetails].[Quantity], [o.OrderDetails].[UnitPrice] -FROM [Order Details] AS [o.OrderDetails] -INNER JOIN ( - SELECT [o0].[OrderID] - FROM [Orders] AS [o0] -) AS [t] ON [o.OrderDetails].[OrderID] = [t].[OrderID] -ORDER BY [t].[OrderID]"); +LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +ORDER BY [o].[OrderID]"); } public override void Include_collection_order_by_collection_column(bool useString) @@ -344,34 +278,22 @@ public override void Include_collection_order_by_collection_column(bool useStrin base.Include_collection_order_by_collection_column(useString); AssertSql( - @"SELECT TOP(1) [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].[CustomerID] LIKE N'W%' -ORDER BY ( - SELECT TOP(1) [oo].[OrderDate] - FROM [Orders] AS [oo] - WHERE [c].[CustomerID] = [oo].[CustomerID] - ORDER BY [oo].[OrderDate] DESC -) DESC, [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID], ( - SELECT TOP(1) [oo1].[OrderDate] - FROM [Orders] AS [oo1] - WHERE [c0].[CustomerID] = [oo1].[CustomerID] - ORDER BY [oo1].[OrderDate] DESC - ) AS [c] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] LIKE N'W%' + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] +FROM ( + SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( + SELECT TOP(1) [o].[OrderDate] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + ORDER BY [o].[OrderDate] DESC) AS [c] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] LIKE N'W%' ORDER BY ( - SELECT TOP(1) [oo0].[OrderDate] - FROM [Orders] AS [oo0] - WHERE [c0].[CustomerID] = [oo0].[CustomerID] - ORDER BY [oo0].[OrderDate] DESC - ) DESC, [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + SELECT TOP(1) [o].[OrderDate] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + ORDER BY [o].[OrderDate] DESC) DESC, [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o0] ON [t].[CustomerID] = [o0].[CustomerID] ORDER BY [t].[c] DESC, [t].[CustomerID]"); } @@ -380,17 +302,10 @@ public override void Include_collection_order_by_key(bool useString) base.Include_collection_order_by_key(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID]"); +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +ORDER BY [c].[CustomerID]"); } public override void Include_collection_order_by_non_key(bool useString) @@ -398,17 +313,10 @@ public override void Include_collection_order_by_non_key(bool useString) base.Include_collection_order_by_non_key(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] -ORDER BY [c].[City], [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID], [c0].[City] - FROM [Customers] AS [c0] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[City], [t].[CustomerID]"); +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +ORDER BY [c].[City], [c].[CustomerID]"); } public override void Include_collection_order_by_non_key_with_take(bool useString) @@ -418,19 +326,13 @@ public override void Include_collection_order_by_non_key_with_take(bool useStrin AssertSql( @"@__p_0='10' -SELECT TOP(@__p_0) [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] -ORDER BY [c].[ContactTitle], [c].[CustomerID]", - // - @"@__p_0='10' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(@__p_0) [c0].[CustomerID], [c0].[ContactTitle] - FROM [Customers] AS [c0] - ORDER BY [c0].[ContactTitle], [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(@__p_0) [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] + ORDER BY [c].[ContactTitle], [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[ContactTitle], [t].[CustomerID]"); } @@ -443,21 +345,14 @@ public override void Include_collection_order_by_non_key_with_skip(bool useStrin AssertSql( @"@__p_0='10' -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] -ORDER BY [c].[ContactTitle], [c].[CustomerID] -OFFSET @__p_0 ROWS", - // - @"@__p_0='10' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID], [c0].[ContactTitle] - FROM [Customers] AS [c0] - ORDER BY [c0].[ContactTitle], [c0].[CustomerID] +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [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] + ORDER BY [c].[ContactTitle], [c].[CustomerID] OFFSET @__p_0 ROWS -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[ContactTitle], [t].[CustomerID]"); } } @@ -467,17 +362,13 @@ public override void Include_collection_order_by_non_key_with_first_or_default(b base.Include_collection_order_by_non_key_with_first_or_default(useString); AssertSql( - @"SELECT TOP(1) [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] -ORDER BY [c].[CompanyName] DESC, [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID], [c0].[CompanyName] - FROM [Customers] AS [c0] - ORDER BY [c0].[CompanyName] DESC, [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(1) [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] + ORDER BY [c].[CompanyName] DESC, [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CompanyName] DESC, [t].[CustomerID]"); } @@ -486,34 +377,22 @@ public override void Include_collection_order_by_subquery(bool useString) base.Include_collection_order_by_subquery(useString); AssertSql( - @"SELECT TOP(1) [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].[CustomerID] = N'ALFKI' -ORDER BY ( - SELECT TOP(1) [o].[OrderDate] - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID] - ORDER BY [o].[EmployeeID] -), [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID], ( - SELECT TOP(1) [o1].[OrderDate] - FROM [Orders] AS [o1] - WHERE [c0].[CustomerID] = [o1].[CustomerID] - ORDER BY [o1].[EmployeeID] - ) AS [c] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] +FROM ( + SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( + SELECT TOP(1) [o].[OrderDate] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + ORDER BY [o].[EmployeeID]) AS [c] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] = N'ALFKI' ORDER BY ( - SELECT TOP(1) [o0].[OrderDate] - FROM [Orders] AS [o0] - WHERE [c0].[CustomerID] = [o0].[CustomerID] - ORDER BY [o0].[EmployeeID] - ), [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + SELECT TOP(1) [o].[OrderDate] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + ORDER BY [o].[EmployeeID]), [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o0] ON [t].[CustomerID] = [o0].[CustomerID] ORDER BY [t].[c], [t].[CustomerID]"); } @@ -522,17 +401,10 @@ public override void Include_collection_as_no_tracking(bool useString) base.Include_collection_as_no_tracking(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID]"); +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +ORDER BY [c].[CustomerID]"); } public override void Include_collection_principal_already_tracked(bool useString) @@ -544,19 +416,14 @@ public override void Include_collection_principal_already_tracked(bool useString FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI'", // - @"SELECT TOP(2) [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].[CustomerID] = N'ALFKI' -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' - ORDER BY [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(2) [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].[CustomerID] = N'ALFKI' + ORDER BY [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -569,19 +436,14 @@ public override void Include_collection_principal_already_tracked_as_no_tracking FROM [Customers] AS [c] WHERE [c].[CustomerID] = N'ALFKI'", // - @"SELECT TOP(2) [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].[CustomerID] = N'ALFKI' -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' - ORDER BY [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(2) [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].[CustomerID] = N'ALFKI' + ORDER BY [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -590,19 +452,11 @@ public override void Include_collection_with_filter(bool useString) base.Include_collection_with_filter(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] WHERE [c].[CustomerID] = N'ALFKI' -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID]"); +ORDER BY [c].[CustomerID]"); } public override void Include_collection_with_filter_reordered(bool useString) @@ -610,19 +464,11 @@ public override void Include_collection_with_filter_reordered(bool useString) base.Include_collection_with_filter_reordered(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] WHERE [c].[CustomerID] = N'ALFKI' -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID]"); +ORDER BY [c].[CustomerID]"); } public override void Include_collection_then_include_collection(bool useString) @@ -630,29 +476,14 @@ public override void Include_collection_then_include_collection(bool useString) base.Include_collection_then_include_collection(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t].[OrderID0], [t].[ProductID], [t].[Discount], [t].[Quantity], [t].[UnitPrice] FROM [Customers] AS [c] -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID] - FROM [Customers] AS [c0] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID], [c.Orders].[OrderID]", - // - @"SELECT [c.Orders.OrderDetails].[OrderID], [c.Orders.OrderDetails].[ProductID], [c.Orders.OrderDetails].[Discount], [c.Orders.OrderDetails].[Quantity], [c.Orders.OrderDetails].[UnitPrice] -FROM [Order Details] AS [c.Orders.OrderDetails] -INNER JOIN ( - SELECT DISTINCT [c.Orders0].[OrderID], [t0].[CustomerID] - FROM [Orders] AS [c.Orders0] - INNER JOIN ( - SELECT [c1].[CustomerID] - FROM [Customers] AS [c1] - ) AS [t0] ON [c.Orders0].[CustomerID] = [t0].[CustomerID] -) AS [t1] ON [c.Orders.OrderDetails].[OrderID] = [t1].[OrderID] -ORDER BY [t1].[CustomerID], [t1].[OrderID]"); +LEFT JOIN ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o0].[OrderID] AS [OrderID0], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] + FROM [Orders] AS [o] + LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +) AS [t] ON [c].[CustomerID] = [t].[CustomerID] +ORDER BY [c].[CustomerID]"); } public override void Include_collection_then_include_collection_then_include_reference(bool useString) @@ -660,7 +491,18 @@ public override void Include_collection_then_include_collection_then_include_ref base.Include_collection_then_include_collection_then_include_reference(useString); 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].[OrderID0], [t0].[ProductID], [t0].[Discount], [t0].[Quantity], [t0].[UnitPrice], [t0].[ProductID0], [t0].[Discontinued], [t0].[ProductName], [t0].[SupplierID], [t0].[UnitPrice0], [t0].[UnitsInStock] +FROM [Customers] AS [c] +LEFT JOIN ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [t].[OrderID] AS [OrderID0], [t].[ProductID], [t].[Discount], [t].[Quantity], [t].[UnitPrice], [t].[ProductID0], [t].[Discontinued], [t].[ProductName], [t].[SupplierID], [t].[UnitPrice0], [t].[UnitsInStock] + FROM [Orders] AS [o] + LEFT JOIN ( + SELECT [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice], [p].[ProductID] AS [ProductID0], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice] AS [UnitPrice0], [p].[UnitsInStock] + FROM [Order Details] AS [o0] + INNER JOIN [Products] AS [p] ON [o0].[ProductID] = [p].[ProductID] + ) AS [t] ON [o].[OrderID] = [t].[OrderID] +) AS [t0] ON [c].[CustomerID] = [t0].[CustomerID] +ORDER BY [c].[CustomerID]"); } public override void Include_collection_when_projection(bool useString) @@ -677,21 +519,12 @@ public override void Include_collection_on_join_clause_with_filter(bool useStrin base.Include_collection_on_join_clause_with_filter(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] INNER JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE [c].[CustomerID] = N'ALFKI' -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT DISTINCT [c0].[CustomerID] - FROM [Customers] AS [c0] - INNER JOIN [Orders] AS [o0] ON [c0].[CustomerID] = [o0].[CustomerID] - WHERE [c0].[CustomerID] = N'ALFKI' -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID]"); +ORDER BY [c].[CustomerID], [o].[OrderID]"); } public override void Include_collection_on_additional_from_clause_with_filter(bool useString) @@ -699,21 +532,15 @@ public override void Include_collection_on_additional_from_clause_with_filter(bo base.Include_collection_on_additional_from_clause_with_filter(useString); AssertSql( - @"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 [c1] -CROSS JOIN [Customers] AS [c] -WHERE [c].[CustomerID] = N'ALFKI' -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT DISTINCT [c0].[CustomerID] - FROM [Customers] AS [c10] - CROSS JOIN [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[CustomerID]"); + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [c0].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Customers] AS [c0] +CROSS 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] + WHERE [c].[CustomerID] = N'ALFKI' +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] +ORDER BY [c0].[CustomerID], [t].[CustomerID]"); } public override void Include_collection_on_additional_from_clause(bool useString) @@ -723,29 +550,15 @@ public override void Include_collection_on_additional_from_clause(bool useString AssertSql( @"@__p_0='5' -SELECT [c2].[CustomerID], [c2].[Address], [c2].[City], [c2].[CompanyName], [c2].[ContactName], [c2].[ContactTitle], [c2].[Country], [c2].[Fax], [c2].[Phone], [c2].[PostalCode], [c2].[Region] -FROM ( - SELECT TOP(@__p_0) [c].* - FROM [Customers] AS [c] - ORDER BY [c].[CustomerID] -) AS [t] -CROSS JOIN [Customers] AS [c2] -ORDER BY [c2].[CustomerID]", - // - @"@__p_0='5' - -SELECT [c2.Orders].[OrderID], [c2.Orders].[CustomerID], [c2.Orders].[EmployeeID], [c2.Orders].[OrderDate] -FROM [Orders] AS [c2.Orders] -INNER JOIN ( - SELECT DISTINCT [c20].[CustomerID] - FROM ( - SELECT TOP(@__p_0) [c0].* - FROM [Customers] AS [c0] - ORDER BY [c0].[CustomerID] - ) AS [t0] - CROSS JOIN [Customers] AS [c20] -) AS [t1] ON [c2.Orders].[CustomerID] = [t1].[CustomerID] -ORDER BY [t1].[CustomerID]"); +SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [t].[CustomerID], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(@__p_0) [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] + ORDER BY [c0].[CustomerID] +) AS [t] +CROSS JOIN [Customers] AS [c] +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +ORDER BY [t].[CustomerID], [c].[CustomerID]"); } public override void Include_duplicate_collection(bool useString) @@ -755,9 +568,9 @@ public override void Include_duplicate_collection(bool useString) if (SupportsOffset) { AssertSql( - @"@__p_0='2' + @"@__p_0='2' -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].[Address], [t0].[City], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Country], [t0].[Fax], [t0].[Phone], [t0].[PostalCode], [t0].[Region] +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].[Address], [t0].[City], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Country], [t0].[Fax], [t0].[Phone], [t0].[PostalCode], [t0].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM ( SELECT TOP(@__p_0) [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] @@ -769,47 +582,9 @@ FROM [Customers] AS [c0] ORDER BY [c0].[CustomerID] OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY ) AS [t0] -ORDER BY [t].[CustomerID], [t0].[CustomerID]", - // - @"@__p_0='2' - -SELECT [c1.Orders].[OrderID], [c1.Orders].[CustomerID], [c1.Orders].[EmployeeID], [c1.Orders].[OrderDate] -FROM [Orders] AS [c1.Orders] -INNER JOIN ( - SELECT DISTINCT [t1].[CustomerID] - FROM ( - SELECT TOP(@__p_0) [c1].* - FROM [Customers] AS [c1] - ORDER BY [c1].[CustomerID] - ) AS [t1] - CROSS JOIN ( - SELECT [c2].* - FROM [Customers] AS [c2] - ORDER BY [c2].[CustomerID] - OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY - ) AS [t2] -) AS [t3] ON [c1.Orders].[CustomerID] = [t3].[CustomerID] -ORDER BY [t3].[CustomerID]", - // - @"@__p_0='2' - -SELECT [c2.Orders].[OrderID], [c2.Orders].[CustomerID], [c2.Orders].[EmployeeID], [c2.Orders].[OrderDate] -FROM [Orders] AS [c2.Orders] -INNER JOIN ( - SELECT DISTINCT [t5].[CustomerID], [t4].[CustomerID] AS [CustomerID0] - FROM ( - SELECT TOP(@__p_0) [c3].* - FROM [Customers] AS [c3] - ORDER BY [c3].[CustomerID] - ) AS [t4] - CROSS JOIN ( - SELECT [c4].* - FROM [Customers] AS [c4] - ORDER BY [c4].[CustomerID] - OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY - ) AS [t5] -) AS [t6] ON [c2.Orders].[CustomerID] = [t6].[CustomerID] -ORDER BY [t6].[CustomerID0], [t6].[CustomerID]"); +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [t0].[CustomerID] = [o0].[CustomerID] +ORDER BY [t].[CustomerID], [t0].[CustomerID]"); } } @@ -823,69 +598,25 @@ public override void Include_duplicate_collection_result_operator(bool useString @"@__p_1='1' @__p_0='2' -SELECT TOP(@__p_1) [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].[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], [t1].[CustomerID0], [t1].[Address0], [t1].[City0], [t1].[CompanyName0], [t1].[ContactName0], [t1].[ContactTitle0], [t1].[Country0], [t1].[Fax0], [t1].[Phone0], [t1].[PostalCode0], [t1].[Region0], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM ( - SELECT TOP(@__p_0) [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] - ORDER BY [c].[CustomerID] -) AS [t] -CROSS JOIN ( - 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] - ORDER BY [c0].[CustomerID] - OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY -) AS [t0] -ORDER BY [t].[CustomerID], [t0].[CustomerID]", - // - @"@__p_1='1' -@__p_0='2' - -SELECT [c1.Orders].[OrderID], [c1.Orders].[CustomerID], [c1.Orders].[EmployeeID], [c1.Orders].[OrderDate] -FROM [Orders] AS [c1.Orders] -INNER JOIN ( - SELECT DISTINCT [t3].* - FROM ( - SELECT TOP(@__p_1) [t1].[CustomerID] - FROM ( - SELECT TOP(@__p_0) [c1].* - FROM [Customers] AS [c1] - ORDER BY [c1].[CustomerID] - ) AS [t1] - CROSS JOIN ( - SELECT [c2].* - FROM [Customers] AS [c2] - ORDER BY [c2].[CustomerID] - OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY - ) AS [t2] - ORDER BY [t1].[CustomerID] - ) AS [t3] -) AS [t4] ON [c1.Orders].[CustomerID] = [t4].[CustomerID] -ORDER BY [t4].[CustomerID]", - // - @"@__p_1='1' -@__p_0='2' - -SELECT [c2.Orders].[OrderID], [c2.Orders].[CustomerID], [c2.Orders].[EmployeeID], [c2.Orders].[OrderDate] -FROM [Orders] AS [c2.Orders] -INNER JOIN ( - SELECT DISTINCT [t7].* + SELECT TOP(@__p_1) [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [t0].[CustomerID] AS [CustomerID0], [t0].[Address] AS [Address0], [t0].[City] AS [City0], [t0].[CompanyName] AS [CompanyName0], [t0].[ContactName] AS [ContactName0], [t0].[ContactTitle] AS [ContactTitle0], [t0].[Country] AS [Country0], [t0].[Fax] AS [Fax0], [t0].[Phone] AS [Phone0], [t0].[PostalCode] AS [PostalCode0], [t0].[Region] AS [Region0] FROM ( - SELECT TOP(@__p_1) [t6].[CustomerID], [t5].[CustomerID] AS [CustomerID0] - FROM ( - SELECT TOP(@__p_0) [c3].* - FROM [Customers] AS [c3] - ORDER BY [c3].[CustomerID] - ) AS [t5] - CROSS JOIN ( - SELECT [c4].* - FROM [Customers] AS [c4] - ORDER BY [c4].[CustomerID] - OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY - ) AS [t6] - ORDER BY [t5].[CustomerID], [t6].[CustomerID] - ) AS [t7] -) AS [t8] ON [c2.Orders].[CustomerID] = [t8].[CustomerID] -ORDER BY [t8].[CustomerID0], [t8].[CustomerID]"); + SELECT TOP(@__p_0) [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] + ORDER BY [c].[CustomerID] + ) AS [t] + CROSS JOIN ( + 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] + ORDER BY [c0].[CustomerID] + OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY + ) AS [t0] + ORDER BY [t].[CustomerID], [t0].[CustomerID] +) AS [t1] +LEFT JOIN [Orders] AS [o] ON [t1].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [t1].[CustomerID0] = [o0].[CustomerID] +ORDER BY [t1].[CustomerID], [t1].[CustomerID0]"); } } @@ -894,21 +625,12 @@ public override void Include_collection_on_join_clause_with_order_by_and_filter( base.Include_collection_on_join_clause_with_order_by_and_filter(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Customers] AS [c] INNER JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +LEFT JOIN [Orders] AS [o0] ON [c].[CustomerID] = [o0].[CustomerID] WHERE [c].[CustomerID] = N'ALFKI' -ORDER BY [c].[City], [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT DISTINCT [c0].[CustomerID], [c0].[City] - FROM [Customers] AS [c0] - INNER JOIN [Orders] AS [o0] ON [c0].[CustomerID] = [o0].[CustomerID] - WHERE [c0].[CustomerID] = N'ALFKI' -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[City], [t].[CustomerID]"); +ORDER BY [c].[City], [c].[CustomerID], [o].[OrderID]"); } public override void Include_collection_when_groupby(bool useString) @@ -980,7 +702,8 @@ SELECT TOP(@__p_0) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName FROM [Customers] AS [c] ORDER BY [c].[CustomerID] ) AS [t] -CROSS JOIN [Customers] AS [c2]"); +CROSS JOIN [Customers] AS [c0] +ORDER BY [t].[CustomerID]"); } public override void Include_where_skip_take_projection(bool useString) @@ -993,11 +716,11 @@ public override void Include_where_skip_take_projection(bool useString) @"@__p_0='1' @__p_1='2' -SELECT [od.Order].[CustomerID] -FROM [Order Details] AS [od] -INNER JOIN [Orders] AS [od.Order] ON [od].[OrderID] = [od.Order].[OrderID] -WHERE [od].[Quantity] = CAST(10 AS smallint) -ORDER BY [od].[OrderID], [od].[ProductID] +SELECT [o].[CustomerID] +FROM [Order Details] AS [o0] +INNER JOIN [Orders] AS [o] ON [o0].[OrderID] = [o].[OrderID] +WHERE [o0].[Quantity] = CAST(10 AS smallint) +ORDER BY [o0].[OrderID], [o0].[ProductID] OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY"); } } @@ -1012,44 +735,24 @@ public override void Include_duplicate_collection_result_operator2(bool useStrin @"@__p_1='1' @__p_0='2' -SELECT TOP(@__p_1) [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].[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], [t1].[CustomerID0], [t1].[Address0], [t1].[City0], [t1].[CompanyName0], [t1].[ContactName0], [t1].[ContactTitle0], [t1].[Country0], [t1].[Fax0], [t1].[Phone0], [t1].[PostalCode0], [t1].[Region0], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM ( - SELECT TOP(@__p_0) [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] - ORDER BY [c].[CustomerID] -) AS [t] -CROSS JOIN ( - 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] - ORDER BY [c0].[CustomerID] - OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY -) AS [t0] -ORDER BY [t].[CustomerID]", - // - @"@__p_1='1' -@__p_0='2' - -SELECT [c1.Orders].[OrderID], [c1.Orders].[CustomerID], [c1.Orders].[EmployeeID], [c1.Orders].[OrderDate] -FROM [Orders] AS [c1.Orders] -INNER JOIN ( - SELECT DISTINCT [t3].* + SELECT TOP(@__p_1) [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [t0].[CustomerID] AS [CustomerID0], [t0].[Address] AS [Address0], [t0].[City] AS [City0], [t0].[CompanyName] AS [CompanyName0], [t0].[ContactName] AS [ContactName0], [t0].[ContactTitle] AS [ContactTitle0], [t0].[Country] AS [Country0], [t0].[Fax] AS [Fax0], [t0].[Phone] AS [Phone0], [t0].[PostalCode] AS [PostalCode0], [t0].[Region] AS [Region0] FROM ( - SELECT TOP(@__p_1) [t1].[CustomerID] - FROM ( - SELECT TOP(@__p_0) [c1].* - FROM [Customers] AS [c1] - ORDER BY [c1].[CustomerID] - ) AS [t1] - CROSS JOIN ( - SELECT [c2].* - FROM [Customers] AS [c2] - ORDER BY [c2].[CustomerID] - OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY - ) AS [t2] - ORDER BY [t1].[CustomerID] - ) AS [t3] -) AS [t4] ON [c1.Orders].[CustomerID] = [t4].[CustomerID] -ORDER BY [t4].[CustomerID]"); + SELECT TOP(@__p_0) [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] + ORDER BY [c].[CustomerID] + ) AS [t] + CROSS JOIN ( + 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] + ORDER BY [c0].[CustomerID] + OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY + ) AS [t0] + ORDER BY [t].[CustomerID], [t0].[CustomerID] +) AS [t1] +LEFT JOIN [Orders] AS [o] ON [t1].[CustomerID] = [o].[CustomerID] +ORDER BY [t1].[CustomerID], [t1].[CustomerID0]"); } } @@ -1058,10 +761,10 @@ public override void Include_multiple_references(bool useString) base.Include_multiple_references(useString); AssertSql( - @"SELECT [od].[OrderID], [od].[ProductID], [od].[Discount], [od].[Quantity], [od].[UnitPrice], [od.Order].[OrderID], [od.Order].[CustomerID], [od.Order].[EmployeeID], [od.Order].[OrderDate], [od.Order.Product].[ProductID], [od.Order.Product].[Discontinued], [od.Order.Product].[ProductName], [od.Order.Product].[SupplierID], [od.Order.Product].[UnitPrice], [od.Order.Product].[UnitsInStock] -FROM [Order Details] AS [od] -INNER JOIN [Orders] AS [od.Order] ON [od].[OrderID] = [od.Order].[OrderID] -INNER JOIN [Products] AS [od.Order.Product] ON [od].[ProductID] = [od.Order.Product].[ProductID]"); + @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate], [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] +FROM [Order Details] AS [o] +INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID] +INNER JOIN [Products] AS [p] ON [o].[ProductID] = [p].[ProductID]"); } public override void Include_reference_alias_generation(bool useString) @@ -1069,9 +772,9 @@ public override void Include_reference_alias_generation(bool useString) base.Include_reference_alias_generation(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o.Order].[OrderID], [o.Order].[CustomerID], [o.Order].[EmployeeID], [o.Order].[OrderDate] + @"SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice], [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Order Details] AS [o] -INNER JOIN [Orders] AS [o.Order] ON [o].[OrderID] = [o.Order].[OrderID]"); +INNER JOIN [Orders] AS [o0] ON [o].[OrderID] = [o0].[OrderID]"); } public override void Include_duplicate_reference(bool useString) @@ -1083,20 +786,21 @@ public override void Include_duplicate_reference(bool useString) AssertSql( @"@__p_0='2' -SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [o1.Customer].[CustomerID], [o1.Customer].[Address], [o1.Customer].[City], [o1.Customer].[CompanyName], [o1.Customer].[ContactName], [o1.Customer].[ContactTitle], [o1.Customer].[Country], [o1.Customer].[Fax], [o1.Customer].[Phone], [o1.Customer].[PostalCode], [o1.Customer].[Region], [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [o2.Customer].[CustomerID], [o2.Customer].[Address], [o2.Customer].[City], [o2.Customer].[CompanyName], [o2.Customer].[ContactName], [o2.Customer].[ContactTitle], [o2.Customer].[Country], [o2.Customer].[Fax], [o2.Customer].[Phone], [o2.Customer].[PostalCode], [o2.Customer].[Region] +SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [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], [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] ORDER BY [o].[CustomerID], [o].[OrderID] ) AS [t] -LEFT JOIN [Customers] AS [o1.Customer] ON [t].[CustomerID] = [o1.Customer].[CustomerID] CROSS JOIN ( SELECT [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Orders] AS [o0] ORDER BY [o0].[CustomerID], [o0].[OrderID] OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY ) AS [t0] -LEFT JOIN [Customers] AS [o2.Customer] ON [t0].[CustomerID] = [o2.Customer].[CustomerID]"); +LEFT JOIN [Customers] AS [c] ON [t].[CustomerID] = [c].[CustomerID] +LEFT JOIN [Customers] AS [c0] ON [t0].[CustomerID] = [c0].[CustomerID] +ORDER BY [t].[CustomerID], [t].[OrderID]"); } } @@ -1109,19 +813,20 @@ public override void Include_duplicate_reference2(bool useString) AssertSql( @"@__p_0='2' -SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [o1.Customer].[CustomerID], [o1.Customer].[Address], [o1.Customer].[City], [o1.Customer].[CompanyName], [o1.Customer].[ContactName], [o1.Customer].[ContactTitle], [o1.Customer].[Country], [o1.Customer].[Fax], [o1.Customer].[Phone], [o1.Customer].[PostalCode], [o1.Customer].[Region], [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] +SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [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] FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] ORDER BY [o].[OrderID] ) AS [t] -LEFT JOIN [Customers] AS [o1.Customer] ON [t].[CustomerID] = [o1.Customer].[CustomerID] CROSS JOIN ( SELECT [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] FROM [Orders] AS [o0] ORDER BY [o0].[OrderID] OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY -) AS [t0]"); +) AS [t0] +LEFT JOIN [Customers] AS [c] ON [t].[CustomerID] = [c].[CustomerID] +ORDER BY [t].[OrderID]"); } } @@ -1134,7 +839,7 @@ public override void Include_duplicate_reference3(bool useString) AssertSql( @"@__p_0='2' -SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [o2.Customer].[CustomerID], [o2.Customer].[Address], [o2.Customer].[City], [o2.Customer].[CompanyName], [o2.Customer].[ContactName], [o2.Customer].[ContactTitle], [o2.Customer].[Country], [o2.Customer].[Fax], [o2.Customer].[Phone], [o2.Customer].[PostalCode], [o2.Customer].[Region] +SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] FROM ( SELECT TOP(@__p_0) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] @@ -1146,7 +851,8 @@ FROM [Orders] AS [o0] ORDER BY [o0].[OrderID] OFFSET 2 ROWS FETCH NEXT 2 ROWS ONLY ) AS [t0] -LEFT JOIN [Customers] AS [o2.Customer] ON [t0].[CustomerID] = [o2.Customer].[CustomerID]"); +LEFT JOIN [Customers] AS [c] ON [t0].[CustomerID] = [c].[CustomerID] +ORDER BY [t].[OrderID]"); } } @@ -1164,10 +870,10 @@ public override void Include_reference_with_filter_reordered(bool useString) base.Include_reference_with_filter_reordered(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region] + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [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] -LEFT JOIN [Customers] AS [o.Customer] ON [o].[CustomerID] = [o.Customer].[CustomerID] -WHERE [o].[CustomerID] = N'ALFKI'"); +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] +WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); } public override void Include_reference_with_filter(bool useString) @@ -1175,10 +881,10 @@ public override void Include_reference_with_filter(bool useString) base.Include_reference_with_filter(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region] + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [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] -LEFT JOIN [Customers] AS [o.Customer] ON [o].[CustomerID] = [o.Customer].[CustomerID] -WHERE [o].[CustomerID] = N'ALFKI'"); +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] +WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL"); } public override void Include_collection_dependent_already_tracked_as_no_tracking(bool useString) @@ -1188,21 +894,16 @@ public override void Include_collection_dependent_already_tracked_as_no_tracking AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI'", - // - @"SELECT TOP(2) [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].[CustomerID] = N'ALFKI' -ORDER BY [c].[CustomerID]", +WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL", // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' - ORDER BY [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(2) [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].[CustomerID] = N'ALFKI' + ORDER BY [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -1213,21 +914,16 @@ public override void Include_collection_dependent_already_tracked(bool useString AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI'", - // - @"SELECT TOP(2) [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].[CustomerID] = N'ALFKI' -ORDER BY [c].[CustomerID]", +WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL", // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] = N'ALFKI' - ORDER BY [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(2) [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].[CustomerID] = N'ALFKI' + ORDER BY [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -1238,11 +934,11 @@ public override void Include_reference_dependent_already_tracked(bool useString) AssertSql( @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE [o].[CustomerID] = N'ALFKI'", +WHERE ([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL", // - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region] + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [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] -LEFT JOIN [Customers] AS [o.Customer] ON [o].[CustomerID] = [o.Customer].[CustomerID]"); +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]"); } public override void Include_reference_as_no_tracking(bool useString) @@ -1250,9 +946,9 @@ public override void Include_reference_as_no_tracking(bool useString) base.Include_reference_as_no_tracking(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region] + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [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] -LEFT JOIN [Customers] AS [o.Customer] ON [o].[CustomerID] = [o.Customer].[CustomerID]"); +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]"); } public override void Include_collection_as_no_tracking2(bool useString) @@ -1262,19 +958,13 @@ public override void Include_collection_as_no_tracking2(bool useString) AssertSql( @"@__p_0='5' -SELECT TOP(@__p_0) [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] -ORDER BY [c].[CustomerID]", - // - @"@__p_0='5' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(@__p_0) [c0].[CustomerID] - FROM [Customers] AS [c0] - ORDER BY [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(@__p_0) [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] + ORDER BY [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -1283,8 +973,9 @@ public override void Include_with_complex_projection(bool useString) base.Include_with_complex_projection(useString); AssertSql( - @"SELECT [o].[CustomerID] AS [Id] -FROM [Orders] AS [o]"); + @"SELECT [c].[CustomerID] AS [Id] +FROM [Orders] AS [o] +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID]"); } public override void Include_with_complex_projection_does_not_change_ordering_of_projection(bool useString) @@ -1294,16 +985,14 @@ public override void Include_with_complex_projection_does_not_change_ordering_of AssertSql( @"SELECT [c].[CustomerID] AS [Id], ( SELECT COUNT(*) - FROM [Orders] AS [o0] - WHERE [c].[CustomerID] = [o0].[CustomerID] -) AS [TotalOrders] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AS [TotalOrders] FROM [Customers] AS [c] -WHERE ([c].[ContactTitle] = N'Owner') AND (( +WHERE (([c].[ContactTitle] = N'Owner') AND [c].[ContactTitle] IS NOT NULL) AND (( SELECT COUNT(*) - FROM [Orders] AS [o] - WHERE [c].[CustomerID] = [o].[CustomerID] -) > 2) -ORDER BY [Id]"); + FROM [Orders] AS [o0] + WHERE ([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) > 2) +ORDER BY [c].[CustomerID]"); } public override void Include_with_take(bool useString) @@ -1313,19 +1002,13 @@ public override void Include_with_take(bool useString) AssertSql( @"@__p_0='10' -SELECT TOP(@__p_0) [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] -ORDER BY [c].[City] DESC, [c].[CustomerID]", - // - @"@__p_0='10' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(@__p_0) [c0].[CustomerID], [c0].[City] - FROM [Customers] AS [c0] - ORDER BY [c0].[City] DESC, [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(@__p_0) [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] + ORDER BY [c].[City] DESC, [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[City] DESC, [t].[CustomerID]"); } @@ -1338,21 +1021,14 @@ public override void Include_with_skip(bool useString) AssertSql( @"@__p_0='80' -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] -ORDER BY [c].[ContactName], [c].[CustomerID] -OFFSET @__p_0 ROWS", - // - @"@__p_0='80' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID], [c0].[ContactName] - FROM [Customers] AS [c0] - ORDER BY [c0].[ContactName], [c0].[CustomerID] +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [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] + ORDER BY [c].[ContactName], [c].[CustomerID] OFFSET @__p_0 ROWS -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[ContactName], [t].[CustomerID]"); } } @@ -1362,59 +1038,27 @@ public override void Then_include_collection_order_by_collection_column(bool use base.Then_include_collection_order_by_collection_column(useString); AssertSql( - @"SELECT TOP(1) [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].[CustomerID] LIKE N'W%' -ORDER BY ( - SELECT TOP(1) [oo].[OrderDate] - FROM [Orders] AS [oo] - WHERE [c].[CustomerID] = [oo].[CustomerID] - ORDER BY [oo].[OrderDate] DESC -) DESC, [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT TOP(1) [c0].[CustomerID], ( - SELECT TOP(1) [oo1].[OrderDate] - FROM [Orders] AS [oo1] - WHERE [c0].[CustomerID] = [oo1].[CustomerID] - ORDER BY [oo1].[OrderDate] DESC - ) AS [c] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] LIKE N'W%' + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[OrderID0], [t0].[ProductID], [t0].[Discount], [t0].[Quantity], [t0].[UnitPrice] +FROM ( + SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], ( + SELECT TOP(1) [o].[OrderDate] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + ORDER BY [o].[OrderDate] DESC) AS [c] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] LIKE N'W%' ORDER BY ( - SELECT TOP(1) [oo0].[OrderDate] - FROM [Orders] AS [oo0] - WHERE [c0].[CustomerID] = [oo0].[CustomerID] - ORDER BY [oo0].[OrderDate] DESC - ) DESC, [c0].[CustomerID] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[c] DESC, [t].[CustomerID], [c.Orders].[OrderID]", - // - @"SELECT [c.Orders.OrderDetails].[OrderID], [c.Orders.OrderDetails].[ProductID], [c.Orders.OrderDetails].[Discount], [c.Orders.OrderDetails].[Quantity], [c.Orders.OrderDetails].[UnitPrice] -FROM [Order Details] AS [c.Orders.OrderDetails] -INNER JOIN ( - SELECT DISTINCT [c.Orders0].[OrderID], [t0].[c], [t0].[CustomerID] - FROM [Orders] AS [c.Orders0] - INNER JOIN ( - SELECT TOP(1) [c1].[CustomerID], ( - SELECT TOP(1) [oo3].[OrderDate] - FROM [Orders] AS [oo3] - WHERE [c1].[CustomerID] = [oo3].[CustomerID] - ORDER BY [oo3].[OrderDate] DESC - ) AS [c] - FROM [Customers] AS [c1] - WHERE [c1].[CustomerID] LIKE N'W%' - ORDER BY ( - SELECT TOP(1) [oo2].[OrderDate] - FROM [Orders] AS [oo2] - WHERE [c1].[CustomerID] = [oo2].[CustomerID] - ORDER BY [oo2].[OrderDate] DESC - ) DESC, [c1].[CustomerID] - ) AS [t0] ON [c.Orders0].[CustomerID] = [t0].[CustomerID] -) AS [t1] ON [c.Orders.OrderDetails].[OrderID] = [t1].[OrderID] -ORDER BY [t1].[c] DESC, [t1].[CustomerID], [t1].[OrderID]"); + SELECT TOP(1) [o].[OrderDate] + FROM [Orders] AS [o] + WHERE ([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL + ORDER BY [o].[OrderDate] DESC) DESC, [c].[CustomerID] +) AS [t] +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 [t0] ON [t].[CustomerID] = [t0].[CustomerID] +ORDER BY [t].[c] DESC, [t].[CustomerID]"); } public override void Include_collection_with_conditional_order_by(bool useString) @@ -1422,23 +1066,13 @@ public override void Include_collection_with_conditional_order_by(bool useString base.Include_collection_with_conditional_order_by(useString); 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 [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Customers] AS [c] +LEFT JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] ORDER BY CASE - WHEN [c].[CustomerID] LIKE N'S%' - THEN 1 ELSE 2 -END, [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID], CASE - WHEN [c0].[CustomerID] LIKE N'S%' - THEN 1 ELSE 2 - END AS [c] - FROM [Customers] AS [c0] -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] -ORDER BY [t].[c], [t].[CustomerID]"); + WHEN [c].[CustomerID] LIKE N'S%' THEN 1 + ELSE 2 +END, [c].[CustomerID]"); } public override void Include_reference_distinct_is_server_evaluated(bool useString) @@ -1446,10 +1080,13 @@ public override void Include_reference_distinct_is_server_evaluated(bool useStri base.Include_reference_distinct_is_server_evaluated(useString); AssertSql( - @"SELECT DISTINCT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region] -FROM [Orders] AS [o] -LEFT JOIN [Customers] AS [o.Customer] ON [o].[CustomerID] = [o.Customer].[CustomerID] -WHERE [o].[OrderID] < 10250"); + @"SELECT [t].[OrderID], [t].[CustomerID], [t].[EmployeeID], [t].[OrderDate], [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM ( + SELECT DISTINCT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + FROM [Orders] AS [o] + WHERE [o].[OrderID] < 10250 +) AS [t] +LEFT JOIN [Customers] AS [c] ON [t].[CustomerID] = [c].[CustomerID]"); } public override void Include_collection_distinct_is_server_evaluated(bool useString) @@ -1457,18 +1094,13 @@ public override void Include_collection_distinct_is_server_evaluated(bool useStr base.Include_collection_distinct_is_server_evaluated(useString); AssertSql( - @"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] -WHERE [c].[CustomerID] LIKE N'A%' -ORDER BY [c].[CustomerID]", - // - @"SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT DISTINCT [c0].[CustomerID] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] LIKE N'A%' -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] + @"SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[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 [Customers] AS [c] + WHERE [c].[CustomerID] LIKE N'A%' +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[CustomerID]"); } @@ -1477,19 +1109,11 @@ public override void Include_collection_OrderBy_object(bool useString) base.Include_collection_OrderBy_object(useString); AssertSql( - @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] + @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o0].[OrderID], [o0].[ProductID], [o0].[Discount], [o0].[Quantity], [o0].[UnitPrice] FROM [Orders] AS [o] +LEFT JOIN [Order Details] AS [o0] ON [o].[OrderID] = [o0].[OrderID] WHERE [o].[OrderID] < 10250 -ORDER BY [o].[OrderID]", - // - @"SELECT [o.OrderDetails].[OrderID], [o.OrderDetails].[ProductID], [o.OrderDetails].[Discount], [o.OrderDetails].[Quantity], [o.OrderDetails].[UnitPrice] -FROM [Order Details] AS [o.OrderDetails] -INNER JOIN ( - SELECT [o0].[OrderID] - FROM [Orders] AS [o0] - WHERE [o0].[OrderID] < 10250 -) AS [t] ON [o.OrderDetails].[OrderID] = [t].[OrderID] -ORDER BY [t].[OrderID]"); +ORDER BY [o].[OrderID]"); } public override void Include_collection_OrderBy_empty_list_contains(bool useString) @@ -1553,29 +1177,21 @@ public override void Include_collection_OrderBy_list_contains(bool useString) AssertSql( @"@__p_1='1' -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].[CustomerID] LIKE N'A%' -ORDER BY CASE - WHEN [c].[CustomerID] IN (N'ALFKI') - THEN CAST(1 AS bit) ELSE CAST(0 AS bit) -END, [c].[CustomerID] -OFFSET @__p_1 ROWS", - // - @"@__p_1='1' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID], CASE - WHEN [c0].[CustomerID] IN (N'ALFKI') - THEN CAST(1 AS bit) ELSE CAST(0 AS bit) +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [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], CASE + WHEN [c].[CustomerID] IN (N'ALFKI') THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END AS [c] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] LIKE N'A%' - ORDER BY [c], [c0].[CustomerID] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] LIKE N'A%' + ORDER BY CASE + WHEN [c].[CustomerID] IN (N'ALFKI') THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) + END, [c].[CustomerID] OFFSET @__p_1 ROWS -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[c], [t].[CustomerID]"); } @@ -1586,38 +1202,26 @@ public override void Include_collection_OrderBy_list_does_not_contains(bool useS AssertSql( @"@__p_1='1' -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].[CustomerID] LIKE N'A%' -ORDER BY CASE - WHEN [c].[CustomerID] NOT IN (N'ALFKI') - THEN CAST(1 AS bit) ELSE CAST(0 AS bit) -END, [c].[CustomerID] -OFFSET @__p_1 ROWS", - // - @"@__p_1='1' - -SELECT [c.Orders].[OrderID], [c.Orders].[CustomerID], [c.Orders].[EmployeeID], [c.Orders].[OrderDate] -FROM [Orders] AS [c.Orders] -INNER JOIN ( - SELECT [c0].[CustomerID], CASE - WHEN [c0].[CustomerID] NOT IN (N'ALFKI') - THEN CAST(1 AS bit) ELSE CAST(0 AS bit) +SELECT [t].[CustomerID], [t].[Address], [t].[City], [t].[CompanyName], [t].[ContactName], [t].[ContactTitle], [t].[Country], [t].[Fax], [t].[Phone], [t].[PostalCode], [t].[Region], [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], CASE + WHEN [c].[CustomerID] NOT IN (N'ALFKI') THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END AS [c] - FROM [Customers] AS [c0] - WHERE [c0].[CustomerID] LIKE N'A%' - ORDER BY [c], [c0].[CustomerID] + FROM [Customers] AS [c] + WHERE [c].[CustomerID] LIKE N'A%' + ORDER BY CASE + WHEN [c].[CustomerID] NOT IN (N'ALFKI') THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) + END, [c].[CustomerID] OFFSET @__p_1 ROWS -) AS [t] ON [c.Orders].[CustomerID] = [t].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] ORDER BY [t].[c], [t].[CustomerID]"); } private void AssertSql(params string[] expected) - // issue #15064 - //=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected); - { - return; - } + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); protected override void ClearLog() => Fixture.TestSqlLoggerFactory.Clear();