From ac35072368f35a476b5a4b38eeae61b0984cc523 Mon Sep 17 00:00:00 2001 From: maumar Date: Tue, 1 Feb 2022 17:57:21 -0800 Subject: [PATCH] Temporal table support for owned and table splitting scenarios Fix to #26858 - Query: improve TableExpressionBase extensibility by adding annotations Fix to #26469 - Query: enable temporal tables for table splitting scenarios Fix to #26451 - Temporal Table: Owned Entities support? Added annotation infra for TableExpressionBase and annotations for temporal table information. Removed (now unnecessary) temporal specific table expressions. Also added temporal table support for owned typed and table splitting in general using the annotations to store the temporal information (no need for provider specific logic in places where we didn't have good extensibility) For table splitting, every entity must explicitly define period start/end columns. They all need to be the same, but if not explicitly provided we try to uniquefy them. We should fix this so that you only need to specify it in one place but it's currently hard to do (hopefully convention layering will make it easier) --- ...yableMethodTranslatingExpressionVisitor.cs | 85 +- .../SqlExpressions/CrossApplyExpression.cs | 12 +- .../SqlExpressions/CrossJoinExpression.cs | 12 +- .../Query/SqlExpressions/ExceptExpression.cs | 22 +- .../Query/SqlExpressions/FromSqlExpression.cs | 19 +- .../SqlExpressions/InnerJoinExpression.cs | 15 +- .../SqlExpressions/IntersectExpression.cs | 22 +- .../SqlExpressions/JoinExpressionBase.cs | 14 +- .../SqlExpressions/LeftJoinExpression.cs | 15 +- .../SqlExpressions/OuterApplyExpression.cs | 12 +- .../PredicateJoinExpressionBase.cs | 18 +- .../SqlExpressions/SelectExpression.Helper.cs | 2 +- .../Query/SqlExpressions/SelectExpression.cs | 18 +- .../Query/SqlExpressions/SetOperationBase.cs | 22 +- .../Query/SqlExpressions/TableExpression.cs | 16 +- .../SqlExpressions/TableExpressionBase.cs | 202 +- .../TableValuedFunctionExpression.cs | 20 +- .../Query/SqlExpressions/UnionExpression.cs | 22 +- .../Internal/SqlServerModelValidator.cs | 63 +- .../SqlServerConventionSetBuilder.cs | 17 +- .../Internal/SqlServerAnnotationNames.cs | 32 + .../Properties/SqlServerStrings.Designer.cs | 31 + .../Properties/SqlServerStrings.resx | 6 + ...rNavigationExpansionExtensibilityHelper.cs | 48 +- .../Internal/SqlServerQuerySqlGenerator.cs | 131 +- ...yableMethodTranslatingExpressionVisitor.cs | 141 +- .../SqlServerSqlNullabilityProcessor.cs | 17 +- .../Internal/TemporalAllTableExpression.cs | 2 + .../Internal/TemporalAsOfTableExpression.cs | 1 + .../TemporalBetweenTableExpression.cs | 1 + .../TemporalContainedInTableExpression.cs | 1 + .../Internal/TemporalFromToTableExpression.cs | 1 + .../Query/Internal/TemporalOperationType.cs | 54 + .../Internal/TemporalRangeTableExpression.cs | 1 + .../Query/Internal/TemporalTableExpression.cs | 1 + .../Builders/OwnedNavigationBuilder.cs | 26 + ...INavigationExpansionExtensibilityHelper.cs | 7 + ...ingExpressionVisitor.ExpressionVisitors.cs | 9 +- .../NavigationExpansionExtensibilityHelper.cs | 5 + .../Query/OwnedQueryCosmosTest.cs | 3 +- .../Query/OwnedQueryTestBase.cs | 21 +- .../Query/OwnedQuerySqlServerTest.cs | 10 +- ...CollectionsSharedTypeQuerySqlServerTest.cs | 3969 ++++++++++++++++- ...igationsSharedTypeQuerySqlServerFixture.cs | 91 +- .../Query/TemporalTableSqlServerTest.cs | 526 +++ .../SqlServerModelValidatorTest.cs | 15 +- .../SqlServerModelBuilderGenericTest.cs | 81 +- 47 files changed, 5704 insertions(+), 155 deletions(-) create mode 100644 src/EFCore.SqlServer/Query/Internal/TemporalOperationType.cs create mode 100644 test/EFCore.SqlServer.FunctionalTests/Query/TemporalTableSqlServerTest.cs diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 4562466f863..0abb4772ae9 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -1155,7 +1155,10 @@ private sealed class SharedTypeEntityExpandingExpressionVisitor : ExpressionVisi { private static readonly MethodInfo _objectEqualsMethodInfo = typeof(object).GetRequiredRuntimeMethod(nameof(object.Equals), typeof(object), typeof(object)); - private static readonly bool _useOldBehavior = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26592", out var enabled) + private static readonly bool _useOldBehavior26592 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26592", out var enabled) + && enabled; + + private static readonly bool _useOldBehavior26469 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled) && enabled; private readonly RelationalSqlTranslatingExpressionVisitor _sqlTranslator; @@ -1178,7 +1181,7 @@ public Expression Expand(SelectExpression selectExpression, Expression lambdaBod { _selectExpression = selectExpression; - if (_useOldBehavior) + if (_useOldBehavior26592) { return Visit(lambdaBody); } @@ -1225,7 +1228,7 @@ protected override Expression VisitExtension(Expression extensionExpression) private Expression? TryExpand(Expression? source, MemberIdentity member) { - if (_useOldBehavior) + if (_useOldBehavior26592) { source = source.UnwrapTypeConversion(out var convertedType); if (source is not EntityShaperExpression entityShaperExpression) @@ -1435,11 +1438,26 @@ outerKey is NewArrayExpression newArrayExpression return null; } + var entityProjectionExpression = GetEntityProjectionExpression(entityShaperExpression); var foreignKey = navigation.ForeignKey; if (navigation.IsCollection) { + SelectExpression innerSelectExpression; + + + if (!_useOldBehavior26469) + { + innerSelectExpression = BuildInnerSelectExpressionForOwnedTypeMappedToDifferentTable( + entityProjectionExpression, + navigation); + } + else + { + innerSelectExpression = _sqlExpressionFactory.Select(targetEntityType); + } + var innerShapedQuery = CreateShapedQueryExpression( - targetEntityType, _sqlExpressionFactory.Select(targetEntityType)); + targetEntityType, innerSelectExpression); var makeNullable = foreignKey.PrincipalKey.Properties .Concat(foreignKey.Properties) @@ -1487,7 +1505,6 @@ outerKey is NewArrayExpression newArrayExpression Expression.Quote(correlationPredicate)); } - var entityProjectionExpression = GetEntityProjectionExpression(entityShaperExpression); var innerShaper = entityProjectionExpression.BindNavigation(navigation); if (innerShaper == null) { @@ -1530,7 +1547,19 @@ outerKey is NewArrayExpression newArrayExpression // Owned types don't support inheritance See https://github.com/dotnet/efcore/issues/9630 // So there is no handling for dependent having TPT table = targetEntityType.GetViewOrTableMappings().Single().Table; - var innerSelectExpression = _sqlExpressionFactory.Select(targetEntityType); + + SelectExpression innerSelectExpression; + if (!_useOldBehavior26469) + { + innerSelectExpression = BuildInnerSelectExpressionForOwnedTypeMappedToDifferentTable( + entityProjectionExpression, + navigation); + } + else + { + innerSelectExpression = _sqlExpressionFactory.Select(targetEntityType); + } + var innerShapedQuery = CreateShapedQueryExpression(targetEntityType, innerSelectExpression); var makeNullable = foreignKey.PrincipalKey.Properties @@ -1584,6 +1613,50 @@ outerKey is NewArrayExpression newArrayExpression : new DeferredOwnedExpansionExpression(targetEntityType, (ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression, navigation); + + SelectExpression BuildInnerSelectExpressionForOwnedTypeMappedToDifferentTable( + EntityProjectionExpression entityProjectionExpression, + INavigation navigation) + { + // just need any column - we use it only to extract the table it originated from + var sourceColumn = entityProjectionExpression + .BindProperty( + navigation.IsOnDependent + ? foreignKey.Properties[0] + : foreignKey.PrincipalKey.Properties[0]); + + var sourceTable = FindRootTableExpressionForColumn(sourceColumn); + var ownedTable = new TableExpression(targetEntityType.GetTableMappings().Single().Table); + + foreach (var annotation in sourceTable.GetAnnotations()) + { + ownedTable.SetAnnotation(annotation.Name, annotation.Value); + } + + return _sqlExpressionFactory.Select(targetEntityType, ownedTable); + } + + static TableExpressionBase FindRootTableExpressionForColumn(ColumnExpression column) + { + var table = column.Table; + if (table is JoinExpressionBase joinExpressionBase) + { + table = joinExpressionBase.Table; + } + else if (table is SetOperationBase setOperationBase) + { + table = setOperationBase.Source1; + } + + if (table is SelectExpression selectExpression) + { + var matchingProjection = (ColumnExpression)selectExpression.Projection.Where(p => p.Alias == column.Name).Single().Expression; + + return FindRootTableExpressionForColumn(matchingProjection); + } + + return table; + } } } diff --git a/src/EFCore.Relational/Query/SqlExpressions/CrossApplyExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/CrossApplyExpression.cs index 8f01d755345..9db3f2d5157 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/CrossApplyExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/CrossApplyExpression.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -22,7 +24,12 @@ public class CrossApplyExpression : JoinExpressionBase /// /// A table source to CROSS APPLY with. public CrossApplyExpression(TableExpressionBase table) - : base(table) + : this(table, annotations: null) + { + } + + private CrossApplyExpression(TableExpressionBase table, IEnumerable? annotations) + : base(table, annotations) { } @@ -45,7 +52,7 @@ public virtual CrossApplyExpression Update(TableExpressionBase table) Check.NotNull(table, nameof(table)); return table != Table - ? new CrossApplyExpression(table) + ? new CrossApplyExpression(table, GetAnnotations()) : this; } @@ -56,6 +63,7 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Append("CROSS APPLY "); expressionPrinter.Visit(Table); + PrintAnnotations(expressionPrinter); } /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/CrossJoinExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/CrossJoinExpression.cs index ef3959596d6..adea611223e 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/CrossJoinExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/CrossJoinExpression.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -22,7 +24,12 @@ public class CrossJoinExpression : JoinExpressionBase /// /// A table source to CROSS JOIN with. public CrossJoinExpression(TableExpressionBase table) - : base(table) + : this(table, annotations: null) + { + } + + private CrossJoinExpression(TableExpressionBase table, IEnumerable? annotations) + : base(table, annotations) { } @@ -45,7 +52,7 @@ public virtual CrossJoinExpression Update(TableExpressionBase table) Check.NotNull(table, nameof(table)); return table != Table - ? new CrossJoinExpression(table) + ? new CrossJoinExpression(table, GetAnnotations()) : this; } @@ -56,6 +63,7 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Append("CROSS JOIN "); expressionPrinter.Visit(Table); + PrintAnnotations(expressionPrinter); } /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/ExceptExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/ExceptExpression.cs index 6efe26ae532..156ba870771 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/ExceptExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/ExceptExpression.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -30,7 +32,17 @@ public ExceptExpression( SelectExpression source1, SelectExpression source2, bool distinct) - : base(alias, source1, source2, distinct) + : this(alias, source1, source2, distinct, annotations: null) + { + } + + private ExceptExpression( + string alias, + SelectExpression source1, + SelectExpression source2, + bool distinct, + IEnumerable? annotations) + : base(alias, source1, source2, distinct, annotations) { } @@ -58,7 +70,7 @@ public virtual ExceptExpression Update(SelectExpression source1, SelectExpressio Check.NotNull(source2, nameof(source2)); return source1 != Source1 || source2 != Source2 - ? new ExceptExpression(Alias, source1, source2, IsDistinct) + ? new ExceptExpression(Alias, source1, source2, IsDistinct, GetAnnotations()) : this; } @@ -81,8 +93,10 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Visit(Source2); } - expressionPrinter.AppendLine() - .AppendLine($") AS {Alias}"); + expressionPrinter.AppendLine(); + expressionPrinter.Append(")"); + PrintAnnotations(expressionPrinter); + expressionPrinter.AppendLine($" AS {Alias}"); } /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/FromSqlExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/FromSqlExpression.cs index 297e186e411..5394f8b52f7 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/FromSqlExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/FromSqlExpression.cs @@ -2,8 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -43,7 +45,16 @@ public FromSqlExpression(string sql, Expression arguments, string alias) /// A user-provided custom SQL for the table source. /// A user-provided parameters to pass to the custom SQL. public FromSqlExpression(string alias, string sql, Expression arguments) - : base(alias) + : this(alias, sql, arguments, annotations: null) + { + } + + private FromSqlExpression( + string alias, + string sql, + Expression arguments, + IEnumerable? annotations) + : base(alias, annotations) { Check.NotEmpty(sql, nameof(sql)); Check.NotNull(arguments, nameof(arguments)); @@ -52,6 +63,7 @@ public FromSqlExpression(string alias, string sql, Expression arguments) Arguments = arguments; } + /// /// The alias assigned to this table source. /// @@ -83,7 +95,7 @@ public virtual FromSqlExpression Update(Expression arguments) Check.NotNull(arguments, nameof(arguments)); return arguments != Arguments - ? new FromSqlExpression(Alias, Sql, arguments) + ? new FromSqlExpression(Alias, Sql, arguments, GetAnnotations()) : this; } @@ -97,7 +109,7 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) /// public virtual TableExpressionBase Clone() - => new FromSqlExpression(Alias, Sql, Arguments); + => new FromSqlExpression(Alias, Sql, Arguments, GetAnnotations()); /// protected override void Print(ExpressionPrinter expressionPrinter) @@ -105,6 +117,7 @@ protected override void Print(ExpressionPrinter expressionPrinter) Check.NotNull(expressionPrinter, nameof(expressionPrinter)); expressionPrinter.Append(Sql); + PrintAnnotations(expressionPrinter); } /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/InnerJoinExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/InnerJoinExpression.cs index d248fbe49bb..6e4727e7abd 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/InnerJoinExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/InnerJoinExpression.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -23,7 +25,15 @@ public class InnerJoinExpression : PredicateJoinExpressionBase /// A table source to INNER JOIN with. /// A predicate to use for the join. public InnerJoinExpression(TableExpressionBase table, SqlExpression joinPredicate) - : base(table, joinPredicate) + : this(table, joinPredicate, annotations: null) + { + } + + private InnerJoinExpression( + TableExpressionBase table, + SqlExpression joinPredicate, + IEnumerable? annotations) + : base(table, joinPredicate, annotations) { } @@ -51,7 +61,7 @@ public virtual InnerJoinExpression Update(TableExpressionBase table, SqlExpressi Check.NotNull(joinPredicate, nameof(joinPredicate)); return table != Table || joinPredicate != JoinPredicate - ? new InnerJoinExpression(table, joinPredicate) + ? new InnerJoinExpression(table, joinPredicate, GetAnnotations()) : this; } @@ -64,6 +74,7 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Visit(Table); expressionPrinter.Append(" ON "); expressionPrinter.Visit(JoinPredicate); + PrintAnnotations(expressionPrinter); } /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/IntersectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/IntersectExpression.cs index 012d8cc875b..91e1cf27194 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/IntersectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/IntersectExpression.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -30,7 +32,17 @@ public IntersectExpression( SelectExpression source1, SelectExpression source2, bool distinct) - : base(alias, source1, source2, distinct) + : this(alias, source1, source2, distinct, annotations: null) + { + } + + private IntersectExpression( + string alias, + SelectExpression source1, + SelectExpression source2, + bool distinct, + IEnumerable? annotations) + : base(alias, source1, source2, distinct, annotations) { } @@ -58,7 +70,7 @@ public virtual IntersectExpression Update(SelectExpression source1, SelectExpres Check.NotNull(source2, nameof(source2)); return source1 != Source1 || source2 != Source2 - ? new IntersectExpression(Alias, source1, source2, IsDistinct) + ? new IntersectExpression(Alias, source1, source2, IsDistinct, GetAnnotations()) : this; } @@ -81,8 +93,10 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Visit(Source2); } - expressionPrinter.AppendLine() - .AppendLine($") AS {Alias}"); + expressionPrinter.AppendLine(); + expressionPrinter.Append(")"); + PrintAnnotations(expressionPrinter); + expressionPrinter.AppendLine($" AS {Alias}"); } /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/JoinExpressionBase.cs b/src/EFCore.Relational/Query/SqlExpressions/JoinExpressionBase.cs index 9aa12c54ab1..ba097fd8327 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/JoinExpressionBase.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/JoinExpressionBase.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -22,7 +24,17 @@ public abstract class JoinExpressionBase : TableExpressionBase /// /// A table source to join with. protected JoinExpressionBase(TableExpressionBase table) - : base(null) + : this(table, annotations: null) + { + } + + /// + /// Creates a new instance of the class. + /// + /// A table source to join with. + /// A collection of annotations associated with this expression. + protected JoinExpressionBase(TableExpressionBase table, IEnumerable? annotations) + : base(alias: null, annotations) { Check.NotNull(table, nameof(table)); diff --git a/src/EFCore.Relational/Query/SqlExpressions/LeftJoinExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/LeftJoinExpression.cs index fd545ad5052..772de63af5c 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/LeftJoinExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/LeftJoinExpression.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -23,7 +25,15 @@ public class LeftJoinExpression : PredicateJoinExpressionBase /// A table source to LEFT JOIN with. /// A predicate to use for the join. public LeftJoinExpression(TableExpressionBase table, SqlExpression joinPredicate) - : base(table, joinPredicate) + : this(table, joinPredicate, annotations: null) + { + } + + private LeftJoinExpression( + TableExpressionBase table, + SqlExpression joinPredicate, + IEnumerable? annotations) + : base(table, joinPredicate, annotations) { } @@ -51,7 +61,7 @@ public virtual LeftJoinExpression Update(TableExpressionBase table, SqlExpressio Check.NotNull(joinPredicate, nameof(joinPredicate)); return table != Table || joinPredicate != JoinPredicate - ? new LeftJoinExpression(table, joinPredicate) + ? new LeftJoinExpression(table, joinPredicate, GetAnnotations()) : this; } @@ -64,6 +74,7 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Visit(Table); expressionPrinter.Append(" ON "); expressionPrinter.Visit(JoinPredicate); + PrintAnnotations(expressionPrinter); } /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/OuterApplyExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/OuterApplyExpression.cs index 7e708aa63c0..7aa13728dc5 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/OuterApplyExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/OuterApplyExpression.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -22,7 +24,12 @@ public class OuterApplyExpression : JoinExpressionBase /// /// A table source to OUTER APPLY with. public OuterApplyExpression(TableExpressionBase table) - : base(table) + : this(table, annotations: null) + { + } + + private OuterApplyExpression(TableExpressionBase table, IEnumerable? annotations) + : base(table, annotations) { } @@ -45,7 +52,7 @@ public virtual OuterApplyExpression Update(TableExpressionBase table) Check.NotNull(table, nameof(table)); return table != Table - ? new OuterApplyExpression(table) + ? new OuterApplyExpression(table, GetAnnotations()) : this; } @@ -56,6 +63,7 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Append("OUTER APPLY "); expressionPrinter.Visit(Table); + PrintAnnotations(expressionPrinter); } /// diff --git a/src/EFCore.Relational/Query/SqlExpressions/PredicateJoinExpressionBase.cs b/src/EFCore.Relational/Query/SqlExpressions/PredicateJoinExpressionBase.cs index 8a854fc927f..4aac17996f9 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/PredicateJoinExpressionBase.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/PredicateJoinExpressionBase.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -23,7 +25,21 @@ public abstract class PredicateJoinExpressionBase : JoinExpressionBase /// A table source to join with. /// A predicate to use for the join. protected PredicateJoinExpressionBase(TableExpressionBase table, SqlExpression joinPredicate) - : base(table) + : this(table, joinPredicate, annotations: null) + { + } + + /// + /// Creates a new instance of the class. + /// + /// A table source to join with. + /// A predicate to use for the join. + /// A collection of annotations associated with this expression. + protected PredicateJoinExpressionBase( + TableExpressionBase table, + SqlExpression joinPredicate, + IEnumerable? annotations) + : base(table, annotations) { Check.NotNull(joinPredicate, nameof(joinPredicate)); diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.Helper.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.Helper.cs index 051eceb7b5e..0884c9141c8 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.Helper.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.Helper.cs @@ -785,7 +785,7 @@ private sealed class CloningExpressionVisitor : ExpressionVisitor var groupingCorrelationPredicate = (SqlExpression?)Visit(selectExpression._groupingCorrelationPredicate); var newSelectExpression = new SelectExpression( - selectExpression.Alias, newProjections, newTables, newTableReferences, newGroupBy, newOrderings) + selectExpression.Alias, newProjections, newTables, newTableReferences, newGroupBy, newOrderings, selectExpression.GetAnnotations()) { Predicate = predicate, Having = havingExpression, diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index 58c7662a5cc..fde3a0f0b87 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -72,8 +72,9 @@ private SelectExpression( List tables, List tableReferences, List groupBy, - List orderings) - : base(alias) + List orderings, + IEnumerable annotations) + : base(alias, annotations) { _projection = projections; _tables = tables; @@ -1493,7 +1494,7 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi { // TODO: Introduce clone method? See issue#24460 var select1 = new SelectExpression( - null, new List(), _tables.ToList(), _tableReferences.ToList(), _groupBy.ToList(), _orderings.ToList()) + null, new List(), _tables.ToList(), _tableReferences.ToList(), _groupBy.ToList(), _orderings.ToList(), GetAnnotations()) { IsDistinct = IsDistinct, Predicate = Predicate, @@ -1799,7 +1800,8 @@ public void ApplyDefaultIfEmpty(ISqlExpressionFactory sqlExpressionFactory) new List(), new List(), new List(), - new List()); + new List(), + Enumerable.Empty()); if (Orderings.Any() || Limit != null @@ -2883,7 +2885,7 @@ private SqlRemappingVisitor PushdownIntoSubqueryInternal() var subqueryAlias = GenerateUniqueAlias(_usedAliases, "t"); var subquery = new SelectExpression( subqueryAlias, new List(), _tables.ToList(), _tableReferences.ToList(), _groupBy.ToList(), - _orderings.ToList()) + _orderings.ToList(), GetAnnotations()) { IsDistinct = IsDistinct, Predicate = Predicate, @@ -3542,7 +3544,7 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) { var newTableReferences = _tableReferences.ToList(); var newSelectExpression = new SelectExpression( - Alias, newProjections, newTables, newTableReferences, newGroupBy, newOrderings) + Alias, newProjections, newTables, newTableReferences, newGroupBy, newOrderings, GetAnnotations()) { _clientProjections = _clientProjections, _projectionMapping = _projectionMapping, @@ -3664,7 +3666,7 @@ public SelectExpression Update( var newTableReferences = _tableReferences.ToList(); var newSelectExpression = new SelectExpression( - alias, projections.ToList(), tables.ToList(), newTableReferences, groupBy.ToList(), orderings.ToList()) + alias, projections.ToList(), tables.ToList(), newTableReferences, groupBy.ToList(), orderings.ToList(), GetAnnotations()) { _projectionMapping = projectionMapping, _clientProjections = _clientProjections.ToList(), @@ -3851,6 +3853,8 @@ protected override void Print(ExpressionPrinter expressionPrinter) } } + PrintAnnotations(expressionPrinter); + if (Alias != null) { indent?.Dispose(); diff --git a/src/EFCore.Relational/Query/SqlExpressions/SetOperationBase.cs b/src/EFCore.Relational/Query/SqlExpressions/SetOperationBase.cs index c47e9f8e821..7b50c876358 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SetOperationBase.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SetOperationBase.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -30,7 +32,25 @@ protected SetOperationBase( SelectExpression source1, SelectExpression source2, bool distinct) - : base(Check.NotEmpty(alias, nameof(alias))) + : this(alias, source1, source2, distinct, annotations: null) + { + } + + /// + /// Creates a new instance of the class. + /// + /// A string alias for the table source. + /// A table source which is first source in the set operation. + /// A table source which is second source in the set operation. + /// A bool value indicating whether result will remove duplicate rows. + /// Collection of annotations associated with this expression. + protected SetOperationBase( + string alias, + SelectExpression source1, + SelectExpression source2, + bool distinct, + IEnumerable? annotations) + : base(Check.NotEmpty(alias, nameof(alias)), annotations) { Check.NotNull(source1, nameof(source1)); Check.NotNull(source2, nameof(source2)); diff --git a/src/EFCore.Relational/Query/SqlExpressions/TableExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/TableExpression.cs index 2c33e4c358a..f7b814d3880 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/TableExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/TableExpression.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; @@ -21,7 +23,12 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions public sealed class TableExpression : TableExpressionBase, IClonableTableExpressionBase { internal TableExpression(ITableBase table) - : base(table.Name.Substring(0, 1).ToLowerInvariant()) + : this(table, null) + { + } + + private TableExpression(ITableBase table, IEnumerable? annotations) + : base(alias: table.Name.Substring(0, 1).ToLowerInvariant(), annotations) { Name = table.Name; Schema = table.Schema; @@ -38,7 +45,10 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Append(Schema).Append("."); } - expressionPrinter.Append(Name).Append(" AS ").Append(Alias); + expressionPrinter.Append(Name); + PrintAnnotations(expressionPrinter); + + expressionPrinter.Append(" AS ").Append(Alias); } /// @@ -68,7 +78,7 @@ public override string? Alias /// public TableExpressionBase Clone() - => new TableExpression(Table) { Alias = Alias }; + => new TableExpression(Table, GetAnnotations()) { Alias = Alias }; /// public override bool Equals(object? obj) diff --git a/src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs b/src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs index 4f3944e8777..933259c5f5b 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs @@ -2,7 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -16,19 +22,40 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions /// not used in application code. /// /// - public abstract class TableExpressionBase : Expression, IPrintableExpression + public abstract class TableExpressionBase : Expression, IPrintableExpression, IMutableAnnotatable { + private SortedDictionary? _annotations; + /// /// Creates a new instance of the class. /// /// A string alias for the table source. protected TableExpressionBase(string? alias) + : this(alias, annotations: null) { Check.NullButNotEmpty(alias, nameof(alias)); Alias = alias; } + /// + /// Creates a new instance of the class. + /// + /// A string alias for the table source. + /// A collection of annotations associated with this expression. + protected TableExpressionBase(string? alias, IEnumerable? annotations) + { + Alias = alias; + + if (annotations != null) + { + foreach (var annotation in annotations) + { + SetAnnotation(annotation.Name, annotation.Value); + } + } + } + /// /// The alias assigned to this table source. /// @@ -50,6 +77,33 @@ public override Type Type public sealed override ExpressionType NodeType => ExpressionType.Extension; + /// + /// Gets the value annotation with the given name, returning if it does not exist. + /// + /// The key of the annotation to find. + /// + /// The value of the existing annotation if an annotation with the specified name already exists. + /// Otherwise, . + /// + public virtual object? this[string name] + { + get => FindAnnotation(name)?.Value; + + set + { + Check.NotEmpty(name, nameof(name)); + + if (value == null) + { + RemoveAnnotation(name); + } + else + { + SetAnnotation(name, value); + } + } + } + /// /// Creates a printable string representation of the given expression using . /// @@ -60,6 +114,21 @@ public sealed override ExpressionType NodeType void IPrintableExpression.Print(ExpressionPrinter expressionPrinter) => Print(expressionPrinter); + /// + /// Creates a printable string representation of annotations associated with the given expression using . + /// + /// The expression printer to use. + protected virtual void PrintAnnotations(ExpressionPrinter expressionPrinter) + { + var annotations = GetAnnotations(); + if (annotations.Any()) + { + expressionPrinter.Append("["); + expressionPrinter.Append(annotations.Select(a => a.Name + "=" + a.Value).Join(" | ")); + expressionPrinter.Append("]"); + } + } + /// public override bool Equals(object? obj) => obj != null @@ -73,5 +142,136 @@ private bool Equals(TableExpressionBase tableExpressionBase) /// public override int GetHashCode() => HashCode.Combine(Alias); + + /// + /// Adds an annotation to this object. Throws if an annotation with the specified name already exists. + /// + /// The key of the annotation to be added. + /// The value to be stored in the annotation. + /// The newly added annotation. + public virtual Annotation AddAnnotation(string name, object? value) + => AddAnnotation(name, new(name, value)); + + /// + /// Adds an annotation to this object. Throws if an annotation with the specified name already exists. + /// + /// The key of the annotation to be added. + /// The annotation to be added. + /// The added annotation. + protected virtual Annotation AddAnnotation(string name, Annotation annotation) + { + if (FindAnnotation(name) != null) + { + throw new InvalidOperationException(CoreStrings.DuplicateAnnotation(name, ToString())); + } + + SetAnnotation(name, annotation, oldAnnotation: null); + + return annotation; + } + + /// + /// Sets the annotation stored under the given key. Overwrites the existing annotation if an + /// annotation with the specified name already exists. + /// + /// The key of the annotation to be added. + /// The value to be stored in the annotation. + public virtual void SetAnnotation(string name, object? value) + { + var oldAnnotation = FindAnnotation(name); + if (oldAnnotation != null + && Equals(oldAnnotation.Value, value)) + { + return; + } + + SetAnnotation(name, new(name, value), oldAnnotation); + } + + /// + /// Sets the annotation stored under the given key. Overwrites the existing annotation if an + /// annotation with the specified name already exists. + /// + /// The key of the annotation to be added. + /// The annotation to be set. + /// The annotation being replaced. + /// The annotation that was set. + protected virtual Annotation? SetAnnotation( + string name, + Annotation annotation, + Annotation? oldAnnotation) + { + _annotations ??= new SortedDictionary(StringComparer.Ordinal); + _annotations[name] = annotation; + + return annotation; + } + + /// + /// Removes the given annotation from this object. + /// + /// The annotation to remove. + /// The annotation that was removed. + public virtual Annotation? RemoveAnnotation(string name) + { + var annotation = FindAnnotation(name); + if (annotation == null) + { + return null; + } + + _annotations!.Remove(name); + + if (_annotations.Count == 0) + { + _annotations = null; + } + + return annotation; + } + + /// + /// Gets the annotation with the given name, returning if it does not exist. + /// + /// The key of the annotation to find. + /// + /// The existing annotation if an annotation with the specified name already exists. Otherwise, . + /// + public virtual Annotation? FindAnnotation(string name) + { + Check.NotEmpty(name, nameof(name)); + + return _annotations == null + ? null + : _annotations.TryGetValue(name, out var annotation) + ? annotation + : null; + } + + /// + /// Gets all annotations on the current object. + /// + public virtual IEnumerable GetAnnotations() + => _annotations?.Values ?? Enumerable.Empty(); + + /// + [DebuggerStepThrough] + IAnnotation IMutableAnnotatable.AddAnnotation(string name, object? value) + => AddAnnotation(name, value); + + /// + [DebuggerStepThrough] + IAnnotation? IMutableAnnotatable.RemoveAnnotation(string name) + => RemoveAnnotation(name); + + /// + [DebuggerStepThrough] + void IMutableAnnotatable.SetOrRemoveAnnotation(string name, object? value) + => this[name] = value; + + /// + [DebuggerStepThrough] + IAnnotation? IReadOnlyAnnotatable.FindAnnotation(string name) + => FindAnnotation(name); } } diff --git a/src/EFCore.Relational/Query/SqlExpressions/TableValuedFunctionExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/TableValuedFunctionExpression.cs index 1800a6c4d44..6d47d13c542 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/TableValuedFunctionExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/TableValuedFunctionExpression.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; @@ -31,12 +32,17 @@ public TableValuedFunctionExpression(IStoreFunction storeFunction, IReadOnlyList : this( storeFunction.Name.Substring(0, 1).ToLowerInvariant(), Check.NotNull(storeFunction, nameof(storeFunction)), - Check.NotNull(arguments, nameof(arguments))) + Check.NotNull(arguments, nameof(arguments)), + annotations: null) { } - private TableValuedFunctionExpression(string alias, IStoreFunction storeFunction, IReadOnlyList arguments) - : base(alias) + private TableValuedFunctionExpression( + string alias, + IStoreFunction storeFunction, + IReadOnlyList arguments, + IEnumerable? annotations) + : base(alias, annotations) { StoreFunction = storeFunction; Arguments = arguments; @@ -76,7 +82,7 @@ protected override Expression VisitChildren(ExpressionVisitor visitor) } return changed - ? new TableValuedFunctionExpression(Alias, StoreFunction, arguments) + ? new TableValuedFunctionExpression(Alias, StoreFunction, arguments, GetAnnotations()) : this; } @@ -91,7 +97,7 @@ public virtual TableValuedFunctionExpression Update(IReadOnlyList Check.NotNull(arguments, nameof(arguments)); return !arguments.SequenceEqual(Arguments) - ? new TableValuedFunctionExpression(Alias, StoreFunction, arguments) + ? new TableValuedFunctionExpression(Alias, StoreFunction, arguments, GetAnnotations()) : this; } @@ -106,7 +112,9 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Append(StoreFunction.Name); expressionPrinter.Append("("); expressionPrinter.VisitCollection(Arguments); - expressionPrinter.Append(") AS "); + expressionPrinter.Append(")"); + PrintAnnotations(expressionPrinter); + expressionPrinter.Append(" AS "); expressionPrinter.Append(Alias); } diff --git a/src/EFCore.Relational/Query/SqlExpressions/UnionExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/UnionExpression.cs index 585303ea6b5..7244ff124c4 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/UnionExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/UnionExpression.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Linq.Expressions; +using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions @@ -30,7 +32,17 @@ public UnionExpression( SelectExpression source1, SelectExpression source2, bool distinct) - : base(alias, source1, source2, distinct) + : this(alias, source1, source2, distinct, annotations: null) + { + } + + private UnionExpression( + string alias, + SelectExpression source1, + SelectExpression source2, + bool distinct, + IEnumerable? annotations) + : base(alias, source1, source2, distinct, annotations) { } @@ -58,7 +70,7 @@ public virtual UnionExpression Update(SelectExpression source1, SelectExpression Check.NotNull(source2, nameof(source2)); return source1 != Source1 || source2 != Source2 - ? new UnionExpression(Alias, source1, source2, IsDistinct) + ? new UnionExpression(Alias, source1, source2, IsDistinct, GetAnnotations()) : this; } @@ -81,8 +93,10 @@ protected override void Print(ExpressionPrinter expressionPrinter) expressionPrinter.Visit(Source2); } - expressionPrinter.AppendLine() - .AppendLine($") AS {Alias}"); + expressionPrinter.AppendLine(); + expressionPrinter.Append(")"); + PrintAnnotations(expressionPrinter); + expressionPrinter.AppendLine($" AS {Alias}"); } /// diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerModelValidator.cs b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerModelValidator.cs index 28234ddc34b..d6ac9c3ce01 100644 --- a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerModelValidator.cs +++ b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerModelValidator.cs @@ -349,7 +349,68 @@ protected override void ValidateSharedTableCompatibility( if (mappedTypes.Any(t => t.IsTemporal()) && mappedTypes.Select(t => t.GetRootType()).Distinct().Count() > 1) { - throw new InvalidOperationException(SqlServerStrings.TemporalNotSupportedForTableSplitting(tableName)); + var useOldBehavior26469 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) + && enabled26469; + + if (useOldBehavior26469) + { + throw new InvalidOperationException(SqlServerStrings.TemporalNotSupportedForTableSplitting(tableName)); + } + + // table splitting is only supported when all entites mapped to this table + // have consistent temporal period mappings also + var expectedPeriodStartColumnName = default(string); + var expectedPeriodEndColumnName = default(string); + + foreach (var mappedType in mappedTypes.Where(t => t.BaseType == null)) + { + if (!mappedType.IsTemporal()) + { + throw new InvalidOperationException( + SqlServerStrings.TemporalAllEntitiesMappedToSameTableMustBeTemporal( + mappedType.DisplayName())); + } + + var periodStartPropertyName = mappedType.GetPeriodStartPropertyName(); + var periodEndPropertyName = mappedType.GetPeriodEndPropertyName(); + + var periodStartProperty = mappedType.GetProperty(periodStartPropertyName!); + var periodEndProperty = mappedType.GetProperty(periodEndPropertyName!); + + var storeObjectIdentifier = StoreObjectIdentifier.Table(tableName, mappedType.GetSchema()); + var periodStartColumnName = periodStartProperty.GetColumnName(storeObjectIdentifier); + var periodEndColumnName = periodEndProperty.GetColumnName(storeObjectIdentifier); + + if (expectedPeriodStartColumnName == null) + { + expectedPeriodStartColumnName = periodStartColumnName; + } + else if (expectedPeriodStartColumnName != periodStartColumnName) + { + throw new InvalidOperationException( + SqlServerStrings.TemporalNotSupportedForTableSplittingWithInconsistentPeriodMapping( + "start", + mappedType.DisplayName(), + periodStartPropertyName, + periodStartColumnName, + expectedPeriodStartColumnName)); + } + + if (expectedPeriodEndColumnName == null) + { + expectedPeriodEndColumnName = periodEndColumnName; + } + else if (expectedPeriodEndColumnName != periodEndColumnName) + { + throw new InvalidOperationException( + SqlServerStrings.TemporalNotSupportedForTableSplittingWithInconsistentPeriodMapping( + "end", + mappedType.DisplayName(), + periodEndPropertyName, + periodEndColumnName, + expectedPeriodEndColumnName)); + } + } } base.ValidateSharedTableCompatibility(mappedTypes, tableName, schema, logger); diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs index 96ac9408605..77f2e6d33ea 100644 --- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs +++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Storage; @@ -66,8 +67,22 @@ public override ConventionSet CreateConventionSet() var sqlServerInMemoryTablesConvention = new SqlServerMemoryOptimizedTablesConvention(Dependencies, RelationalDependencies); conventionSet.EntityTypeAnnotationChangedConventions.Add(sqlServerInMemoryTablesConvention); + + var useOldBehavior26469 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) && enabled26469; + if (!useOldBehavior26469) + { + ReplaceConvention( + conventionSet.ForeignKeyPropertiesChangedConventions, + (RelationalValueGenerationConvention)valueGenerationConvention); + + ReplaceConvention( + conventionSet.ForeignKeyOwnershipChangedConventions, + (RelationalValueGenerationConvention)valueGenerationConvention); + } + ReplaceConvention( - conventionSet.EntityTypeAnnotationChangedConventions, (RelationalValueGenerationConvention)valueGenerationConvention); + conventionSet.EntityTypeAnnotationChangedConventions, + (RelationalValueGenerationConvention)valueGenerationConvention); var sqlServerTemporalConvention = new SqlServerTemporalConvention(Dependencies, RelationalDependencies); ConventionSet.AddBefore( diff --git a/src/EFCore.SqlServer/Metadata/Internal/SqlServerAnnotationNames.cs b/src/EFCore.SqlServer/Metadata/Internal/SqlServerAnnotationNames.cs index 816c72c5975..ec8debb0d00 100644 --- a/src/EFCore.SqlServer/Metadata/Internal/SqlServerAnnotationNames.cs +++ b/src/EFCore.SqlServer/Metadata/Internal/SqlServerAnnotationNames.cs @@ -195,6 +195,38 @@ public static class SqlServerAnnotationNames /// public const string TemporalPeriodEndColumnName = Prefix + "TemporalPeriodEndColumnName"; + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public const string TemporalOperationType = Prefix + "TemporalOperationType"; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public const string TemporalAsOfPointInTime = Prefix + "TemporalAsOfPointInTime"; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public const string TemporalRangeOperationFrom = Prefix + "TemporalRangeOperationFrom"; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public const string TemporalRangeOperationTo = Prefix + "TemporalRangeOperationTo"; + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in diff --git a/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs b/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs index 23fd122e7e9..a6bc2070cb8 100644 --- a/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs +++ b/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs @@ -251,6 +251,29 @@ public static string TemporalNavigationExpansionOnlySupportedForAsOf(object? ope GetString("TemporalNavigationExpansionOnlySupportedForAsOf", nameof(operationName)), operationName); + /// + /// When multiple temporal entities are mapped to the same table, their period {periodType} properties must map to the same column. There is an issue with the entity type '{entityType}' with period property '{periodProperty}' which is mapped to column '{periodColumn}'. Expected period column name is '{expectedColumnName}'. + /// + public static string TemporalNotSupportedForTableSplittingWithInconsistentPeriodMapping( + object? periodType, + object? entityType, + object? periodProperty, + object? periodColumn, + object? expectedColumnName) + => string.Format( + GetString( + "TemporalNotSupportedForTableSplittingWithInconsistentPeriodMapping", + nameof(periodType), + nameof(entityType), + nameof(periodProperty), + nameof(periodColumn), + nameof(expectedColumnName)), + periodType, + entityType, + periodProperty, + periodColumn, + expectedColumnName); + /// /// Temporal tables are not supported for table splitting scenario. Table: '{table}'. /// @@ -259,6 +282,14 @@ public static string TemporalNotSupportedForTableSplitting(object? table) GetString("TemporalNotSupportedForTableSplitting", nameof(table)), table); + /// + /// Entity type '{entityType}' should be marked as temporal because it shares table mapping with another entity that has been marked as temporal. Alternatively, other entity types that share the same table must be non-temporal. + /// + public static string TemporalAllEntitiesMappedToSameTableMustBeTemporal(object? entityType) + => string.Format( + GetString("TemporalAllEntitiesMappedToSameTableMustBeTemporal", nameof(entityType)), + entityType); + /// /// Only root entity type should be marked as temporal. Entity type: '{entityType}'. /// diff --git a/src/EFCore.SqlServer/Properties/SqlServerStrings.resx b/src/EFCore.SqlServer/Properties/SqlServerStrings.resx index 5770c19ea28..bfd5cfc2338 100644 --- a/src/EFCore.SqlServer/Properties/SqlServerStrings.resx +++ b/src/EFCore.SqlServer/Properties/SqlServerStrings.resx @@ -295,9 +295,15 @@ Navigation expansion is only supported for '{operationName}' temporal operation. For other operations use join manually. + + When multiple temporal entities are mapped to the same table, their period {periodType} properties must map to the same column. Issue happens for entity type '{entityType}' with period property '{periodProperty}' which is mapped to column '{periodColumn}'. Expected period column name is '{expectedColumnName}'. + Temporal tables are not supported for table splitting scenario. Table: '{table}'. + + Entity type '{entityType}' should be marked as temporal because it shares table mapping with another entity that has been marked as temporal. Alternatively, other entity types that share the same table must be non-temporal. + Only root entity type should be marked as temporal. Entity type: '{entityType}'. diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerNavigationExpansionExtensibilityHelper.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerNavigationExpansionExtensibilityHelper.cs index eddcf7a5a18..76d22056594 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerNavigationExpansionExtensibilityHelper.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerNavigationExpansionExtensibilityHelper.cs @@ -35,25 +35,47 @@ public SqlServerNavigationExpansionExtensibilityHelper(NavigationExpansionExtens /// public override QueryRootExpression CreateQueryRoot(IEntityType entityType, QueryRootExpression? source) { - if (source is TemporalQueryRootExpression) + if (source is TemporalAsOfQueryRootExpression asOf) { - if (!entityType.GetRootType().IsTemporal()) - { - throw new InvalidOperationException( - SqlServerStrings.TemporalNavigationExpansionBetweenTemporalAndNonTemporal(entityType.DisplayName())); - } + // AsOf is the only temporal operation that can pass the validation + return source.QueryProvider != null + ? new TemporalAsOfQueryRootExpression(source.QueryProvider, entityType, asOf.PointInTime) + : new TemporalAsOfQueryRootExpression(entityType, asOf.PointInTime); + } + + return base.CreateQueryRoot(entityType, source); + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public override void ValidateQueryRootCreation(IEntityType entityType, QueryRootExpression? source) + { + var useOldBehavior26469 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) + && enabled26469; - if (source is TemporalAsOfQueryRootExpression asOf) + if (!useOldBehavior26469) + { + if (source is TemporalQueryRootExpression) { - return source.QueryProvider != null - ? new TemporalAsOfQueryRootExpression(source.QueryProvider, entityType, asOf.PointInTime) - : new TemporalAsOfQueryRootExpression(entityType, asOf.PointInTime); - } + if (!entityType.GetRootType().IsTemporal()) + { + throw new InvalidOperationException( + SqlServerStrings.TemporalNavigationExpansionBetweenTemporalAndNonTemporal(entityType.DisplayName())); + } - throw new InvalidOperationException(SqlServerStrings.TemporalNavigationExpansionOnlySupportedForAsOf("AsOf")); + if (source is not TemporalAsOfQueryRootExpression) + { + throw new InvalidOperationException( + SqlServerStrings.TemporalNavigationExpansionOnlySupportedForAsOf("AsOf")); + } + } } - return base.CreateQueryRoot(entityType, source); + base.ValidateQueryRootCreation(entityType, source); } /// diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs index 68bebe06218..803953ca48e 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Internal; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; @@ -110,55 +111,125 @@ protected override void GenerateLimitOffset(SelectExpression selectExpression) /// protected override Expression VisitExtension(Expression extensionExpression) { - if (extensionExpression is TemporalTableExpression temporalTableExpression) + var useOldBehavior26469 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) + && enabled26469; + + if (useOldBehavior26469) + { +#pragma warning disable CS0618 // Type or member is obsolete + if (extensionExpression is TemporalTableExpression temporalTableExpression) + { + Sql.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(temporalTableExpression.Name, temporalTableExpression.Schema)) + .Append(" FOR SYSTEM_TIME "); + + switch (temporalTableExpression) + { + case TemporalAsOfTableExpression asOf: + Sql.Append("AS OF ") + .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(asOf.PointInTime)); + break; + + case TemporalFromToTableExpression fromTo: + Sql.Append("FROM ") + .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(fromTo.From)) + .Append(" TO ") + .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(fromTo.To)); + break; + + case TemporalBetweenTableExpression between: + Sql.Append("BETWEEN ") + .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(between.From)) + .Append(" AND ") + .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(between.To)); + break; + + case TemporalContainedInTableExpression containedIn: + Sql.Append("CONTAINED IN (") + .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(containedIn.From)) + .Append(", ") + .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(containedIn.To)) + .Append(")"); + break; + + case TemporalAllTableExpression _: + Sql.Append("ALL"); + break; + + default: + throw new InvalidOperationException(temporalTableExpression.Print()); + } + + if (temporalTableExpression.Alias != null) + { + Sql.Append(AliasSeparator) + .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(temporalTableExpression.Alias)); + } + + return temporalTableExpression; + } +#pragma warning restore CS0618 // Type or member is obsolete + } + else if (extensionExpression is TableExpression tableExpression + && tableExpression.FindAnnotation(SqlServerAnnotationNames.TemporalOperationType) != null) { - Sql.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(temporalTableExpression.Name, temporalTableExpression.Schema)) + Sql.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(tableExpression.Name, tableExpression.Schema)) .Append(" FOR SYSTEM_TIME "); - switch (temporalTableExpression) + var temporalOperationType = (TemporalOperationType)tableExpression[SqlServerAnnotationNames.TemporalOperationType]!; + + switch (temporalOperationType) { - case TemporalAsOfTableExpression asOf: - Sql.Append("AS OF ") - .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(asOf.PointInTime)); + case TemporalOperationType.All: + Sql.Append("ALL"); break; - case TemporalFromToTableExpression fromTo: - Sql.Append("FROM ") - .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(fromTo.From)) - .Append(" TO ") - .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(fromTo.To)); - break; + case TemporalOperationType.AsOf: + var pointInTime = (DateTime)tableExpression[SqlServerAnnotationNames.TemporalAsOfPointInTime]!; - case TemporalBetweenTableExpression between: - Sql.Append("BETWEEN ") - .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(between.From)) - .Append(" AND ") - .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(between.To)); + Sql.Append("AS OF ") + .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(pointInTime)); break; - case TemporalContainedInTableExpression containedIn: - Sql.Append("CONTAINED IN (") - .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(containedIn.From)) - .Append(", ") - .Append(Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral(containedIn.To)) - .Append(")"); - break; + case TemporalOperationType.Between: + case TemporalOperationType.ContainedIn: + case TemporalOperationType.FromTo: + var from = Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral( + (DateTime)tableExpression[SqlServerAnnotationNames.TemporalRangeOperationFrom]!); + + var to = Sql.TypeMappingSource.GetMapping(typeof(DateTime)).GenerateSqlLiteral( + (DateTime)tableExpression[SqlServerAnnotationNames.TemporalRangeOperationTo]!); + + switch (temporalOperationType) + { + case TemporalOperationType.FromTo: + Sql.Append($"FROM {from} TO {to}"); + break; + + case TemporalOperationType.Between: + Sql.Append($"BETWEEN {from} AND {to}"); + break; + + case TemporalOperationType.ContainedIn: + Sql.Append($"CONTAINED IN ({from}, {to})"); + break; + + default: + throw new InvalidOperationException(tableExpression.Print()); + } - case TemporalAllTableExpression _: - Sql.Append("ALL"); break; default: - throw new InvalidOperationException(temporalTableExpression.Print()); + throw new InvalidOperationException(tableExpression.Print()); } - if (temporalTableExpression.Alias != null) + if (tableExpression.Alias != null) { Sql.Append(AliasSeparator) - .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(temporalTableExpression.Alias)); + .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(tableExpression.Alias)); } - return temporalTableExpression; + return tableExpression; } return base.VisitExtension(extensionExpression); diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs index 83f5766b0ec..e08b6a9a9e8 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs @@ -2,10 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Internal; using Microsoft.EntityFrameworkCore.Storage; namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal @@ -63,22 +66,74 @@ protected override Expression VisitExtension(Expression extensionExpression) { if (extensionExpression is TemporalQueryRootExpression queryRootExpression) { - // sql server model validator will throw if entity is mapped to multiple tables - var table = queryRootExpression.EntityType.GetTableMappings().Single().Table; - var temporalTableExpression = queryRootExpression switch + SelectExpression? selectExpression; + + var useOldBehavior26469 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) + && enabled26469; + + if (useOldBehavior26469) + { + // sql server model validator will throw if entity is mapped to multiple tables + var table = queryRootExpression.EntityType.GetTableMappings().Single().Table; +#pragma warning disable CS0618 // Type or member is obsolete + var temporalTableExpression = queryRootExpression switch + { + TemporalAllQueryRootExpression _ => (TemporalTableExpression)new TemporalAllTableExpression(table), + TemporalAsOfQueryRootExpression asOf => new TemporalAsOfTableExpression(table, asOf.PointInTime), + TemporalBetweenQueryRootExpression between => new TemporalBetweenTableExpression(table, between.From, between.To), + TemporalContainedInQueryRootExpression containedIn => new TemporalContainedInTableExpression( + table, containedIn.From, containedIn.To), + TemporalFromToQueryRootExpression fromTo => new TemporalFromToTableExpression(table, fromTo.From, fromTo.To), + _ => throw new InvalidOperationException(queryRootExpression.Print()) + }; +#pragma warning restore CS0618 // Type or member is obsolete + + selectExpression = RelationalDependencies.SqlExpressionFactory.Select( + queryRootExpression.EntityType, + temporalTableExpression); + } + else { - TemporalAllQueryRootExpression _ => (TemporalTableExpression)new TemporalAllTableExpression(table), - TemporalAsOfQueryRootExpression asOf => new TemporalAsOfTableExpression(table, asOf.PointInTime), - TemporalBetweenQueryRootExpression between => new TemporalBetweenTableExpression(table, between.From, between.To), - TemporalContainedInQueryRootExpression containedIn => new TemporalContainedInTableExpression( - table, containedIn.From, containedIn.To), - TemporalFromToQueryRootExpression fromTo => new TemporalFromToTableExpression(table, fromTo.From, fromTo.To), - _ => throw new InvalidOperationException(queryRootExpression.Print()) - }; - - var selectExpression = RelationalDependencies.SqlExpressionFactory.Select( - queryRootExpression.EntityType, - temporalTableExpression); + selectExpression = RelationalDependencies.SqlExpressionFactory.Select(queryRootExpression.EntityType); + + var tableExpressions = ExtractTableExpressions(selectExpression); + ValidateAllTablesHaveSameAnnotations(tableExpressions); + foreach (var tableExpression in tableExpressions) + { + switch (queryRootExpression) + { + case TemporalAllQueryRootExpression: + tableExpression[SqlServerAnnotationNames.TemporalOperationType] = TemporalOperationType.All; + break; + + case TemporalAsOfQueryRootExpression asOf: + tableExpression[SqlServerAnnotationNames.TemporalOperationType] = TemporalOperationType.AsOf; + tableExpression[SqlServerAnnotationNames.TemporalAsOfPointInTime] = asOf.PointInTime; + break; + + case TemporalBetweenQueryRootExpression between: + tableExpression[SqlServerAnnotationNames.TemporalOperationType] = TemporalOperationType.Between; + tableExpression[SqlServerAnnotationNames.TemporalRangeOperationFrom] = between.From; + tableExpression[SqlServerAnnotationNames.TemporalRangeOperationTo] = between.To; + break; + + case TemporalContainedInQueryRootExpression containedIn: + tableExpression[SqlServerAnnotationNames.TemporalOperationType] = TemporalOperationType.ContainedIn; + tableExpression[SqlServerAnnotationNames.TemporalRangeOperationFrom] = containedIn.From; + tableExpression[SqlServerAnnotationNames.TemporalRangeOperationTo] = containedIn.To; + break; + + case TemporalFromToQueryRootExpression fromTo: + tableExpression[SqlServerAnnotationNames.TemporalOperationType] = TemporalOperationType.FromTo; + tableExpression[SqlServerAnnotationNames.TemporalRangeOperationFrom] = fromTo.From; + tableExpression[SqlServerAnnotationNames.TemporalRangeOperationTo] = fromTo.To; + break; + + default: + throw new InvalidOperationException(queryRootExpression.Print()); + } + } + } return new ShapedQueryExpression( selectExpression, @@ -93,5 +148,61 @@ protected override Expression VisitExtension(Expression extensionExpression) return base.VisitExtension(extensionExpression); } + + private List ExtractTableExpressions(TableExpressionBase tableExpressionBase) + { + if (tableExpressionBase is JoinExpressionBase joinExpression) + { + tableExpressionBase = joinExpression.Table; + } + + if (tableExpressionBase is TableExpression tableExpression) + { + return new List { tableExpression }; + } + + if (tableExpressionBase is SelectExpression selectExpression) + { + var result = new List(); + foreach (var table in selectExpression.Tables) + { + result.AddRange(ExtractTableExpressions(table)); + } + + return result; + } + + if (tableExpressionBase is SetOperationBase setOperationBase) + { + var result = new List(); + result.AddRange(ExtractTableExpressions(setOperationBase.Source1)); + result.AddRange(ExtractTableExpressions(setOperationBase.Source2)); + + return result; + } + + throw new InvalidOperationException("Unsupported table expression base type."); + } + + private void ValidateAllTablesHaveSameAnnotations(List tableExpressions) + { + List? expectedAnnotations = null; + foreach (var tableExpression in tableExpressions) + { + if (expectedAnnotations == null) + { + expectedAnnotations = new List(tableExpression.GetAnnotations().OrderBy(x => x.Name)); + } + else + { + var annotations = tableExpression.GetAnnotations().OrderBy(x => x.Name).ToList(); + if (expectedAnnotations.Count != annotations.Count + || expectedAnnotations.Zip(annotations, (e, a) => e.Name != a.Name || e.Value != a.Value).Any()) + { + throw new InvalidOperationException("Annotations for all tables representing an entity type must match."); + } + } + } + } } } diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs index 788082216d9..9c5e2f37f40 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; @@ -35,9 +36,19 @@ public SqlServerSqlNullabilityProcessor( /// protected override TableExpressionBase Visit(TableExpressionBase tableExpressionBase) { - return tableExpressionBase is TemporalTableExpression temporalTableExpression - ? temporalTableExpression - : base.Visit(tableExpressionBase); + var useOldBehavior26469 = AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) + && enabled26469; + + if (useOldBehavior26469) + { +#pragma warning disable CS0618 // Type or member is obsolete + return tableExpressionBase is TemporalTableExpression temporalTableExpression + ? temporalTableExpression + : base.Visit(tableExpressionBase); +#pragma warning restore CS0618 // Type or member is obsolete + } + + return base.Visit(tableExpressionBase); } } } diff --git a/src/EFCore.SqlServer/Query/Internal/TemporalAllTableExpression.cs b/src/EFCore.SqlServer/Query/Internal/TemporalAllTableExpression.cs index c6f666cb180..de81f8b0ed0 100644 --- a/src/EFCore.SqlServer/Query/Internal/TemporalAllTableExpression.cs +++ b/src/EFCore.SqlServer/Query/Internal/TemporalAllTableExpression.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; @@ -13,6 +14,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [Obsolete("Use TableExpressionBase annotations to convey temporal query information")] public class TemporalAllTableExpression : TemporalTableExpression { /// diff --git a/src/EFCore.SqlServer/Query/Internal/TemporalAsOfTableExpression.cs b/src/EFCore.SqlServer/Query/Internal/TemporalAsOfTableExpression.cs index fab53ce8f7d..b0c6d3ac5cc 100644 --- a/src/EFCore.SqlServer/Query/Internal/TemporalAsOfTableExpression.cs +++ b/src/EFCore.SqlServer/Query/Internal/TemporalAsOfTableExpression.cs @@ -14,6 +14,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [Obsolete("Use TableExpressionBase annotations to convey temporal query information")] public class TemporalAsOfTableExpression : TemporalTableExpression { /// diff --git a/src/EFCore.SqlServer/Query/Internal/TemporalBetweenTableExpression.cs b/src/EFCore.SqlServer/Query/Internal/TemporalBetweenTableExpression.cs index b8f1313ee6d..2be718ca5df 100644 --- a/src/EFCore.SqlServer/Query/Internal/TemporalBetweenTableExpression.cs +++ b/src/EFCore.SqlServer/Query/Internal/TemporalBetweenTableExpression.cs @@ -14,6 +14,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [Obsolete("Use TableExpressionBase annotations to convey temporal query information")] public class TemporalBetweenTableExpression : TemporalRangeTableExpression { /// diff --git a/src/EFCore.SqlServer/Query/Internal/TemporalContainedInTableExpression.cs b/src/EFCore.SqlServer/Query/Internal/TemporalContainedInTableExpression.cs index 7fda5d8bbfb..92cf5ac042f 100644 --- a/src/EFCore.SqlServer/Query/Internal/TemporalContainedInTableExpression.cs +++ b/src/EFCore.SqlServer/Query/Internal/TemporalContainedInTableExpression.cs @@ -14,6 +14,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [Obsolete("Use TableExpressionBase annotations to convey temporal query information")] public class TemporalContainedInTableExpression : TemporalRangeTableExpression { /// diff --git a/src/EFCore.SqlServer/Query/Internal/TemporalFromToTableExpression.cs b/src/EFCore.SqlServer/Query/Internal/TemporalFromToTableExpression.cs index 7a3b179542e..426355ed6c1 100644 --- a/src/EFCore.SqlServer/Query/Internal/TemporalFromToTableExpression.cs +++ b/src/EFCore.SqlServer/Query/Internal/TemporalFromToTableExpression.cs @@ -14,6 +14,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [Obsolete("Use TableExpressionBase annotations to convey temporal query information")] public class TemporalFromToTableExpression : TemporalRangeTableExpression { /// diff --git a/src/EFCore.SqlServer/Query/Internal/TemporalOperationType.cs b/src/EFCore.SqlServer/Query/Internal/TemporalOperationType.cs new file mode 100644 index 00000000000..d9b87daa779 --- /dev/null +++ b/src/EFCore.SqlServer/Query/Internal/TemporalOperationType.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal +{ + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public enum TemporalOperationType + { + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + All, + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + AsOf, + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + Between, + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + ContainedIn, + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + FromTo + } +} diff --git a/src/EFCore.SqlServer/Query/Internal/TemporalRangeTableExpression.cs b/src/EFCore.SqlServer/Query/Internal/TemporalRangeTableExpression.cs index 276fa723a1f..f9a3728d68f 100644 --- a/src/EFCore.SqlServer/Query/Internal/TemporalRangeTableExpression.cs +++ b/src/EFCore.SqlServer/Query/Internal/TemporalRangeTableExpression.cs @@ -12,6 +12,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [Obsolete("Use TableExpressionBase annotations to convey temporal query information")] public abstract class TemporalRangeTableExpression : TemporalTableExpression { /// diff --git a/src/EFCore.SqlServer/Query/Internal/TemporalTableExpression.cs b/src/EFCore.SqlServer/Query/Internal/TemporalTableExpression.cs index 6668c77e25f..23586a9d937 100644 --- a/src/EFCore.SqlServer/Query/Internal/TemporalTableExpression.cs +++ b/src/EFCore.SqlServer/Query/Internal/TemporalTableExpression.cs @@ -13,6 +13,7 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// + [Obsolete("Use TableExpressionBase annotations to convey temporal query information")] public abstract class TemporalTableExpression : TableExpressionBase, IClonableTableExpressionBase { /// diff --git a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs index 4852d169d97..305f99d3cda 100644 --- a/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs +++ b/src/EFCore/Metadata/Builders/OwnedNavigationBuilder.cs @@ -180,6 +180,32 @@ public virtual PropertyBuilder Property(string propertyNam typeof(TProperty), Check.NotEmpty(propertyName, nameof(propertyName)), ConfigurationSource.Explicit)!.Metadata)); + /// + /// Returns an object that can be used to configure a property of the entity type. + /// If no property with the given name exists, then a new property will be added. + /// + /// + /// When adding a new property, if a property with the same name exists in the entity class + /// then it will be added to the model. If no property exists in the entity class, then + /// a new shadow state property will be added. A shadow state property is one that does not have a + /// corresponding property in the entity class. The current value for the property is stored in + /// the rather than being stored in instances of the entity class. + /// + /// The type of the property to be configured. + /// The name of the property to be configured. + /// Indicates whether the type configuration source should be set. + /// An object that can be used to configure the property. + public virtual PropertyBuilder Property( + Type propertyType, + string propertyName, + bool setTypeConfigurationSource = true) + => new( + DependentEntityType.Builder.Property( + Check.NotNull(propertyType, nameof(propertyType)), + Check.NotEmpty(propertyName, nameof(propertyName)), + setTypeConfigurationSource ? ConfigurationSource.Explicit : null, + ConfigurationSource.Explicit)!.Metadata); + /// /// /// Returns an object that can be used to configure a property of the owned entity type. diff --git a/src/EFCore/Query/INavigationExpansionExtensibilityHelper.cs b/src/EFCore/Query/INavigationExpansionExtensibilityHelper.cs index c8d81479d32..8fe120a83ad 100644 --- a/src/EFCore/Query/INavigationExpansionExtensibilityHelper.cs +++ b/src/EFCore/Query/INavigationExpansionExtensibilityHelper.cs @@ -21,6 +21,13 @@ public interface INavigationExpansionExtensibilityHelper /// Source expression. QueryRootExpression CreateQueryRoot(IEntityType entityType, QueryRootExpression? source); + /// + /// Validates whether a new can be created. + /// + /// Entity type of the new . + /// Source expression. + void ValidateQueryRootCreation(IEntityType entityType, QueryRootExpression? source); + /// /// Checks whether two query roots are compatible for a set operation to combine them. /// diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index 48089acf9d6..4f2c221ce8c 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -159,6 +159,9 @@ protected Expression ExpandNavigation( return ownedExpansion; } + // make sure that we can actually expand this navigation (later) + _extensibilityHelper.ValidateQueryRootCreation(targetType, entityReference.QueryRootExpression); + var ownedEntityReference = new EntityReference(targetType, entityReference.QueryRootExpression); _navigationExpandingExpressionVisitor.PopulateEagerLoadedNavigations(ownedEntityReference.IncludePaths); ownedEntityReference.MarkAsOptional(); @@ -229,7 +232,8 @@ protected Expression ExpandSkipNavigation( // Second psuedo-navigation is a reference var secondTargetType = navigation.TargetEntityType; // we can use the entity reference here. If the join entity wasn't temporal, - // the query root creator would have thrown the exception when it was being created + // the query root creation validator would have thrown the exception when it was being created + _extensibilityHelper.ValidateQueryRootCreation(secondTargetType, entityReference.QueryRootExpression); var innerQueryable = _extensibilityHelper.CreateQueryRoot(secondTargetType, entityReference.QueryRootExpression); var innerSource = (NavigationExpansionExpression)_navigationExpandingExpressionVisitor.Visit(innerQueryable); @@ -278,6 +282,8 @@ protected Expression ExpandSkipNavigation( { // Second psuedo-navigation is a collection var secondTargetType = navigation.TargetEntityType; + + _extensibilityHelper.ValidateQueryRootCreation(secondTargetType, entityReference.QueryRootExpression); var innerQueryable = _extensibilityHelper.CreateQueryRoot(secondTargetType, entityReference.QueryRootExpression); var innerSource = (NavigationExpansionExpression)_navigationExpandingExpressionVisitor.Visit(innerQueryable); @@ -358,6 +364,7 @@ private Expression ExpandForeignKey( Check.DebugAssert(!targetType.IsOwned(), "Owned entity expanding foreign key."); + _extensibilityHelper.ValidateQueryRootCreation(targetType, entityReference.QueryRootExpression); var innerQueryable = _extensibilityHelper.CreateQueryRoot(targetType, entityReference.QueryRootExpression); var innerSource = (NavigationExpansionExpression)_navigationExpandingExpressionVisitor.Visit(innerQueryable); diff --git a/src/EFCore/Query/NavigationExpansionExtensibilityHelper.cs b/src/EFCore/Query/NavigationExpansionExtensibilityHelper.cs index 1ef1c32a4f5..41279f68a24 100644 --- a/src/EFCore/Query/NavigationExpansionExtensibilityHelper.cs +++ b/src/EFCore/Query/NavigationExpansionExtensibilityHelper.cs @@ -28,6 +28,11 @@ public virtual QueryRootExpression CreateQueryRoot(IEntityType entityType, Query ? new QueryRootExpression(source.QueryProvider, entityType) : new QueryRootExpression(entityType); + /// + public virtual void ValidateQueryRootCreation(IEntityType entityType, QueryRootExpression? source) + { + } + /// public virtual bool AreQueryRootsCompatible(QueryRootExpression? first, QueryRootExpression? second) { diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/OwnedQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/OwnedQueryCosmosTest.cs index 5536a9d086a..584c937f5da 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/OwnedQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/OwnedQueryCosmosTest.cs @@ -811,7 +811,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con { Id = 1, id = Guid.NewGuid().ToString(), - StarId = 1 + StarId = 1, + Name = "Earth" }); }); diff --git a/test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs index 246188130f6..02240115e74 100644 --- a/test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs @@ -928,6 +928,15 @@ public virtual async Task Filter_on_indexer_using_function_argument(bool async) await myFunc(async, zipCode); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Simple_query_entity_with_owned_collection(bool async) + { + return AssertQuery( + async, + ss => ss.Set()); + } + protected virtual DbContext CreateContext() => Fixture.CreateContext(); @@ -1094,6 +1103,7 @@ public IReadOnlyDictionary GetEntityAsserters() var aa = (Planet)a; Assert.Equal(ee.Id, aa.Id); + Assert.Equal(ee.Name, aa.Name); Assert.Equal(ee.StarId, aa.StarId); } } @@ -1500,7 +1510,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con }); }); - modelBuilder.Entity(pb => pb.HasData(new Planet { Id = 1, StarId = 1 })); + modelBuilder.Entity(pb => pb.HasData(new Planet { Id = 1, StarId = 1, Name = "Earth" })); modelBuilder.Entity( mb => mb.HasData( @@ -1630,11 +1640,16 @@ public virtual IQueryable Set() return (IQueryable)_bartons.AsQueryable(); } + if (typeof(TEntity) == typeof(Star)) + { + return (IQueryable)_stars.AsQueryable(); + } + throw new InvalidOperationException("Invalid entity type: " + typeof(TEntity)); } private static IReadOnlyList CreatePlanets() - => new List { new() { Id = 1, StarId = 1 } }; + => new List { new() { Id = 1, StarId = 1, Name = "Earth" } }; private static IReadOnlyList CreateStars() => new List @@ -1978,6 +1993,8 @@ protected class Planet { public int Id { get; set; } + public string Name { get; set; } + public int StarId { get; set; } public Star Star { get; set; } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs index 498679e0079..0556ea6da05 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs @@ -229,7 +229,7 @@ public override async Task Navigation_rewrite_on_owned_reference_followed_by_reg await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity(async); AssertSql( - @"SELECT [p].[Id], [p].[StarId] + @"SELECT [p].[Id], [p].[Name], [p].[StarId] FROM [OwnedPerson] AS [o] LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id]"); } @@ -256,7 +256,7 @@ public override async Task Project_multiple_owned_navigations(bool async) await base.Project_multiple_owned_navigations(async); AssertSql( - @"SELECT [o].[Id], [p].[Id], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [p].[StarId] + @"SELECT [o].[Id], [p].[Id], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [p].[Name], [p].[StarId] FROM [OwnedPerson] AS [o] LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] LEFT JOIN ( @@ -278,7 +278,7 @@ FROM [Order] AS [o0] LEFT JOIN [OwnedPerson] AS [o1] ON [o0].[ClientId] = [o1].[Id] LEFT JOIN [Planet] AS [p0] ON [o1].[PersonAddress_Country_PlanetId] = [p0].[Id] LEFT JOIN [Star] AS [s] ON [p0].[StarId] = [s].[Id] - WHERE ([o].[Id] = [o0].[ClientId]) AND (([s].[Id] <> 42) OR ([s].[Id] IS NULL))) AS [Count], [p].[Id], [p].[StarId] + WHERE ([o].[Id] = [o0].[ClientId]) AND (([s].[Id] <> 42) OR ([s].[Id] IS NULL))) AS [Count], [p].[Id], [p].[Name], [p].[StarId] FROM [OwnedPerson] AS [o] LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] ORDER BY [o].[Id]"); @@ -962,7 +962,7 @@ public override async Task Project_multiple_owned_navigations_split(bool async) await base.Project_multiple_owned_navigations_split(async); AssertSql( - @"SELECT [o].[Id], [p].[Id], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [p].[StarId] + @"SELECT [o].[Id], [p].[Id], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [p].[Name], [p].[StarId] FROM [OwnedPerson] AS [o] LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] ORDER BY [o].[Id], [p].[Id]", @@ -1166,7 +1166,7 @@ public override async Task Projecting_collection_correlated_with_keyless_entity_ await base.Projecting_collection_correlated_with_keyless_entity_after_navigation_works_using_parent_identifiers(async); AssertSql( - @"SELECT [b].[Throned_Value], [f].[Id], [b].[Id], [p].[Id], [p].[StarId] + @"SELECT [b].[Throned_Value], [f].[Id], [b].[Id], [p].[Id], [p].[Name], [p].[StarId] FROM [Fink] AS [f] LEFT JOIN [Barton] AS [b] ON [f].[BartonId] = [b].[Id] LEFT JOIN [Planet] AS [p] ON ([b].[Throned_Value] <> [p].[Id]) OR ([b].[Throned_Value] IS NULL) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs index fd13e78a0b3..a2cdaaad71a 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs @@ -1,21 +1,3964 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel; +using Xunit; using Xunit.Abstractions; namespace Microsoft.EntityFrameworkCore.Query { - // TODO: this now throws due to table splitting validation - //public class TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest : ComplexNavigationsCollectionsSharedQueryTypeRelationalTestBase< - // TemporalComplexNavigationsSharedTypeQuerySqlServerFixture> - //{ - // public TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest( - // TemporalComplexNavigationsSharedTypeQuerySqlServerFixture fixture, - // ITestOutputHelper testOutputHelper) - // : base(fixture) - // { - // Fixture.TestSqlLoggerFactory.Clear(); - // //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); - // } - //} + public class TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest : ComplexNavigationsCollectionsSharedTypeQueryRelationalTestBase< + TemporalComplexNavigationsSharedTypeQuerySqlServerFixture> + { + public TemporalComplexNavigationsCollectionsSharedTypeQuerySqlServerTest( + TemporalComplexNavigationsSharedTypeQuerySqlServerFixture fixture, + ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + protected override Expression RewriteServerQueryExpression(Expression serverQueryExpression) + { + var temporalEntityTypes = new List + { + typeof(Level1), + typeof(Level2), + typeof(Level3), + typeof(Level4), + }; + + var rewriter = new TemporalPointInTimeQueryRewriter(Fixture.ChangesDate, temporalEntityTypes); + + return rewriter.Visit(serverQueryExpression); + } + + public override async Task Complex_multi_include_with_order_by_and_paging(bool async) + { + await base.Complex_multi_include_with_order_by_and_paging(async); + + AssertSql( + @"@__p_0='0' +@__p_1='10' + +SELECT [t].[Id], [t].[Date], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id00], [t3].[Id], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd], [t3].[PeriodStart], [t3].[Id0], [t3].[Id00] +FROM ( + SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Name] + OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY +) AS [t] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t0] ON [t].[Id] = [t0].[Level1_Required_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l2].[Id] = [t2].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t1] ON CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t1].[OneToMany_Optional_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level2_Optional_Id], [l5].[Level2_Required_Id], [l5].[Level3_Name], [l5].[OneToMany_Optional_Inverse3Id], [l5].[OneToMany_Required_Inverse3Id], [l5].[OneToOne_Optional_PK_Inverse3Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [l7].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] ON [l6].[Id] = [l7].[Id] + WHERE (([l6].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l6].[Level1_Required_Id] IS NOT NULL)) AND ([l6].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l5].[Id] = [t4].[Id] + WHERE ([l5].[Level2_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t3] ON CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t3].[OneToMany_Required_Inverse3Id] +ORDER BY [t].[Name], [t].[Id], [t0].[Id], [t0].[Id0], [t1].[Id], [t1].[Id0], [t1].[Id00], [t3].[Id], [t3].[Id0]"); + } + + public override async Task Complex_multi_include_with_order_by_and_paging_joins_on_correct_key(bool async) + { + await base.Complex_multi_include_with_order_by_and_paging_joins_on_correct_key(async); + + AssertSql( + @"@__p_0='0' +@__p_1='10' + +SELECT [t].[Id], [t].[Date], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t1].[Id], [t1].[Id0], [t2].[Id], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Id00], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t4].[Id], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Id00] +FROM ( + SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Name] + OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY +) AS [t] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t0] ON [t].[Id] = [t0].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[OneToOne_Required_PK_Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Level2_Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[PeriodEnd], [l2].[PeriodStart], [l3].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] ON [l2].[Id] = [l3].[Id] + WHERE (([l2].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l2].[Level1_Required_Id] IS NOT NULL)) AND ([l2].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [t].[Id] = [t1].[Level1_Required_Id] +LEFT JOIN ( + SELECT [l4].[Id], [l4].[Level2_Optional_Id], [l4].[Level2_Required_Id], [l4].[Level3_Name], [l4].[OneToMany_Optional_Inverse3Id], [l4].[OneToMany_Required_Inverse3Id], [l4].[OneToOne_Optional_PK_Inverse3Id], [l4].[PeriodEnd], [l4].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] + INNER JOIN ( + SELECT [l5].[Id], [l6].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l4].[Id] = [t3].[Id] + WHERE ([l4].[Level2_Required_Id] IS NOT NULL) AND ([l4].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t2] ON CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t2].[OneToMany_Optional_Inverse3Id] +LEFT JOIN ( + SELECT [l7].[Id], [l7].[Level2_Optional_Id], [l7].[Level2_Required_Id], [l7].[Level3_Name], [l7].[OneToMany_Optional_Inverse3Id], [l7].[OneToMany_Required_Inverse3Id], [l7].[OneToOne_Optional_PK_Inverse3Id], [l7].[PeriodEnd], [l7].[PeriodStart], [t5].[Id] AS [Id0], [t5].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN ( + SELECT [l8].[Id], [l9].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] ON [l8].[Id] = [l9].[Id] + WHERE (([l8].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l8].[Level1_Required_Id] IS NOT NULL)) AND ([l8].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t5] ON [l7].[Id] = [t5].[Id] + WHERE ([l7].[Level2_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t4] ON CASE + WHEN (((([t1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t1].[Level1_Required_Id] IS NOT NULL)) AND ([t1].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t1].[PeriodEnd] IS NOT NULL)) AND ([t1].[PeriodStart] IS NOT NULL) THEN [t1].[Id] +END = [t4].[OneToMany_Required_Inverse3Id] +ORDER BY [t].[Name], [t].[Id], [t0].[Id], [t0].[Id0], [t1].[Id], [t1].[Id0], [t2].[Id], [t2].[Id0], [t2].[Id00], [t4].[Id], [t4].[Id0]"); + } + + public override async Task Complex_multi_include_with_order_by_and_paging_joins_on_correct_key2(bool async) + { + await base.Complex_multi_include_with_order_by_and_paging_joins_on_correct_key2(async); + + AssertSql( + @"@__p_0='0' +@__p_1='10' + +SELECT [t].[Id], [t].[Date], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t0].[Id0], [t1].[Id0], [t1].[Id00], [t3].[Id], [t3].[Level3_Optional_Id], [t3].[Level3_Required_Id], [t3].[Level4_Name], [t3].[OneToMany_Optional_Inverse4Id], [t3].[OneToMany_Required_Inverse4Id], [t3].[OneToOne_Optional_PK_Inverse4Id], [t3].[PeriodEnd], [t3].[PeriodStart], [t3].[Id0], [t3].[Id00], [t3].[Id000] +FROM ( + SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Name] + OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY +) AS [t] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t0] ON [t].[Id] = [t0].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l2].[Id] = [t2].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t1] ON CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t1].[Level2_Required_Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00], [t4].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t5].[Id] AS [Id0], [t5].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t5] ON [l6].[Id] = [t5].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t4] ON [l5].[Id] = [t4].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) +) AS [t3] ON CASE + WHEN ((([t1].[Level2_Required_Id] IS NOT NULL) AND ([t1].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t1].[PeriodEnd] IS NOT NULL)) AND ([t1].[PeriodStart] IS NOT NULL) THEN [t1].[Id] +END = [t3].[OneToMany_Optional_Inverse4Id] +ORDER BY [t].[Name], [t].[Id], [t0].[Id], [t0].[Id0], [t1].[Id], [t1].[Id0], [t1].[Id00], [t3].[Id], [t3].[Id0], [t3].[Id00]"); + } + + public override async Task Complex_query_with_let_collection_projection_FirstOrDefault(bool async) + { + await base.Complex_query_with_let_collection_projection_FirstOrDefault(async); + + AssertSql( + @"SELECT [l].[Id], [t0].[Id], [t0].[Id0], [t1].[Name], [t1].[Id], [t0].[c] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[c], [t].[Id], [t].[Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[OneToMany_Optional_Inverse2Id] + FROM ( + SELECT 1 AS [c], [l0].[Id], [l1].[Id] AS [Id0], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l0].[OneToMany_Optional_Inverse2Id], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Id], [l1].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +OUTER APPLY ( + SELECT [l2].[Name], [l2].[Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + WHERE EXISTS ( + SELECT 1 + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (((([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([l2].[Id] = [l3].[OneToMany_Optional_Inverse2Id])) AND ([l3].[Id] = CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] + END)) +) AS [t1] +ORDER BY [l].[Id], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(bool async) + { + // Nested collection with ToList. Issue #23303. + await Assert.ThrowsAsync( + () => base.Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(async)); + + AssertSql(@"SELECT [l].[Id], [t0].[Id], [t0].[Id0], [t1].[Name], [t1].[Id], [t0].[c] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[c], [t].[Id], [t].[Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[OneToMany_Optional_Inverse2Id] + FROM ( + SELECT 1 AS [c], [l0].[Id], [l1].[Id] AS [Id0], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l0].[OneToMany_Optional_Inverse2Id], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Id], [l1].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE [l0].[OneToOne_Required_PK_Date] IS NOT NULL AND [l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l0].[Level2_Name] <> N'Foo' OR [l0].[Level2_Name] IS NULL) + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +OUTER APPLY ( + SELECT [l2].[Name], [l2].[Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + WHERE EXISTS ( + SELECT 1 + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [l2].[Id] = [l3].[OneToMany_Optional_Inverse2Id] AND [l3].[Id] = CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id] + END) +) AS [t1] +ORDER BY [l].[Id], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Filtered_include_after_different_filtered_include_different_level(bool async) + { + await base.Filtered_include_after_different_filtered_include_different_level(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t3].[Id], [t3].[OneToOne_Required_PK_Date], [t3].[Level1_Optional_Id], [t3].[Level1_Required_Id], [t3].[Level2_Name], [t3].[OneToMany_Optional_Inverse2Id], [t3].[OneToMany_Required_Inverse2Id], [t3].[OneToOne_Optional_PK_Inverse2Id], [t3].[PeriodEnd], [t3].[PeriodStart], [t3].[Id0], [t3].[Id1], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd0], [t3].[PeriodStart0], [t3].[Id00], [t3].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +OUTER APPLY ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t1].[Id] AS [Id1], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t1].[Id0] AS [Id00], [t1].[Id00] AS [Id000] + FROM ( + SELECT TOP(3) [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id])) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ORDER BY [l0].[Level2_Name] + ) AS [t] + LEFT JOIN ( + SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] + FROM ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], ROW_NUMBER() OVER(PARTITION BY [l2].[OneToMany_Required_Inverse3Id] ORDER BY [l2].[Level3_Name] DESC) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l2].[Id] = [t2].[Id] + WHERE (([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND (([l2].[Level3_Name] <> N'Bar') OR ([l2].[Level3_Name] IS NULL)) + ) AS [t0] + WHERE 1 < [t0].[row] + ) AS [t1] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] + END = [t1].[OneToMany_Required_Inverse3Id] +) AS [t3] +ORDER BY [l].[Id], [t3].[Level2_Name], [t3].[Id], [t3].[Id0], [t3].[OneToMany_Required_Inverse3Id], [t3].[Level3_Name] DESC, [t3].[Id1], [t3].[Id00]"); + } + + public override async Task Filtered_include_after_different_filtered_include_same_level(bool async) + { + await base.Filtered_include_after_different_filtered_include_same_level(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t1].[Id], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Level2_Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ) AS [t] + WHERE [t].[row] <= 3 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0] + FROM ( + SELECT [l2].[Id], [l2].[OneToOne_Required_PK_Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Level2_Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[PeriodEnd], [l2].[PeriodStart], [l3].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l2].[OneToMany_Required_Inverse2Id] ORDER BY [l2].[Level2_Name] DESC) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] ON [l2].[Id] = [l3].[Id] + WHERE ((([l2].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l2].[Level1_Required_Id] IS NOT NULL)) AND ([l2].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (([l2].[Level2_Name] <> N'Bar') OR ([l2].[Level2_Name] IS NULL)) + ) AS [t2] + WHERE 1 < [t2].[row] +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Required_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Level2_Name], [t0].[Id], [t0].[Id0], [t1].[OneToMany_Required_Inverse2Id], [t1].[Level2_Name] DESC, [t1].[Id]"); + } + + public override async Task Filtered_include_after_reference_navigation(bool async) + { + await base.Filtered_include_after_reference_navigation(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] + FROM ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], ROW_NUMBER() OVER(PARTITION BY [l2].[OneToMany_Optional_Inverse3Id] ORDER BY [l2].[Level3_Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l2].[Id] = [t2].[Id] + WHERE (([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND (([l2].[Level3_Name] <> N'Foo') OR ([l2].[Level3_Name] IS NULL)) + ) AS [t0] + WHERE (1 < [t0].[row]) AND ([t0].[row] <= 4) +) AS [t1] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t1].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t1].[OneToMany_Optional_Inverse3Id], [t1].[Level3_Name], [t1].[Id], [t1].[Id0]"); + } + + public override async Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async) + { + await base.Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t5].[Id], [t5].[OneToOne_Required_PK_Date], [t5].[Level1_Optional_Id], [t5].[Level1_Required_Id], [t5].[Level2_Name], [t5].[OneToMany_Optional_Inverse2Id], [t5].[OneToMany_Required_Inverse2Id], [t5].[OneToOne_Optional_PK_Inverse2Id], [t5].[PeriodEnd], [t5].[PeriodStart], [t5].[Id0], [t5].[Level2_Optional_Id], [t5].[Level2_Required_Id], [t5].[Level3_Name], [t5].[OneToMany_Optional_Inverse3Id], [t5].[OneToMany_Required_Inverse3Id], [t5].[OneToOne_Optional_PK_Inverse3Id], [t5].[PeriodEnd0], [t5].[PeriodStart0], [t5].[Id00], [t5].[Id01], [t5].[Id000], [t5].[Id1], [t5].[Level3_Optional_Id], [t5].[Level3_Required_Id], [t5].[Level4_Name], [t5].[OneToMany_Optional_Inverse4Id], [t5].[OneToMany_Required_Inverse4Id], [t5].[OneToOne_Optional_PK_Inverse4Id], [t5].[PeriodEnd1], [t5].[PeriodStart1], [t5].[Id02], [t5].[Id001], [t5].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +OUTER APPLY ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t].[Id0] AS [Id00], [t0].[Id0] AS [Id01], [t0].[Id00] AS [Id000], [t2].[Id] AS [Id1], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id], [t2].[PeriodEnd] AS [PeriodEnd1], [t2].[PeriodStart] AS [PeriodStart1], [t2].[Id0] AS [Id02], [t2].[Id00] AS [Id001], [t2].[Id000] AS [Id0000], [t].[c] + FROM ( + SELECT TOP(1) [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id])) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END + ) AS [t] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE (([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL)) AND ([l5].[Id] > 1) + ) AS [t2] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] + END = [t2].[OneToMany_Optional_Inverse4Id] +) AS [t5] +ORDER BY [l].[Id], [t5].[c], [t5].[Id], [t5].[Id00], [t5].[Id0], [t5].[Id01], [t5].[Id000], [t5].[Id1], [t5].[Id02], [t5].[Id001]"); + } + + public override async Task Filtered_include_and_non_filtered_include_on_same_navigation1(bool async) + { + await base.Filtered_include_and_non_filtered_include_on_same_navigation1(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t].[c] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END) AS [row], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ) AS [t] + WHERE [t].[row] <= 3 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[c], [t0].[Id]"); + } + + public override async Task Filtered_include_and_non_filtered_include_on_same_navigation2(bool async) + { + await base.Filtered_include_and_non_filtered_include_on_same_navigation2(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t].[c] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END) AS [row], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ) AS [t] + WHERE [t].[row] <= 3 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[c], [t0].[Id]"); + } + + public override async Task Filtered_include_basic_OrderBy_Skip(bool async) + { + await base.Filtered_include_basic_OrderBy_Skip(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Level2_Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] + WHERE 1 < [t].[row] +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Level2_Name], [t0].[Id]"); + } + + public override async Task Filtered_include_basic_OrderBy_Skip_Take(bool async) + { + await base.Filtered_include_basic_OrderBy_Skip_Take(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Level2_Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] + WHERE (1 < [t].[row]) AND ([t].[row] <= 4) +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Level2_Name], [t0].[Id]"); + } + + public override async Task Filtered_include_basic_OrderBy_Take(bool async) + { + await base.Filtered_include_basic_OrderBy_Take(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Level2_Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] + WHERE [t].[row] <= 3 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Level2_Name], [t0].[Id]"); + } + + public override async Task Filtered_include_basic_Where(bool async) + { + await base.Filtered_include_basic_Where(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([l0].[Id] > 5) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Id]"); + } + + public override async Task Filtered_include_complex_three_level_with_middle_having_filter1(bool async) + { + await base.Filtered_include_complex_three_level_with_middle_having_filter1(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t8].[Id], [t8].[OneToOne_Required_PK_Date], [t8].[Level1_Optional_Id], [t8].[Level1_Required_Id], [t8].[Level2_Name], [t8].[OneToMany_Optional_Inverse2Id], [t8].[OneToMany_Required_Inverse2Id], [t8].[OneToOne_Optional_PK_Inverse2Id], [t8].[PeriodEnd], [t8].[PeriodStart], [t8].[Id0], [t8].[Id1], [t8].[Level2_Optional_Id], [t8].[Level2_Required_Id], [t8].[Level3_Name], [t8].[OneToMany_Optional_Inverse3Id], [t8].[OneToMany_Required_Inverse3Id], [t8].[OneToOne_Optional_PK_Inverse3Id], [t8].[PeriodEnd0], [t8].[PeriodStart0], [t8].[Id00], [t8].[Id000], [t8].[Id10], [t8].[Level3_Optional_Id], [t8].[Level3_Required_Id], [t8].[Level4_Name], [t8].[OneToMany_Optional_Inverse4Id], [t8].[OneToMany_Required_Inverse4Id], [t8].[OneToOne_Optional_PK_Inverse4Id], [t8].[PeriodEnd00], [t8].[PeriodStart00], [t8].[Id01], [t8].[Id0000], [t8].[Id00000], [t8].[Id2], [t8].[Level3_Optional_Id0], [t8].[Level3_Required_Id0], [t8].[Level4_Name0], [t8].[OneToMany_Optional_Inverse4Id0], [t8].[OneToMany_Required_Inverse4Id0], [t8].[OneToOne_Optional_PK_Inverse4Id0], [t8].[PeriodEnd1], [t8].[PeriodStart1], [t8].[Id02], [t8].[Id001], [t8].[Id0001] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], [t7].[Id] AS [Id1], [t7].[Level2_Optional_Id], [t7].[Level2_Required_Id], [t7].[Level3_Name], [t7].[OneToMany_Optional_Inverse3Id], [t7].[OneToMany_Required_Inverse3Id], [t7].[OneToOne_Optional_PK_Inverse3Id], [t7].[PeriodEnd] AS [PeriodEnd0], [t7].[PeriodStart] AS [PeriodStart0], [t7].[Id0] AS [Id00], [t7].[Id00] AS [Id000], [t7].[Id1] AS [Id10], [t7].[Level3_Optional_Id], [t7].[Level3_Required_Id], [t7].[Level4_Name], [t7].[OneToMany_Optional_Inverse4Id], [t7].[OneToMany_Required_Inverse4Id], [t7].[OneToOne_Optional_PK_Inverse4Id], [t7].[PeriodEnd0] AS [PeriodEnd00], [t7].[PeriodStart0] AS [PeriodStart00], [t7].[Id01], [t7].[Id000] AS [Id0000], [t7].[Id0000] AS [Id00000], [t7].[Id2], [t7].[Level3_Optional_Id0], [t7].[Level3_Required_Id0], [t7].[Level4_Name0], [t7].[OneToMany_Optional_Inverse4Id0], [t7].[OneToMany_Required_Inverse4Id0], [t7].[OneToOne_Optional_PK_Inverse4Id0], [t7].[PeriodEnd1], [t7].[PeriodStart1], [t7].[Id02], [t7].[Id001], [t7].[Id0001], [t7].[c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + OUTER APPLY ( + SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00], [t1].[Id] AS [Id1], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id000], [t1].[Id000] AS [Id0000], [t4].[Id] AS [Id2], [t4].[Level3_Optional_Id] AS [Level3_Optional_Id0], [t4].[Level3_Required_Id] AS [Level3_Required_Id0], [t4].[Level4_Name] AS [Level4_Name0], [t4].[OneToMany_Optional_Inverse4Id] AS [OneToMany_Optional_Inverse4Id0], [t4].[OneToMany_Required_Inverse4Id] AS [OneToMany_Required_Inverse4Id0], [t4].[OneToOne_Optional_PK_Inverse4Id] AS [OneToOne_Optional_PK_Inverse4Id0], [t4].[PeriodEnd] AS [PeriodEnd1], [t4].[PeriodStart] AS [PeriodStart1], [t4].[Id0] AS [Id02], [t4].[Id00] AS [Id001], [t4].[Id000] AS [Id0001], [t0].[c] + FROM ( + SELECT TOP(1) [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00], CASE + WHEN ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l2].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ((([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ((CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END IS NOT NULL) AND ((CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [l2].[OneToMany_Optional_Inverse3Id]) OR ((CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END IS NULL) AND ([l2].[OneToMany_Optional_Inverse3Id] IS NULL))))) AND (([l2].[Level3_Name] <> N'Foo') OR ([l2].[Level3_Name] IS NULL)) + ORDER BY CASE + WHEN ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l2].[Id] + END + ) AS [t0] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l6].[Id] = [t3].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t0].[Id] + END = [t1].[OneToMany_Optional_Inverse4Id] + LEFT JOIN ( + SELECT [l9].[Id], [l9].[Level3_Optional_Id], [l9].[Level3_Required_Id], [l9].[Level4_Name], [l9].[OneToMany_Optional_Inverse4Id], [l9].[OneToMany_Required_Inverse4Id], [l9].[OneToOne_Optional_PK_Inverse4Id], [l9].[PeriodEnd], [l9].[PeriodStart], [t5].[Id] AS [Id0], [t5].[Id0] AS [Id00], [t5].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] + INNER JOIN ( + SELECT [l10].[Id], [t6].[Id] AS [Id0], [t6].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] + INNER JOIN ( + SELECT [l11].[Id], [l12].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l11] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l12] ON [l11].[Id] = [l12].[Id] + WHERE (([l11].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l11].[Level1_Required_Id] IS NOT NULL)) AND ([l11].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t6] ON [l10].[Id] = [t6].[Id] + WHERE ([l10].[Level2_Required_Id] IS NOT NULL) AND ([l10].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t5] ON [l9].[Id] = [t5].[Id] + WHERE ([l9].[Level3_Required_Id] IS NOT NULL) AND ([l9].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t4] ON CASE + WHEN ([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t0].[Id] + END = [t4].[OneToMany_Required_Inverse4Id] + ) AS [t7] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t8] ON [l].[Id] = [t8].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t8].[Id], [t8].[Id0], [t8].[c], [t8].[Id1], [t8].[Id00], [t8].[Id000], [t8].[Id10], [t8].[Id01], [t8].[Id0000], [t8].[Id00000], [t8].[Id2], [t8].[Id02], [t8].[Id001]"); + } + + public override async Task Filtered_include_complex_three_level_with_middle_having_filter2(bool async) + { + await base.Filtered_include_complex_three_level_with_middle_having_filter2(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t8].[Id], [t8].[OneToOne_Required_PK_Date], [t8].[Level1_Optional_Id], [t8].[Level1_Required_Id], [t8].[Level2_Name], [t8].[OneToMany_Optional_Inverse2Id], [t8].[OneToMany_Required_Inverse2Id], [t8].[OneToOne_Optional_PK_Inverse2Id], [t8].[PeriodEnd], [t8].[PeriodStart], [t8].[Id0], [t8].[Id1], [t8].[Level2_Optional_Id], [t8].[Level2_Required_Id], [t8].[Level3_Name], [t8].[OneToMany_Optional_Inverse3Id], [t8].[OneToMany_Required_Inverse3Id], [t8].[OneToOne_Optional_PK_Inverse3Id], [t8].[PeriodEnd0], [t8].[PeriodStart0], [t8].[Id00], [t8].[Id000], [t8].[Id10], [t8].[Level3_Optional_Id], [t8].[Level3_Required_Id], [t8].[Level4_Name], [t8].[OneToMany_Optional_Inverse4Id], [t8].[OneToMany_Required_Inverse4Id], [t8].[OneToOne_Optional_PK_Inverse4Id], [t8].[PeriodEnd00], [t8].[PeriodStart00], [t8].[Id01], [t8].[Id0000], [t8].[Id00000], [t8].[Id2], [t8].[Level3_Optional_Id0], [t8].[Level3_Required_Id0], [t8].[Level4_Name0], [t8].[OneToMany_Optional_Inverse4Id0], [t8].[OneToMany_Required_Inverse4Id0], [t8].[OneToOne_Optional_PK_Inverse4Id0], [t8].[PeriodEnd1], [t8].[PeriodStart1], [t8].[Id02], [t8].[Id001], [t8].[Id0001] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], [t7].[Id] AS [Id1], [t7].[Level2_Optional_Id], [t7].[Level2_Required_Id], [t7].[Level3_Name], [t7].[OneToMany_Optional_Inverse3Id], [t7].[OneToMany_Required_Inverse3Id], [t7].[OneToOne_Optional_PK_Inverse3Id], [t7].[PeriodEnd] AS [PeriodEnd0], [t7].[PeriodStart] AS [PeriodStart0], [t7].[Id0] AS [Id00], [t7].[Id00] AS [Id000], [t7].[Id1] AS [Id10], [t7].[Level3_Optional_Id], [t7].[Level3_Required_Id], [t7].[Level4_Name], [t7].[OneToMany_Optional_Inverse4Id], [t7].[OneToMany_Required_Inverse4Id], [t7].[OneToOne_Optional_PK_Inverse4Id], [t7].[PeriodEnd0] AS [PeriodEnd00], [t7].[PeriodStart0] AS [PeriodStart00], [t7].[Id01], [t7].[Id000] AS [Id0000], [t7].[Id0000] AS [Id00000], [t7].[Id2], [t7].[Level3_Optional_Id0], [t7].[Level3_Required_Id0], [t7].[Level4_Name0], [t7].[OneToMany_Optional_Inverse4Id0], [t7].[OneToMany_Required_Inverse4Id0], [t7].[OneToOne_Optional_PK_Inverse4Id0], [t7].[PeriodEnd1], [t7].[PeriodStart1], [t7].[Id02], [t7].[Id001], [t7].[Id0001], [t7].[c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + OUTER APPLY ( + SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00], [t1].[Id] AS [Id1], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id000], [t1].[Id000] AS [Id0000], [t4].[Id] AS [Id2], [t4].[Level3_Optional_Id] AS [Level3_Optional_Id0], [t4].[Level3_Required_Id] AS [Level3_Required_Id0], [t4].[Level4_Name] AS [Level4_Name0], [t4].[OneToMany_Optional_Inverse4Id] AS [OneToMany_Optional_Inverse4Id0], [t4].[OneToMany_Required_Inverse4Id] AS [OneToMany_Required_Inverse4Id0], [t4].[OneToOne_Optional_PK_Inverse4Id] AS [OneToOne_Optional_PK_Inverse4Id0], [t4].[PeriodEnd] AS [PeriodEnd1], [t4].[PeriodStart] AS [PeriodStart1], [t4].[Id0] AS [Id02], [t4].[Id00] AS [Id001], [t4].[Id000] AS [Id0001], [t0].[c] + FROM ( + SELECT TOP(1) [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00], CASE + WHEN ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l2].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ((([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ((CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END IS NOT NULL) AND ((CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [l2].[OneToMany_Optional_Inverse3Id]) OR ((CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END IS NULL) AND ([l2].[OneToMany_Optional_Inverse3Id] IS NULL))))) AND (([l2].[Level3_Name] <> N'Foo') OR ([l2].[Level3_Name] IS NULL)) + ORDER BY CASE + WHEN ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l2].[Id] + END + ) AS [t0] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l6].[Id] = [t3].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t0].[Id] + END = [t1].[OneToMany_Optional_Inverse4Id] + LEFT JOIN ( + SELECT [l9].[Id], [l9].[Level3_Optional_Id], [l9].[Level3_Required_Id], [l9].[Level4_Name], [l9].[OneToMany_Optional_Inverse4Id], [l9].[OneToMany_Required_Inverse4Id], [l9].[OneToOne_Optional_PK_Inverse4Id], [l9].[PeriodEnd], [l9].[PeriodStart], [t5].[Id] AS [Id0], [t5].[Id0] AS [Id00], [t5].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] + INNER JOIN ( + SELECT [l10].[Id], [t6].[Id] AS [Id0], [t6].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] + INNER JOIN ( + SELECT [l11].[Id], [l12].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l11] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l12] ON [l11].[Id] = [l12].[Id] + WHERE (([l11].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l11].[Level1_Required_Id] IS NOT NULL)) AND ([l11].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t6] ON [l10].[Id] = [t6].[Id] + WHERE ([l10].[Level2_Required_Id] IS NOT NULL) AND ([l10].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t5] ON [l9].[Id] = [t5].[Id] + WHERE ([l9].[Level3_Required_Id] IS NOT NULL) AND ([l9].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t4] ON CASE + WHEN ([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t0].[Id] + END = [t4].[OneToMany_Required_Inverse4Id] + ) AS [t7] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t8] ON [l].[Id] = [t8].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t8].[Id], [t8].[Id0], [t8].[c], [t8].[Id1], [t8].[Id00], [t8].[Id000], [t8].[Id10], [t8].[Id01], [t8].[Id0000], [t8].[Id00000], [t8].[Id2], [t8].[Id02], [t8].[Id001]"); + } + + public override async Task Filtered_include_context_accessed_inside_filter(bool async) + { + await base.Filtered_include_context_accessed_inside_filter(async); + + AssertSql( + @"SELECT COUNT(*) +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l]", + // + @"@__p_0='True' + +SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t].[c] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END) AS [row], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (@__p_0 = CAST(1 AS bit)) + ) AS [t] + WHERE [t].[row] <= 3 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[c], [t0].[Id]"); + } + + public override async Task Filtered_include_context_accessed_inside_filter_correlated(bool async) + { + await base.Filtered_include_context_accessed_inside_filter_correlated(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t].[c] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END) AS [row], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (( + SELECT COUNT(*) + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + WHERE [l2].[Id] <> [l0].[Id]) > 1) + ) AS [t] + WHERE [t].[row] <= 3 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[c], [t0].[Id]"); + } + + // TODO: remove later!!!!! + public override Task Filtered_include_is_considered_loaded(bool async) + { + return base.Filtered_include_is_considered_loaded(async); + } + + public override Task Filtered_include_calling_methods_directly_on_parameter_throws(bool async) + { + return base.Filtered_include_calling_methods_directly_on_parameter_throws(async); + } + + public override Task Filtered_include_different_filter_set_on_same_navigation_twice(bool async) + { + return base.Filtered_include_different_filter_set_on_same_navigation_twice(async); + } + + public override Task Filtered_include_different_filter_set_on_same_navigation_twice_multi_level(bool async) + { + return base.Filtered_include_different_filter_set_on_same_navigation_twice_multi_level(async); + } + + public override async Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(bool async) + { + await base.Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t4].[Id], [t4].[OneToOne_Required_PK_Date], [t4].[Level1_Optional_Id], [t4].[Level1_Required_Id], [t4].[Level2_Name], [t4].[OneToMany_Optional_Inverse2Id], [t4].[OneToMany_Required_Inverse2Id], [t4].[OneToOne_Optional_PK_Inverse2Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Id1], [t4].[Id00], [t4].[Id000], [t4].[Id2], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[Id01], [t4].[Id001], [t4].[Level2_Optional_Id0], [t4].[Level2_Required_Id0], [t4].[Level3_Name0], [t4].[OneToMany_Optional_Inverse3Id0], [t4].[OneToMany_Required_Inverse3Id0], [t4].[OneToOne_Optional_PK_Inverse3Id0], [t4].[PeriodEnd1], [t4].[PeriodStart1] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +OUTER APPLY ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [t2].[Id] AS [Id2], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd] AS [PeriodEnd0], [t2].[PeriodStart] AS [PeriodStart0], [t2].[Id0] AS [Id01], [t2].[Id00] AS [Id001], [t0].[Level2_Optional_Id] AS [Level2_Optional_Id0], [t0].[Level2_Required_Id] AS [Level2_Required_Id0], [t0].[Level3_Name] AS [Level3_Name0], [t0].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [t0].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [t0].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [t0].[PeriodEnd] AS [PeriodEnd1], [t0].[PeriodStart] AS [PeriodStart1], [t].[c] + FROM ( + SELECT TOP(2) [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id])) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END + ) AS [t] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] + END = [t0].[Level2_Required_Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level2_Optional_Id], [l5].[Level2_Required_Id], [l5].[Level3_Name], [l5].[OneToMany_Optional_Inverse3Id], [l5].[OneToMany_Required_Inverse3Id], [l5].[OneToOne_Optional_PK_Inverse3Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [l7].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] ON [l6].[Id] = [l7].[Id] + WHERE (([l6].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l6].[Level1_Required_Id] IS NOT NULL)) AND ([l6].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level2_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] + END = [t2].[OneToMany_Optional_Inverse3Id] +) AS [t4] +ORDER BY [l].[Id], [t4].[c], [t4].[Id], [t4].[Id0], [t4].[Id1], [t4].[Id00], [t4].[Id000], [t4].[Id2], [t4].[Id01]"); + } + + public override async Task Filtered_include_on_ThenInclude(bool async) + { + await base.Filtered_include_on_ThenInclude(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] + FROM ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], ROW_NUMBER() OVER(PARTITION BY [l2].[OneToMany_Optional_Inverse3Id] ORDER BY [l2].[Level3_Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l2].[Id] = [t2].[Id] + WHERE (([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND (([l2].[Level3_Name] <> N'Foo') OR ([l2].[Level3_Name] IS NULL)) + ) AS [t0] + WHERE (1 < [t0].[row]) AND ([t0].[row] <= 4) +) AS [t1] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t1].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t1].[OneToMany_Optional_Inverse3Id], [t1].[Level3_Name], [t1].[Id], [t1].[Id0]"); + } + + public override async Task Filtered_include_Skip_without_OrderBy(bool async) + { + await base.Filtered_include_Skip_without_OrderBy(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Id], [l1].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] + WHERE 1 < [t].[row] +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Filtered_include_Take_without_OrderBy(bool async) + { + await base.Filtered_include_Take_without_OrderBy(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Id], [l1].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Filtered_include_Take_with_another_Take_on_top_level(bool async) + { + await base.Filtered_include_Take_with_another_Take_on_top_level(async); + + AssertSql( + @"@__p_0='5' + +SELECT [t].[Id], [t].[Date], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd0], [t2].[PeriodStart0], [t2].[Id00], [t2].[Id01], [t2].[Id000] +FROM ( + SELECT TOP(@__p_0) [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Id] +) AS [t] +OUTER APPLY ( + SELECT [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t0].[Id0] AS [Id00], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id000] + FROM ( + SELECT TOP(4) [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) + ORDER BY [l0].[Level2_Name] DESC + ) AS [t0] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l2].[Id] = [t3].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level2_Optional_Id] +) AS [t2] +ORDER BY [t].[Id], [t2].[Level2_Name] DESC, [t2].[Id], [t2].[Id00], [t2].[Id0], [t2].[Id01]"); + } + + public override async Task Filtered_include_ThenInclude_OrderBy(bool async) + { + await base.Filtered_include_ThenInclude_OrderBy(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t1].[Id], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id1], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id00], [t1].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], [t0].[Id] AS [Id1], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToMany_Optional_Inverse3Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Level2_Name], [t1].[Id], [t1].[Id0], [t1].[Level3_Name] DESC, [t1].[Id1], [t1].[Id00]"); + } + + public override async Task Filtered_include_variable_used_inside_filter(bool async) + { + await base.Filtered_include_variable_used_inside_filter(async); + + AssertSql( + @"@__prm_0='Foo' (Size = 4000) + +SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t].[c] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END) AS [row], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (([l0].[Level2_Name] <> @__prm_0) OR ([l0].[Level2_Name] IS NULL)) + ) AS [t] + WHERE [t].[row] <= 3 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[c], [t0].[Id]"); + } + + public override async Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(bool async) + { + await base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(async); + + AssertSql( + @"SELECT [t].[Id], [t].[Date], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd0], [t2].[PeriodStart0], [t2].[Id00], [t2].[Id01], [t2].[Id000] +FROM ( + SELECT TOP(1) [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Id] +) AS [t] +OUTER APPLY ( + SELECT [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t0].[Id0] AS [Id00], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id000] + FROM ( + SELECT TOP(40) [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) + ) AS [t0] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l2].[Id] = [t3].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level2_Optional_Id] +) AS [t2] +ORDER BY [t].[Id], [t2].[Id], [t2].[Id00], [t2].[Id0], [t2].[Id01]"); + } + + public override async Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(bool async) + { + await base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(async); + + AssertSql( + @"@__p_0='30' + +SELECT [t].[Id], [t].[Date], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd0], [t2].[PeriodStart0], [t2].[Id00], [t2].[Id01], [t2].[Id000] +FROM ( + SELECT TOP(@__p_0) [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Id] +) AS [t] +OUTER APPLY ( + SELECT [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t0].[Id0] AS [Id00], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id000] + FROM ( + SELECT TOP(40) [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) + ) AS [t0] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l2].[Id] = [t3].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level2_Optional_Id] +) AS [t2] +ORDER BY [t].[Id], [t2].[Id], [t2].[Id00], [t2].[Id0], [t2].[Id01]"); + } + + public override async Task Filtered_ThenInclude_OrderBy(bool async) + { + await base.Filtered_ThenInclude_OrderBy(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t1].[Id], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id1], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id00], [t1].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], [t0].[Id] AS [Id1], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToMany_Optional_Inverse3Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Id], [t1].[Id0], [t1].[Level3_Name], [t1].[Id1], [t1].[Id00]"); + } + + public override async Task FirstOrDefault_with_predicate_on_correlated_collection_in_projection(bool async) + { + await base.FirstOrDefault_with_predicate_on_correlated_collection_in_projection(async); + + AssertSql( + @"SELECT [l].[Id], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END ORDER BY [l0].[Id], [l1].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON ([l].[Id] = [t0].[OneToMany_Optional_Inverse2Id]) AND ([l].[Id] = CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] +END)"); + } + + public override async Task Filtered_include_OrderBy(bool async) + { + await base.Filtered_include_OrderBy(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Level2_Name], [t].[Id]"); + } + + public override async Task Filtered_include_same_filter_set_on_same_navigation_twice(bool async) + { + await base.Filtered_include_same_filter_set_on_same_navigation_twice(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t].[c] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END DESC) AS [row], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[c] DESC, [t0].[Id]"); + } + + public override async Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async) + { + await base.Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t4].[Id], [t4].[OneToOne_Required_PK_Date], [t4].[Level1_Optional_Id], [t4].[Level1_Required_Id], [t4].[Level2_Name], [t4].[OneToMany_Optional_Inverse2Id], [t4].[OneToMany_Required_Inverse2Id], [t4].[OneToOne_Optional_PK_Inverse2Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Id1], [t4].[Id00], [t4].[Id000], [t4].[Id2], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[Id01], [t4].[Id001], [t4].[Level2_Optional_Id0], [t4].[Level2_Required_Id0], [t4].[Level3_Name0], [t4].[OneToMany_Optional_Inverse3Id0], [t4].[OneToMany_Required_Inverse3Id0], [t4].[OneToOne_Optional_PK_Inverse3Id0], [t4].[PeriodEnd1], [t4].[PeriodStart1] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +OUTER APPLY ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [t2].[Id] AS [Id2], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd] AS [PeriodEnd0], [t2].[PeriodStart] AS [PeriodStart0], [t2].[Id0] AS [Id01], [t2].[Id00] AS [Id001], [t0].[Level2_Optional_Id] AS [Level2_Optional_Id0], [t0].[Level2_Required_Id] AS [Level2_Required_Id0], [t0].[Level3_Name] AS [Level3_Name0], [t0].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [t0].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [t0].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [t0].[PeriodEnd] AS [PeriodEnd1], [t0].[PeriodStart] AS [PeriodStart1], [t].[c] + FROM ( + SELECT TOP(2) [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id])) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) + ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END + ) AS [t] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] + END = [t0].[Level2_Required_Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level2_Optional_Id], [l5].[Level2_Required_Id], [l5].[Level3_Name], [l5].[OneToMany_Optional_Inverse3Id], [l5].[OneToMany_Required_Inverse3Id], [l5].[OneToOne_Optional_PK_Inverse3Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [l7].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] ON [l6].[Id] = [l7].[Id] + WHERE (([l6].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l6].[Level1_Required_Id] IS NOT NULL)) AND ([l6].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level2_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] + END = [t2].[OneToMany_Optional_Inverse3Id] +) AS [t4] +ORDER BY [l].[Id], [t4].[c], [t4].[Id], [t4].[Id0], [t4].[Id1], [t4].[Id00], [t4].[Id000], [t4].[Id2], [t4].[Id01]"); + } + + public override async Task Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(bool async) + { + await base.Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(async); + + AssertSql( + @"@__p_0='10' +@__p_1='5' + +SELECT [t].[Id], [t].[Date], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd0], [t2].[PeriodStart0], [t2].[Id00], [t2].[Id01], [t2].[Id000] +FROM ( + SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Id] DESC + OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY +) AS [t] +OUTER APPLY ( + SELECT [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t0].[Id0] AS [Id00], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id000] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) + ORDER BY [l0].[Level2_Name] DESC + OFFSET 2 ROWS FETCH NEXT 4 ROWS ONLY + ) AS [t0] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l2].[Id] = [t3].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level2_Optional_Id] +) AS [t2] +ORDER BY [t].[Id] DESC, [t2].[Level2_Name] DESC, [t2].[Id], [t2].[Id00], [t2].[Id0], [t2].[Id01]"); + } + + public override async Task Include_after_SelectMany(bool async) + { + await base.Include_after_SelectMany(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Required_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Include_and_ThenInclude_collections_followed_by_projecting_the_first_collection(bool async) + { + await base.Include_and_ThenInclude_collections_followed_by_projecting_the_first_collection(async); + + AssertSql( + @"SELECT [l].[Id], [t1].[Id], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id1], [t1].[Id00], [t1].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [l1].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Id], [t1].[Id1], [t1].[Id0], [t1].[Id00]"); + } + + public override async Task Include_collection(bool async) + { + await base.Include_collection(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Id]"); + } + + public override async Task Include_collection_and_another_navigation_chain_followed_by_projecting_the_first_collection(bool async) + { + await base.Include_collection_and_another_navigation_chain_followed_by_projecting_the_first_collection(async); + + AssertSql( + @"SELECT [l].[Id], [t4].[Id], [t4].[OneToOne_Required_PK_Date], [t4].[Level1_Optional_Id], [t4].[Level1_Required_Id], [t4].[Level2_Name], [t4].[OneToMany_Optional_Inverse2Id], [t4].[OneToMany_Required_Inverse2Id], [t4].[OneToOne_Optional_PK_Inverse2Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[Id1], [t4].[Level3_Optional_Id], [t4].[Level3_Required_Id], [t4].[Level4_Name], [t4].[OneToMany_Optional_Inverse4Id], [t4].[OneToMany_Required_Inverse4Id], [t4].[OneToOne_Optional_PK_Inverse4Id], [t4].[PeriodEnd1], [t4].[PeriodStart1], [t4].[Id2], [t4].[Id00], [t4].[Id000], [t4].[Id01], [t4].[Id001], [t4].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t1].[Id] AS [Id1], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd1], [t1].[PeriodStart] AS [PeriodStart1], [l1].[Id] AS [Id2], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id001], [t1].[Id000] AS [Id0000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l6].[Id] = [t3].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level3_Optional_Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t4] ON [l].[Id] = [t4].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t4].[Id], [t4].[Id2], [t4].[Id0], [t4].[Id00], [t4].[Id000], [t4].[Id1], [t4].[Id01], [t4].[Id001]"); + } + + public override async Task Include_collection_followed_by_complex_includes_and_projecting_the_included_collection(bool async) + { + await base.Include_collection_followed_by_complex_includes_and_projecting_the_included_collection(async); + + AssertSql( + @"SELECT [l].[Id], [t9].[Id], [t9].[OneToOne_Required_PK_Date], [t9].[Level1_Optional_Id], [t9].[Level1_Required_Id], [t9].[Level2_Name], [t9].[OneToMany_Optional_Inverse2Id], [t9].[OneToMany_Required_Inverse2Id], [t9].[OneToOne_Optional_PK_Inverse2Id], [t9].[PeriodEnd], [t9].[PeriodStart], [t9].[Id0], [t9].[Level2_Optional_Id], [t9].[Level2_Required_Id], [t9].[Level3_Name], [t9].[OneToMany_Optional_Inverse3Id], [t9].[OneToMany_Required_Inverse3Id], [t9].[OneToOne_Optional_PK_Inverse3Id], [t9].[PeriodEnd0], [t9].[PeriodStart0], [t9].[Id1], [t9].[Level3_Optional_Id], [t9].[Level3_Required_Id], [t9].[Level4_Name], [t9].[OneToMany_Optional_Inverse4Id], [t9].[OneToMany_Required_Inverse4Id], [t9].[OneToOne_Optional_PK_Inverse4Id], [t9].[PeriodEnd1], [t9].[PeriodStart1], [t9].[Id2], [t9].[Level2_Optional_Id0], [t9].[Level2_Required_Id0], [t9].[Level3_Name0], [t9].[OneToMany_Optional_Inverse3Id0], [t9].[OneToMany_Required_Inverse3Id0], [t9].[OneToOne_Optional_PK_Inverse3Id0], [t9].[PeriodEnd2], [t9].[PeriodStart2], [t9].[Id3], [t9].[Id00], [t9].[Id000], [t9].[Id01], [t9].[Id001], [t9].[Id0000], [t9].[Id02], [t9].[Id002], [t9].[Id4], [t9].[Level3_Optional_Id0], [t9].[Level3_Required_Id0], [t9].[Level4_Name0], [t9].[OneToMany_Optional_Inverse4Id0], [t9].[OneToMany_Required_Inverse4Id0], [t9].[OneToOne_Optional_PK_Inverse4Id0], [t9].[PeriodEnd3], [t9].[PeriodStart3], [t9].[Id03], [t9].[Id003], [t9].[Id0001] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t1].[Id] AS [Id1], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd1], [t1].[PeriodStart] AS [PeriodStart1], [t4].[Id] AS [Id2], [t4].[Level2_Optional_Id] AS [Level2_Optional_Id0], [t4].[Level2_Required_Id] AS [Level2_Required_Id0], [t4].[Level3_Name] AS [Level3_Name0], [t4].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [t4].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [t4].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [t4].[PeriodEnd] AS [PeriodEnd2], [t4].[PeriodStart] AS [PeriodStart2], [l1].[Id] AS [Id3], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id001], [t1].[Id000] AS [Id0000], [t4].[Id0] AS [Id02], [t4].[Id00] AS [Id002], [t6].[Id] AS [Id4], [t6].[Level3_Optional_Id] AS [Level3_Optional_Id0], [t6].[Level3_Required_Id] AS [Level3_Required_Id0], [t6].[Level4_Name] AS [Level4_Name0], [t6].[OneToMany_Optional_Inverse4Id] AS [OneToMany_Optional_Inverse4Id0], [t6].[OneToMany_Required_Inverse4Id] AS [OneToMany_Required_Inverse4Id0], [t6].[OneToOne_Optional_PK_Inverse4Id] AS [OneToOne_Optional_PK_Inverse4Id0], [t6].[PeriodEnd] AS [PeriodEnd3], [t6].[PeriodStart] AS [PeriodStart3], [t6].[Id0] AS [Id03], [t6].[Id00] AS [Id003], [t6].[Id000] AS [Id0001] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l6].[Id] = [t3].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level3_Optional_Id] + LEFT JOIN ( + SELECT [l9].[Id], [l9].[Level2_Optional_Id], [l9].[Level2_Required_Id], [l9].[Level3_Name], [l9].[OneToMany_Optional_Inverse3Id], [l9].[OneToMany_Required_Inverse3Id], [l9].[OneToOne_Optional_PK_Inverse3Id], [l9].[PeriodEnd], [l9].[PeriodStart], [t5].[Id] AS [Id0], [t5].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] + INNER JOIN ( + SELECT [l10].[Id], [l11].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l11] ON [l10].[Id] = [l11].[Id] + WHERE (([l10].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l10].[Level1_Required_Id] IS NOT NULL)) AND ([l10].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t5] ON [l9].[Id] = [t5].[Id] + WHERE ([l9].[Level2_Required_Id] IS NOT NULL) AND ([l9].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t4] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t4].[Level2_Optional_Id] + LEFT JOIN ( + SELECT [l12].[Id], [l12].[Level3_Optional_Id], [l12].[Level3_Required_Id], [l12].[Level4_Name], [l12].[OneToMany_Optional_Inverse4Id], [l12].[OneToMany_Required_Inverse4Id], [l12].[OneToOne_Optional_PK_Inverse4Id], [l12].[PeriodEnd], [l12].[PeriodStart], [t7].[Id] AS [Id0], [t7].[Id0] AS [Id00], [t7].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l12] + INNER JOIN ( + SELECT [l13].[Id], [t8].[Id] AS [Id0], [t8].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l13] + INNER JOIN ( + SELECT [l14].[Id], [l15].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l14] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l15] ON [l14].[Id] = [l15].[Id] + WHERE (([l14].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l14].[Level1_Required_Id] IS NOT NULL)) AND ([l14].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t8] ON [l13].[Id] = [t8].[Id] + WHERE ([l13].[Level2_Required_Id] IS NOT NULL) AND ([l13].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t7] ON [l12].[Id] = [t7].[Id] + WHERE ([l12].[Level3_Required_Id] IS NOT NULL) AND ([l12].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t6] ON CASE + WHEN ((([t4].[Level2_Required_Id] IS NOT NULL) AND ([t4].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t4].[PeriodEnd] IS NOT NULL)) AND ([t4].[PeriodStart] IS NOT NULL) THEN [t4].[Id] + END = [t6].[OneToMany_Optional_Inverse4Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t9] ON [l].[Id] = [t9].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t9].[Id], [t9].[Id3], [t9].[Id0], [t9].[Id00], [t9].[Id000], [t9].[Id1], [t9].[Id01], [t9].[Id001], [t9].[Id0000], [t9].[Id2], [t9].[Id02], [t9].[Id002], [t9].[Id4], [t9].[Id03], [t9].[Id003]"); + } + + public override async Task Include_collection_followed_by_include_reference(bool async) + { + await base.Include_collection_followed_by_include_reference(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t1].[Id], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id1], [t1].[Id00], [t1].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [l1].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Id], [t1].[Id1], [t1].[Id0], [t1].[Id00]"); + } + + public override async Task Include_collection_followed_by_projecting_the_included_collection(bool async) + { + await base.Include_collection_followed_by_projecting_the_included_collection(async); + + AssertSql( + @"SELECT [l].[Id], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Id]"); + } + + public override async Task Include_collection_multiple(bool async) + { + await base.Include_collection_multiple(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t9].[Id], [t9].[OneToOne_Required_PK_Date], [t9].[Level1_Optional_Id], [t9].[Level1_Required_Id], [t9].[Level2_Name], [t9].[OneToMany_Optional_Inverse2Id], [t9].[OneToMany_Required_Inverse2Id], [t9].[OneToOne_Optional_PK_Inverse2Id], [t9].[PeriodEnd], [t9].[PeriodStart], [t9].[Id0], [t9].[Level2_Optional_Id], [t9].[Level2_Required_Id], [t9].[Level3_Name], [t9].[OneToMany_Optional_Inverse3Id], [t9].[OneToMany_Required_Inverse3Id], [t9].[OneToOne_Optional_PK_Inverse3Id], [t9].[PeriodEnd0], [t9].[PeriodStart0], [t9].[Id1], [t9].[Level3_Optional_Id], [t9].[Level3_Required_Id], [t9].[Level4_Name], [t9].[OneToMany_Optional_Inverse4Id], [t9].[OneToMany_Required_Inverse4Id], [t9].[OneToOne_Optional_PK_Inverse4Id], [t9].[PeriodEnd1], [t9].[PeriodStart1], [t9].[Id2], [t9].[Level2_Optional_Id0], [t9].[Level2_Required_Id0], [t9].[Level3_Name0], [t9].[OneToMany_Optional_Inverse3Id0], [t9].[OneToMany_Required_Inverse3Id0], [t9].[OneToOne_Optional_PK_Inverse3Id0], [t9].[PeriodEnd2], [t9].[PeriodStart2], [t9].[Id3], [t9].[Id00], [t9].[Id000], [t9].[Id01], [t9].[Id001], [t9].[Id0000], [t9].[Id02], [t9].[Id002], [t9].[Id4], [t9].[Level3_Optional_Id0], [t9].[Level3_Required_Id0], [t9].[Level4_Name0], [t9].[OneToMany_Optional_Inverse4Id0], [t9].[OneToMany_Required_Inverse4Id0], [t9].[OneToOne_Optional_PK_Inverse4Id0], [t9].[PeriodEnd3], [t9].[PeriodStart3], [t9].[Id03], [t9].[Id003], [t9].[Id0001] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t1].[Id] AS [Id1], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd1], [t1].[PeriodStart] AS [PeriodStart1], [t4].[Id] AS [Id2], [t4].[Level2_Optional_Id] AS [Level2_Optional_Id0], [t4].[Level2_Required_Id] AS [Level2_Required_Id0], [t4].[Level3_Name] AS [Level3_Name0], [t4].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [t4].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [t4].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [t4].[PeriodEnd] AS [PeriodEnd2], [t4].[PeriodStart] AS [PeriodStart2], [l1].[Id] AS [Id3], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id001], [t1].[Id000] AS [Id0000], [t4].[Id0] AS [Id02], [t4].[Id00] AS [Id002], [t6].[Id] AS [Id4], [t6].[Level3_Optional_Id] AS [Level3_Optional_Id0], [t6].[Level3_Required_Id] AS [Level3_Required_Id0], [t6].[Level4_Name] AS [Level4_Name0], [t6].[OneToMany_Optional_Inverse4Id] AS [OneToMany_Optional_Inverse4Id0], [t6].[OneToMany_Required_Inverse4Id] AS [OneToMany_Required_Inverse4Id0], [t6].[OneToOne_Optional_PK_Inverse4Id] AS [OneToOne_Optional_PK_Inverse4Id0], [t6].[PeriodEnd] AS [PeriodEnd3], [t6].[PeriodStart] AS [PeriodStart3], [t6].[Id0] AS [Id03], [t6].[Id00] AS [Id003], [t6].[Id000] AS [Id0001] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l6].[Id] = [t3].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level3_Optional_Id] + LEFT JOIN ( + SELECT [l9].[Id], [l9].[Level2_Optional_Id], [l9].[Level2_Required_Id], [l9].[Level3_Name], [l9].[OneToMany_Optional_Inverse3Id], [l9].[OneToMany_Required_Inverse3Id], [l9].[OneToOne_Optional_PK_Inverse3Id], [l9].[PeriodEnd], [l9].[PeriodStart], [t5].[Id] AS [Id0], [t5].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] + INNER JOIN ( + SELECT [l10].[Id], [l11].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l11] ON [l10].[Id] = [l11].[Id] + WHERE (([l10].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l10].[Level1_Required_Id] IS NOT NULL)) AND ([l10].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t5] ON [l9].[Id] = [t5].[Id] + WHERE ([l9].[Level2_Required_Id] IS NOT NULL) AND ([l9].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t4] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t4].[Level2_Optional_Id] + LEFT JOIN ( + SELECT [l12].[Id], [l12].[Level3_Optional_Id], [l12].[Level3_Required_Id], [l12].[Level4_Name], [l12].[OneToMany_Optional_Inverse4Id], [l12].[OneToMany_Required_Inverse4Id], [l12].[OneToOne_Optional_PK_Inverse4Id], [l12].[PeriodEnd], [l12].[PeriodStart], [t7].[Id] AS [Id0], [t7].[Id0] AS [Id00], [t7].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l12] + INNER JOIN ( + SELECT [l13].[Id], [t8].[Id] AS [Id0], [t8].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l13] + INNER JOIN ( + SELECT [l14].[Id], [l15].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l14] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l15] ON [l14].[Id] = [l15].[Id] + WHERE (([l14].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l14].[Level1_Required_Id] IS NOT NULL)) AND ([l14].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t8] ON [l13].[Id] = [t8].[Id] + WHERE ([l13].[Level2_Required_Id] IS NOT NULL) AND ([l13].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t7] ON [l12].[Id] = [t7].[Id] + WHERE ([l12].[Level3_Required_Id] IS NOT NULL) AND ([l12].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t6] ON CASE + WHEN ((([t4].[Level2_Required_Id] IS NOT NULL) AND ([t4].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t4].[PeriodEnd] IS NOT NULL)) AND ([t4].[PeriodStart] IS NOT NULL) THEN [t4].[Id] + END = [t6].[OneToMany_Optional_Inverse4Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t9] ON [l].[Id] = [t9].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t9].[Id], [t9].[Id3], [t9].[Id0], [t9].[Id00], [t9].[Id000], [t9].[Id1], [t9].[Id01], [t9].[Id001], [t9].[Id0000], [t9].[Id2], [t9].[Id02], [t9].[Id002], [t9].[Id4], [t9].[Id03], [t9].[Id003]"); + } + + public override async Task Include_collection_multiple_with_filter(bool async) + { + await base.Include_collection_multiple_with_filter(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t4].[Id], [t4].[OneToOne_Required_PK_Date], [t4].[Level1_Optional_Id], [t4].[Level1_Required_Id], [t4].[Level2_Name], [t4].[OneToMany_Optional_Inverse2Id], [t4].[OneToMany_Required_Inverse2Id], [t4].[OneToOne_Optional_PK_Inverse2Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[Id1], [t4].[Level3_Optional_Id], [t4].[Level3_Required_Id], [t4].[Level4_Name], [t4].[OneToMany_Optional_Inverse4Id], [t4].[OneToMany_Required_Inverse4Id], [t4].[OneToOne_Optional_PK_Inverse4Id], [t4].[PeriodEnd1], [t4].[PeriodStart1], [t4].[Id2], [t4].[Id00], [t4].[Id000], [t4].[Id01], [t4].[Id001], [t4].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[OneToOne_Required_PK_Date], [l5].[Level1_Optional_Id], [l5].[Level1_Required_Id], [l5].[Level2_Name], [l5].[OneToMany_Optional_Inverse2Id], [l5].[OneToMany_Required_Inverse2Id], [l5].[OneToOne_Optional_PK_Inverse2Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t2].[Id] AS [Id1], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id], [t2].[PeriodEnd] AS [PeriodEnd1], [t2].[PeriodStart] AS [PeriodStart1], [l6].[Id] AS [Id2], [t1].[Id0] AS [Id00], [t1].[Id00] AS [Id000], [t2].[Id0] AS [Id01], [t2].[Id00] AS [Id001], [t2].[Id000] AS [Id0000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + LEFT JOIN ( + SELECT [l7].[Id], [l7].[Level2_Optional_Id], [l7].[Level2_Required_Id], [l7].[Level3_Name], [l7].[OneToMany_Optional_Inverse3Id], [l7].[OneToMany_Required_Inverse3Id], [l7].[OneToOne_Optional_PK_Inverse3Id], [l7].[PeriodEnd], [l7].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN ( + SELECT [l8].[Id], [l9].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] ON [l8].[Id] = [l9].[Id] + WHERE (([l8].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l8].[Level1_Required_Id] IS NOT NULL)) AND ([l8].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l7].[Id] = [t3].[Id] + WHERE ([l7].[Level2_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l5].[Id] + END = [t1].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN ( + SELECT [l10].[Id], [l10].[Level3_Optional_Id], [l10].[Level3_Required_Id], [l10].[Level4_Name], [l10].[OneToMany_Optional_Inverse4Id], [l10].[OneToMany_Required_Inverse4Id], [l10].[OneToOne_Optional_PK_Inverse4Id], [l10].[PeriodEnd], [l10].[PeriodStart], [t5].[Id] AS [Id0], [t5].[Id0] AS [Id00], [t5].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] + INNER JOIN ( + SELECT [l11].[Id], [t6].[Id] AS [Id0], [t6].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l11] + INNER JOIN ( + SELECT [l12].[Id], [l13].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l12] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l13] ON [l12].[Id] = [l13].[Id] + WHERE (([l12].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l12].[Level1_Required_Id] IS NOT NULL)) AND ([l12].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t6] ON [l11].[Id] = [t6].[Id] + WHERE ([l11].[Level2_Required_Id] IS NOT NULL) AND ([l11].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t5] ON [l10].[Id] = [t5].[Id] + WHERE ([l10].[Level3_Required_Id] IS NOT NULL) AND ([l10].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t2] ON CASE + WHEN ((([t1].[Level2_Required_Id] IS NOT NULL) AND ([t1].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t1].[PeriodEnd] IS NOT NULL)) AND ([t1].[PeriodStart] IS NOT NULL) THEN [t1].[Id] + END = [t2].[Level3_Optional_Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t4] ON [l].[Id] = [t4].[OneToMany_Optional_Inverse2Id] +WHERE ( + SELECT COUNT(*) + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Optional_Id], [l3].[Level1_Required_Id], [l3].[Level2_Name], [l3].[OneToMany_Optional_Inverse2Id], [l3].[OneToMany_Required_Inverse2Id], [l3].[OneToOne_Optional_PK_Inverse2Id], [l3].[PeriodEnd], [l3].[PeriodStart], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + WHERE (((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([l].[Id] = [l0].[OneToMany_Optional_Inverse2Id])) AND (([t0].[Level3_Name] <> N'Foo') OR ([t0].[Level3_Name] IS NULL))) > 0 +ORDER BY [l].[Id], [t4].[Id], [t4].[Id2], [t4].[Id0], [t4].[Id00], [t4].[Id000], [t4].[Id1], [t4].[Id01], [t4].[Id001]"); + } + + public override async Task Include_collection_ThenInclude_reference_followed_by_projection_into_anonmous_type(bool async) + { + await base.Include_collection_ThenInclude_reference_followed_by_projection_into_anonmous_type(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t1].[Id], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id1], [t1].[Id00], [t1].[Id000], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd0], [t2].[PeriodStart0], [t2].[Id1], [t2].[Id00], [t2].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [l1].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[OneToOne_Required_PK_Date], [l5].[Level1_Optional_Id], [l5].[Level1_Required_Id], [l5].[Level2_Name], [l5].[OneToMany_Optional_Inverse2Id], [l5].[OneToMany_Required_Inverse2Id], [l5].[OneToOne_Optional_PK_Inverse2Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd] AS [PeriodEnd0], [t3].[PeriodStart] AS [PeriodStart0], [l6].[Id] AS [Id1], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + LEFT JOIN ( + SELECT [l7].[Id], [l7].[Level2_Optional_Id], [l7].[Level2_Required_Id], [l7].[Level3_Name], [l7].[OneToMany_Optional_Inverse3Id], [l7].[OneToMany_Required_Inverse3Id], [l7].[OneToOne_Optional_PK_Inverse3Id], [l7].[PeriodEnd], [l7].[PeriodStart], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN ( + SELECT [l8].[Id], [l9].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] ON [l8].[Id] = [l9].[Id] + WHERE (([l8].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l8].[Level1_Required_Id] IS NOT NULL)) AND ([l8].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l7].[Id] = [t4].[Id] + WHERE ([l7].[Level2_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON CASE + WHEN (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l5].[Id] + END = [t3].[OneToOne_Optional_PK_Inverse3Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t2] ON [l].[Id] = [t2].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Id], [t1].[Id1], [t1].[Id0], [t1].[Id00], [t1].[Id000], [t2].[Id], [t2].[Id1], [t2].[Id0], [t2].[Id00]"); + } + + public override async Task Include_collection_ThenInclude_two_references(bool async) + { + await base.Include_collection_ThenInclude_two_references(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t4].[Id], [t4].[OneToOne_Required_PK_Date], [t4].[Level1_Optional_Id], [t4].[Level1_Required_Id], [t4].[Level2_Name], [t4].[OneToMany_Optional_Inverse2Id], [t4].[OneToMany_Required_Inverse2Id], [t4].[OneToOne_Optional_PK_Inverse2Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[Id1], [t4].[Level3_Optional_Id], [t4].[Level3_Required_Id], [t4].[Level4_Name], [t4].[OneToMany_Optional_Inverse4Id], [t4].[OneToMany_Required_Inverse4Id], [t4].[OneToOne_Optional_PK_Inverse4Id], [t4].[PeriodEnd1], [t4].[PeriodStart1], [t4].[Id2], [t4].[Id00], [t4].[Id000], [t4].[Id01], [t4].[Id001], [t4].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t1].[Id] AS [Id1], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd1], [t1].[PeriodStart] AS [PeriodStart1], [l1].[Id] AS [Id2], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id001], [t1].[Id000] AS [Id0000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l6].[Id] = [t3].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level3_Optional_Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t4] ON [l].[Id] = [t4].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t4].[Id], [t4].[Id2], [t4].[Id0], [t4].[Id00], [t4].[Id000], [t4].[Id1], [t4].[Id01], [t4].[Id001]"); + } + + public override async Task Include_collection_then_reference(bool async) + { + await base.Include_collection_then_reference(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t1].[Id], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id1], [t1].[Id00], [t1].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [t0].[Id] AS [Id0], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [l1].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[Level2_Optional_Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Id], [t1].[Id1], [t1].[Id0], [t1].[Id00]"); + } + + public override async Task Include_collection_with_conditional_order_by(bool async) + { + await base.Include_collection_with_conditional_order_by(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +ORDER BY CASE + WHEN ([l].[Name] IS NOT NULL) AND ([l].[Name] LIKE N'%03') THEN 1 + ELSE 2 +END, [l].[Id], [t].[Id]"); + } + + public override async Task Include_collection_with_groupby_in_subquery(bool async) + { + await base.Include_collection_with_groupby_in_subquery(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart], [t].[Name], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0] +FROM ( + SELECT [l].[Name] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Name] +) AS [t] +LEFT JOIN ( + SELECT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l0].[Name] ORDER BY [l0].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[Name] = [t0].[Name] +LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Level2_Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[PeriodEnd], [l1].[PeriodStart], [l2].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] ON [l1].[Id] = [l2].[Id] + WHERE (([l1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l1].[Level1_Required_Id] IS NOT NULL)) AND ([l1].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t2] ON [t0].[Id] = [t2].[OneToMany_Optional_Inverse2Id] +ORDER BY [t].[Name], [t0].[Id], [t2].[Id]"); + } + + public override async Task Include_collection_with_groupby_in_subquery_and_filter_after_groupby(bool async) + { + await base.Include_collection_with_groupby_in_subquery_and_filter_after_groupby(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart], [t].[Name], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0] +FROM ( + SELECT [l].[Name] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Name] + HAVING ([l].[Name] <> N'Foo') OR ([l].[Name] IS NULL) +) AS [t] +LEFT JOIN ( + SELECT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l0].[Name] ORDER BY [l0].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[Name] = [t0].[Name] +LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Level2_Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[PeriodEnd], [l1].[PeriodStart], [l2].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] ON [l1].[Id] = [l2].[Id] + WHERE (([l1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l1].[Level1_Required_Id] IS NOT NULL)) AND ([l1].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t2] ON [t0].[Id] = [t2].[OneToMany_Optional_Inverse2Id] +ORDER BY [t].[Name], [t0].[Id], [t2].[Id]"); + } + + public override async Task Include_collection_with_groupby_in_subquery_and_filter_before_groupby(bool async) + { + await base.Include_collection_with_groupby_in_subquery_and_filter_before_groupby(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart], [t].[Name], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0] +FROM ( + SELECT [l].[Name] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + WHERE [l].[Id] > 3 + GROUP BY [l].[Name] +) AS [t] +LEFT JOIN ( + SELECT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l0].[Name] ORDER BY [l0].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + WHERE [l0].[Id] > 3 + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[Name] = [t0].[Name] +LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Level2_Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[PeriodEnd], [l1].[PeriodStart], [l2].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] ON [l1].[Id] = [l2].[Id] + WHERE (([l1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l1].[Level1_Required_Id] IS NOT NULL)) AND ([l1].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t2] ON [t0].[Id] = [t2].[OneToMany_Optional_Inverse2Id] +ORDER BY [t].[Name], [t0].[Id], [t2].[Id]"); + } + + public override async Task Include_nested_with_optional_navigation(bool async) + { + await base.Include_nested_with_optional_navigation(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t3].[Id], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd], [t3].[PeriodStart], [t3].[Id0], [t3].[Level3_Optional_Id], [t3].[Level3_Required_Id], [t3].[Level4_Name], [t3].[OneToMany_Optional_Inverse4Id], [t3].[OneToMany_Required_Inverse4Id], [t3].[OneToOne_Optional_PK_Inverse4Id], [t3].[PeriodEnd0], [t3].[PeriodStart0], [t3].[Id1], [t3].[Id00], [t3].[Id01], [t3].[Id000], [t3].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t0].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id000], [t1].[Id000] AS [Id0000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t0] ON [l2].[Id] = [t0].[Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l2].[Id] + END = [t1].[Level3_Required_Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t3] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t3].[OneToMany_Required_Inverse3Id] +WHERE ([t].[Level2_Name] <> N'L2 09') OR ([t].[Level2_Name] IS NULL) +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t3].[Id], [t3].[Id1], [t3].[Id00], [t3].[Id0], [t3].[Id01], [t3].[Id000]"); + } + + public override async Task Include_partially_added_before_Where_and_then_build_upon(bool async) + { + await base.Include_partially_added_before_Where_and_then_build_upon(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t].[Id], [t].[Id0], [t0].[Id0], [t3].[Id], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd], [t3].[PeriodStart], [t3].[Id0], [t3].[Level3_Optional_Id], [t3].[Level3_Required_Id], [t3].[Level4_Name], [t3].[OneToMany_Optional_Inverse4Id], [t3].[OneToMany_Required_Inverse4Id], [t3].[OneToOne_Optional_PK_Inverse4Id], [t3].[PeriodEnd0], [t3].[PeriodStart0], [t3].[Id1], [t3].[Id00], [t3].[Id01], [t3].[Id000], [t3].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToOne_Optional_PK_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[OneToOne_Required_PK_Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Level2_Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[PeriodEnd], [l2].[PeriodStart], [l3].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] ON [l2].[Id] = [l3].[Id] + WHERE (([l2].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l2].[Level1_Required_Id] IS NOT NULL)) AND ([l2].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l4].[Id], [l4].[Level2_Optional_Id], [l4].[Level2_Required_Id], [l4].[Level3_Name], [l4].[OneToMany_Optional_Inverse3Id], [l4].[OneToMany_Required_Inverse3Id], [l4].[OneToOne_Optional_PK_Inverse3Id], [l4].[PeriodEnd], [l4].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id], [t2].[PeriodEnd] AS [PeriodEnd0], [t2].[PeriodStart] AS [PeriodStart0], [t1].[Id] AS [Id1], [t1].[Id0] AS [Id00], [t2].[Id0] AS [Id01], [t2].[Id00] AS [Id000], [t2].[Id000] AS [Id0000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] + INNER JOIN ( + SELECT [l5].[Id], [l6].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l4].[Id] = [t1].[Id] + LEFT JOIN ( + SELECT [l7].[Id], [l7].[Level3_Optional_Id], [l7].[Level3_Required_Id], [l7].[Level4_Name], [l7].[OneToMany_Optional_Inverse4Id], [l7].[OneToMany_Required_Inverse4Id], [l7].[OneToOne_Optional_PK_Inverse4Id], [l7].[PeriodEnd], [l7].[PeriodStart], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00], [t4].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN ( + SELECT [l8].[Id], [t5].[Id] AS [Id0], [t5].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN ( + SELECT [l9].[Id], [l10].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] ON [l9].[Id] = [l10].[Id] + WHERE (([l9].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l9].[Level1_Required_Id] IS NOT NULL)) AND ([l9].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t5] ON [l8].[Id] = [t5].[Id] + WHERE ([l8].[Level2_Required_Id] IS NOT NULL) AND ([l8].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t4] ON [l7].[Id] = [t4].[Id] + WHERE ([l7].[Level3_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t2] ON CASE + WHEN ([l4].[Level2_Required_Id] IS NOT NULL) AND ([l4].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l4].[Id] + END = [t2].[Level3_Optional_Id] + WHERE ([l4].[Level2_Required_Id] IS NOT NULL) AND ([l4].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t3] ON CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t3].[OneToMany_Optional_Inverse3Id] +WHERE (CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END < 3) OR (CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END > 8) +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t3].[Id], [t3].[Id1], [t3].[Id00], [t3].[Id0], [t3].[Id01], [t3].[Id000]"); + } + + public override async Task Include_partially_added_before_Where_and_then_build_upon_with_filtered_include(bool async) + { + await base.Include_partially_added_before_Where_and_then_build_upon_with_filtered_include(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t].[Id], [t].[Id0], [t0].[Id0], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id00], [t4].[Id], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Level3_Optional_Id], [t4].[Level3_Required_Id], [t4].[Level4_Name], [t4].[OneToMany_Optional_Inverse4Id], [t4].[OneToMany_Required_Inverse4Id], [t4].[OneToOne_Optional_PK_Inverse4Id], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[Id1], [t4].[Id00], [t4].[Id01], [t4].[Id000], [t4].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToOne_Optional_PK_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[OneToOne_Required_PK_Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Level2_Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[PeriodEnd], [l2].[PeriodStart], [l3].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] ON [l2].[Id] = [l3].[Id] + WHERE (([l2].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l2].[Level1_Required_Id] IS NOT NULL)) AND ([l2].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [t2].[Id], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Id00], [t2].[c] + FROM ( + SELECT [l4].[Id], [l4].[Level2_Optional_Id], [l4].[Level2_Required_Id], [l4].[Level3_Name], [l4].[OneToMany_Optional_Inverse3Id], [l4].[OneToMany_Required_Inverse3Id], [l4].[OneToOne_Optional_PK_Inverse3Id], [l4].[PeriodEnd], [l4].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00], ROW_NUMBER() OVER(PARTITION BY [l4].[OneToMany_Optional_Inverse3Id] ORDER BY CASE + WHEN ([l4].[Level2_Required_Id] IS NOT NULL) AND ([l4].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l4].[Id] + END) AS [row], CASE + WHEN ([l4].[Level2_Required_Id] IS NOT NULL) AND ([l4].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l4].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] + INNER JOIN ( + SELECT [l5].[Id], [l6].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l4].[Id] = [t3].[Id] + WHERE ([l4].[Level2_Required_Id] IS NOT NULL) AND ([l4].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] + WHERE [t2].[row] <= 3 +) AS [t1] ON CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t1].[OneToMany_Optional_Inverse3Id] +LEFT JOIN ( + SELECT [l7].[Id], [l7].[Level2_Optional_Id], [l7].[Level2_Required_Id], [l7].[Level3_Name], [l7].[OneToMany_Optional_Inverse3Id], [l7].[OneToMany_Required_Inverse3Id], [l7].[OneToOne_Optional_PK_Inverse3Id], [l7].[PeriodEnd], [l7].[PeriodStart], [t6].[Id] AS [Id0], [t6].[Level3_Optional_Id], [t6].[Level3_Required_Id], [t6].[Level4_Name], [t6].[OneToMany_Optional_Inverse4Id], [t6].[OneToMany_Required_Inverse4Id], [t6].[OneToOne_Optional_PK_Inverse4Id], [t6].[PeriodEnd] AS [PeriodEnd0], [t6].[PeriodStart] AS [PeriodStart0], [t5].[Id] AS [Id1], [t5].[Id0] AS [Id00], [t6].[Id0] AS [Id01], [t6].[Id00] AS [Id000], [t6].[Id000] AS [Id0000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN ( + SELECT [l8].[Id], [l9].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] ON [l8].[Id] = [l9].[Id] + WHERE (([l8].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l8].[Level1_Required_Id] IS NOT NULL)) AND ([l8].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t5] ON [l7].[Id] = [t5].[Id] + LEFT JOIN ( + SELECT [l10].[Id], [l10].[Level3_Optional_Id], [l10].[Level3_Required_Id], [l10].[Level4_Name], [l10].[OneToMany_Optional_Inverse4Id], [l10].[OneToMany_Required_Inverse4Id], [l10].[OneToOne_Optional_PK_Inverse4Id], [l10].[PeriodEnd], [l10].[PeriodStart], [t7].[Id] AS [Id0], [t7].[Id0] AS [Id00], [t7].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] + INNER JOIN ( + SELECT [l11].[Id], [t8].[Id] AS [Id0], [t8].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l11] + INNER JOIN ( + SELECT [l12].[Id], [l13].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l12] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l13] ON [l12].[Id] = [l13].[Id] + WHERE (([l12].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l12].[Level1_Required_Id] IS NOT NULL)) AND ([l12].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t8] ON [l11].[Id] = [t8].[Id] + WHERE ([l11].[Level2_Required_Id] IS NOT NULL) AND ([l11].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t7] ON [l10].[Id] = [t7].[Id] + WHERE ([l10].[Level3_Required_Id] IS NOT NULL) AND ([l10].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t6] ON CASE + WHEN ([l7].[Level2_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l7].[Id] + END = [t6].[Level3_Optional_Id] + WHERE ([l7].[Level2_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t4] ON CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t4].[OneToMany_Required_Inverse3Id] +WHERE (CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END < 3) OR (CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END > 8) +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t1].[OneToMany_Optional_Inverse3Id], [t1].[c], [t1].[Id], [t1].[Id0], [t1].[Id00], [t4].[Id], [t4].[Id1], [t4].[Id00], [t4].[Id0], [t4].[Id01], [t4].[Id000]"); + } + + public override async Task Include_reference_and_collection_order_by(bool async) + { + await base.Include_reference_and_collection_order_by(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Name], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Include_reference_collection_order_by_reference_navigation(bool async) + { + await base.Include_reference_collection_order_by_reference_navigation(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END, [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Include_reference_followed_by_include_collection(bool async) + { + await base.Include_reference_followed_by_include_collection(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Include_reference_ThenInclude_collection_order_by(bool async) + { + await base.Include_reference_ThenInclude_collection_order_by(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Name], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Include_ThenInclude_ThenInclude_followed_by_two_nested_selects(bool async) + { + await base.Include_ThenInclude_ThenInclude_followed_by_two_nested_selects(async); + + AssertSql( + @"SELECT [l].[Id], [t4].[Id], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Level3_Optional_Id], [t4].[Level3_Required_Id], [t4].[Level4_Name], [t4].[OneToMany_Optional_Inverse4Id], [t4].[OneToMany_Required_Inverse4Id], [t4].[OneToOne_Optional_PK_Inverse4Id], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[Id1], [t4].[Id2], [t4].[Id00], [t4].[Id000], [t4].[Id01], [t4].[Id001], [t4].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [l0].[Id] AS [Id1], [l1].[Id] AS [Id2], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id001], [t1].[Id000] AS [Id0000], [l0].[OneToMany_Optional_Inverse2Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToOne_Optional_PK_Inverse3Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l6].[Id] = [t3].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] + END = [t1].[Level3_Optional_Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t4] ON [l].[Id] = [t4].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t4].[Id1], [t4].[Id2], [t4].[Id], [t4].[Id00], [t4].[Id000], [t4].[Id0], [t4].[Id01], [t4].[Id001]"); + } + + public override async Task Including_reference_navigation_and_projecting_collection_navigation(bool async) + { + await base.Including_reference_navigation_and_projecting_collection_navigation(async); + + AssertSql( + @"SELECT [l].[Id], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t].[Id0], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Required_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[Level2_Optional_Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[OneToOne_Required_PK_Date], [l5].[Level1_Optional_Id], [l5].[Level1_Required_Id], [l5].[Level2_Name], [l5].[OneToMany_Optional_Inverse2Id], [l5].[OneToMany_Required_Inverse2Id], [l5].[OneToOne_Optional_PK_Inverse2Id], [l5].[PeriodEnd], [l5].[PeriodStart], [l6].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t2] ON [l].[Id] = [t2].[OneToMany_Required_Inverse2Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id]"); + } + + public override async Task LeftJoin_with_Any_on_outer_source_and_projecting_collection_from_inner(bool async) + { + await base.LeftJoin_with_Any_on_outer_source_and_projecting_collection_from_inner(async); + + AssertSql( + @"SELECT CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NULL) OR ([t0].[Level1_Required_Id] IS NULL)) OR ([t0].[OneToMany_Required_Inverse2Id] IS NULL)) OR (CASE + WHEN ([t0].[PeriodEnd0] IS NOT NULL) AND ([t0].[PeriodStart0] IS NOT NULL) THEN [t0].[PeriodEnd0] + END IS NULL)) OR (CASE + WHEN ([t0].[PeriodEnd0] IS NOT NULL) AND ([t0].[PeriodStart0] IS NOT NULL) THEN [t0].[PeriodStart0] + END IS NULL) THEN 0 + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd0] IS NOT NULL)) AND ([t0].[PeriodStart0] IS NOT NULL) THEN [t0].[Id0] +END, [l].[Id], [t0].[Id], [t0].[Id0], [t0].[Id00], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [t].[Id] AS [Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id], [t].[PeriodEnd] AS [PeriodEnd0], [t].[PeriodStart] AS [PeriodStart0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[PeriodEnd], [l1].[PeriodStart], [l2].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] ON [l1].[Id] = [l2].[Id] + WHERE (([l1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l1].[Level1_Required_Id] IS NOT NULL)) AND ([l1].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l0].[Id] = CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] + END + WHERE (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[PeriodEnd] + END IS NOT NULL)) AND (CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[PeriodStart] + END IS NOT NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Required_Id] +LEFT JOIN ( + SELECT [l3].[Id], [l3].[Level2_Optional_Id], [l3].[Level2_Required_Id], [l3].[Level3_Name], [l3].[OneToMany_Optional_Inverse3Id], [l3].[OneToMany_Required_Inverse3Id], [l3].[OneToOne_Optional_PK_Inverse3Id], [l3].[PeriodEnd], [l3].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN ( + SELECT [l4].[Id], [l5].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] ON [l4].[Id] = [l5].[Id] + WHERE (([l4].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l4].[Level1_Required_Id] IS NOT NULL)) AND ([l4].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l3].[Id] = [t2].[Id] + WHERE ([l3].[Level2_Required_Id] IS NOT NULL) AND ([l3].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t1] ON CASE + WHEN (((([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t0].[PeriodEnd0] IS NOT NULL)) AND ([t0].[PeriodStart0] IS NOT NULL) THEN [t0].[Id0] +END = [t1].[OneToMany_Required_Inverse3Id] +WHERE [l].[Name] IN (N'L1 01', N'L1 02') +ORDER BY [l].[Id], [t0].[Id], [t0].[Id0], [t0].[Id00], [t1].[Id], [t1].[Id0]"); + } + + public override async Task Lift_projection_mapping_when_pushing_down_subquery(bool async) + { + await base.Lift_projection_mapping_when_pushing_down_subquery(async); + + AssertSql( + @"@__p_0='25' + +SELECT [t].[Id], [t0].[Id0], [t0].[Id1], [t2].[Id], [t2].[Id0], [t2].[Id1], [t0].[Id], [t0].[c] +FROM ( + SELECT TOP(@__p_0) [l].[Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +) AS [t] +LEFT JOIN ( + SELECT [t1].[Id], [t1].[c], [t1].[Id0], [t1].[Id1], [t1].[OneToMany_Required_Inverse2Id] + FROM ( + SELECT CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [Id], 1 AS [c], [l0].[Id] AS [Id0], [l1].[Id] AS [Id1], [l0].[OneToMany_Required_Inverse2Id], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Required_Inverse2Id] ORDER BY [l0].[Id], [l1].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] + WHERE [t1].[row] <= 1 +) AS [t0] ON [t].[Id] = [t0].[OneToMany_Required_Inverse2Id] +LEFT JOIN ( + SELECT CASE + WHEN (([l2].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l2].[Level1_Required_Id] IS NOT NULL)) AND ([l2].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l2].[Id] + END AS [Id], [l2].[Id] AS [Id0], [l3].[Id] AS [Id1], [l2].[OneToMany_Required_Inverse2Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] ON [l2].[Id] = [l3].[Id] + WHERE (([l2].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l2].[Level1_Required_Id] IS NOT NULL)) AND ([l2].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t2] ON [t].[Id] = [t2].[OneToMany_Required_Inverse2Id] +ORDER BY [t].[Id], [t0].[Id0], [t0].[Id1], [t2].[Id0]"); + } + + public override async Task Multiple_complex_includes(bool async) + { + await base.Multiple_complex_includes(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd0], [t2].[PeriodStart0], [t2].[Id1], [t2].[Id00], [t2].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[OneToOne_Required_PK_Date], [l5].[Level1_Optional_Id], [l5].[Level1_Required_Id], [l5].[Level2_Name], [l5].[OneToMany_Optional_Inverse2Id], [l5].[OneToMany_Required_Inverse2Id], [l5].[OneToOne_Optional_PK_Inverse2Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd] AS [PeriodEnd0], [t3].[PeriodStart] AS [PeriodStart0], [l6].[Id] AS [Id1], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + LEFT JOIN ( + SELECT [l7].[Id], [l7].[Level2_Optional_Id], [l7].[Level2_Required_Id], [l7].[Level3_Name], [l7].[OneToMany_Optional_Inverse3Id], [l7].[OneToMany_Required_Inverse3Id], [l7].[OneToOne_Optional_PK_Inverse3Id], [l7].[PeriodEnd], [l7].[PeriodStart], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN ( + SELECT [l8].[Id], [l9].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] ON [l8].[Id] = [l9].[Id] + WHERE (([l8].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l8].[Level1_Required_Id] IS NOT NULL)) AND ([l8].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l7].[Id] = [t4].[Id] + WHERE ([l7].[Level2_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON CASE + WHEN (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l5].[Id] + END = [t3].[Level2_Optional_Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t2] ON [l].[Id] = [t2].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id1], [t2].[Id0], [t2].[Id00]"); + } + + public override async Task Multiple_complex_include_select(bool async) + { + await base.Multiple_complex_include_select(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd0], [t2].[PeriodStart0], [t2].[Id1], [t2].[Id00], [t2].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[OneToOne_Required_PK_Date], [l5].[Level1_Optional_Id], [l5].[Level1_Required_Id], [l5].[Level2_Name], [l5].[OneToMany_Optional_Inverse2Id], [l5].[OneToMany_Required_Inverse2Id], [l5].[OneToOne_Optional_PK_Inverse2Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd] AS [PeriodEnd0], [t3].[PeriodStart] AS [PeriodStart0], [l6].[Id] AS [Id1], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + LEFT JOIN ( + SELECT [l7].[Id], [l7].[Level2_Optional_Id], [l7].[Level2_Required_Id], [l7].[Level3_Name], [l7].[OneToMany_Optional_Inverse3Id], [l7].[OneToMany_Required_Inverse3Id], [l7].[OneToOne_Optional_PK_Inverse3Id], [l7].[PeriodEnd], [l7].[PeriodStart], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN ( + SELECT [l8].[Id], [l9].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] ON [l8].[Id] = [l9].[Id] + WHERE (([l8].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l8].[Level1_Required_Id] IS NOT NULL)) AND ([l8].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l7].[Id] = [t4].[Id] + WHERE ([l7].[Level2_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON CASE + WHEN (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l5].[Id] + END = [t3].[Level2_Optional_Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t2] ON [l].[Id] = [t2].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id1], [t2].[Id0], [t2].[Id00]"); + } + + public override async Task Multiple_include_with_multiple_optional_navigations(bool async) + { + await base.Multiple_include_with_multiple_optional_navigations(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id0], [t2].[Id00], [t4].[Id], [t4].[Id0], [t5].[Id], [t5].[Id0], [t5].[Id00], [t7].[Id], [t7].[Level2_Optional_Id], [t7].[Level2_Required_Id], [t7].[Level3_Name], [t7].[OneToMany_Optional_Inverse3Id], [t7].[OneToMany_Required_Inverse3Id], [t7].[OneToOne_Optional_PK_Inverse3Id], [t7].[PeriodEnd], [t7].[PeriodStart], [t7].[Id0], [t7].[Id00], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t4].[OneToOne_Required_PK_Date], [t4].[Level1_Optional_Id], [t4].[Level1_Required_Id], [t4].[Level2_Name], [t4].[OneToMany_Optional_Inverse2Id], [t4].[OneToMany_Required_Inverse2Id], [t4].[OneToOne_Optional_PK_Inverse2Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t5].[Level2_Optional_Id], [t5].[Level2_Required_Id], [t5].[Level3_Name], [t5].[OneToMany_Optional_Inverse3Id], [t5].[OneToMany_Required_Inverse3Id], [t5].[OneToOne_Optional_PK_Inverse3Id], [t5].[PeriodEnd], [t5].[PeriodStart] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Required_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level3_Name], [l2].[OneToOne_Optional_PK_Inverse3Id], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToOne_Optional_PK_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level2_Optional_Id], [l5].[Level2_Required_Id], [l5].[Level3_Name], [l5].[OneToMany_Optional_Inverse3Id], [l5].[OneToMany_Required_Inverse3Id], [l5].[OneToOne_Optional_PK_Inverse3Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [l7].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] ON [l6].[Id] = [l7].[Id] + WHERE (([l6].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l6].[Level1_Required_Id] IS NOT NULL)) AND ([l6].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level2_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t2] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t2].[Level2_Optional_Id] +LEFT JOIN ( + SELECT [l8].[Id], [l8].[OneToOne_Required_PK_Date], [l8].[Level1_Optional_Id], [l8].[Level1_Required_Id], [l8].[Level2_Name], [l8].[OneToMany_Optional_Inverse2Id], [l8].[OneToMany_Required_Inverse2Id], [l8].[OneToOne_Optional_PK_Inverse2Id], [l8].[PeriodEnd], [l8].[PeriodStart], [l9].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] ON [l8].[Id] = [l9].[Id] + WHERE (([l8].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l8].[Level1_Required_Id] IS NOT NULL)) AND ([l8].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t4] ON [l].[Id] = [t4].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l10].[Id], [l10].[Level2_Optional_Id], [l10].[Level2_Required_Id], [l10].[Level3_Name], [l10].[OneToMany_Optional_Inverse3Id], [l10].[OneToMany_Required_Inverse3Id], [l10].[OneToOne_Optional_PK_Inverse3Id], [l10].[PeriodEnd], [l10].[PeriodStart], [t6].[Id] AS [Id0], [t6].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] + INNER JOIN ( + SELECT [l11].[Id], [l12].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l11] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l12] ON [l11].[Id] = [l12].[Id] + WHERE (([l11].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l11].[Level1_Required_Id] IS NOT NULL)) AND ([l11].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t6] ON [l10].[Id] = [t6].[Id] + WHERE ([l10].[Level2_Required_Id] IS NOT NULL) AND ([l10].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t5] ON CASE + WHEN (((([t4].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t4].[Level1_Required_Id] IS NOT NULL)) AND ([t4].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t4].[PeriodEnd] IS NOT NULL)) AND ([t4].[PeriodStart] IS NOT NULL) THEN [t4].[Id] +END = [t5].[Level2_Optional_Id] +LEFT JOIN ( + SELECT [l13].[Id], [l13].[Level2_Optional_Id], [l13].[Level2_Required_Id], [l13].[Level3_Name], [l13].[OneToMany_Optional_Inverse3Id], [l13].[OneToMany_Required_Inverse3Id], [l13].[OneToOne_Optional_PK_Inverse3Id], [l13].[PeriodEnd], [l13].[PeriodStart], [t8].[Id] AS [Id0], [t8].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l13] + INNER JOIN ( + SELECT [l14].[Id], [l15].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l14] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l15] ON [l14].[Id] = [l15].[Id] + WHERE (([l14].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l14].[Level1_Required_Id] IS NOT NULL)) AND ([l14].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t8] ON [l13].[Id] = [t8].[Id] + WHERE ([l13].[Level2_Required_Id] IS NOT NULL) AND ([l13].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t7] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t7].[OneToMany_Optional_Inverse3Id] +WHERE ([t0].[Level3_Name] <> N'Foo') OR ([t0].[Level3_Name] IS NULL) +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id0], [t2].[Id00], [t4].[Id], [t4].[Id0], [t5].[Id], [t5].[Id0], [t5].[Id00], [t7].[Id], [t7].[Id0]"); + } + + public override async Task Multiple_optional_navigation_with_Include(bool async) + { + await base.Multiple_optional_navigation_with_Include(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Id00], [t2].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToOne_Optional_PK_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) +) AS [t2] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t2].[OneToMany_Optional_Inverse4Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id0], [t2].[Id00]"); + } + + public override async Task Multiple_optional_navigation_with_string_based_Include(bool async) + { + await base.Multiple_optional_navigation_with_string_based_Include(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Id00], [t2].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToOne_Optional_PK_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) +) AS [t2] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t2].[OneToMany_Optional_Inverse4Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id0], [t2].[Id00]"); + } + + public override async Task Multiple_SelectMany_navigation_property_followed_by_select_collection_navigation(bool async) + { + await base.Multiple_SelectMany_navigation_property_followed_by_select_collection_navigation(async); + + AssertSql( + @"SELECT CASE + WHEN ([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t0].[Id] +END, [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Id00], [t2].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +INNER JOIN ( + SELECT [l2].[Id], [l2].[Level2_Required_Id], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) +) AS [t2] ON CASE + WHEN ([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t0].[Id] +END = [t2].[OneToMany_Optional_Inverse4Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id0], [t2].[Id00]"); + } + + public override async Task Multiple_SelectMany_with_Include(bool async) + { + await base.Multiple_SelectMany_with_Include(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t2].[Id], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id], [t2].[PeriodEnd], [t2].[PeriodStart], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id0], [t0].[Id00], [t2].[Id0], [t2].[Id00], [t2].[Id000], [t5].[Id], [t5].[Level3_Optional_Id], [t5].[Level3_Required_Id], [t5].[Level4_Name], [t5].[OneToMany_Optional_Inverse4Id], [t5].[OneToMany_Required_Inverse4Id], [t5].[OneToOne_Optional_PK_Inverse4Id], [t5].[PeriodEnd], [t5].[PeriodStart], [t5].[Id0], [t5].[Id00], [t5].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +INNER JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) +) AS [t2] ON CASE + WHEN ([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t0].[Id] +END = [t2].[Level3_Required_Id] +LEFT JOIN ( + SELECT [l9].[Id], [l9].[Level3_Optional_Id], [l9].[Level3_Required_Id], [l9].[Level4_Name], [l9].[OneToMany_Optional_Inverse4Id], [l9].[OneToMany_Required_Inverse4Id], [l9].[OneToOne_Optional_PK_Inverse4Id], [l9].[PeriodEnd], [l9].[PeriodStart], [t6].[Id] AS [Id0], [t6].[Id0] AS [Id00], [t6].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] + INNER JOIN ( + SELECT [l10].[Id], [t7].[Id] AS [Id0], [t7].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l10] + INNER JOIN ( + SELECT [l11].[Id], [l12].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l11] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l12] ON [l11].[Id] = [l12].[Id] + WHERE (([l11].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l11].[Level1_Required_Id] IS NOT NULL)) AND ([l11].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t7] ON [l10].[Id] = [t7].[Id] + WHERE ([l10].[Level2_Required_Id] IS NOT NULL) AND ([l10].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t6] ON [l9].[Id] = [t6].[Id] + WHERE ([l9].[Level3_Required_Id] IS NOT NULL) AND ([l9].[OneToMany_Required_Inverse4Id] IS NOT NULL) +) AS [t5] ON CASE + WHEN ([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t0].[Id] +END = [t5].[OneToMany_Optional_Inverse4Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id0], [t2].[Id00], [t2].[Id000], [t5].[Id], [t5].[Id0], [t5].[Id00]"); + } + + public override async Task Multi_level_include_correct_PK_is_chosen_as_the_join_predicate_for_queries_that_join_same_table_multiple_times(bool async) + { + await base.Multi_level_include_correct_PK_is_chosen_as_the_join_predicate_for_queries_that_join_same_table_multiple_times(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t4].[Id], [t4].[OneToOne_Required_PK_Date], [t4].[Level1_Optional_Id], [t4].[Level1_Required_Id], [t4].[Level2_Name], [t4].[OneToMany_Optional_Inverse2Id], [t4].[OneToMany_Required_Inverse2Id], [t4].[OneToOne_Optional_PK_Inverse2Id], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[Id0], [t4].[Id1], [t4].[Level2_Optional_Id], [t4].[Level2_Required_Id], [t4].[Level3_Name], [t4].[OneToMany_Optional_Inverse3Id], [t4].[OneToMany_Required_Inverse3Id], [t4].[OneToOne_Optional_PK_Inverse3Id], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[Id00], [t4].[OneToOne_Required_PK_Date0], [t4].[Level1_Optional_Id0], [t4].[Level1_Required_Id0], [t4].[Level2_Name0], [t4].[OneToMany_Optional_Inverse2Id0], [t4].[OneToMany_Required_Inverse2Id0], [t4].[OneToOne_Optional_PK_Inverse2Id0], [t4].[PeriodEnd00], [t4].[PeriodStart00], [t4].[Id10], [t4].[Id000], [t4].[Id01], [t4].[Id2], [t4].[Level2_Optional_Id0], [t4].[Level2_Required_Id0], [t4].[Level3_Name0], [t4].[OneToMany_Optional_Inverse3Id0], [t4].[OneToMany_Required_Inverse3Id0], [t4].[OneToOne_Optional_PK_Inverse3Id0], [t4].[PeriodEnd1], [t4].[PeriodStart1], [t4].[Id02], [t4].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], [t3].[Id] AS [Id1], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd] AS [PeriodEnd0], [t3].[PeriodStart] AS [PeriodStart0], [t3].[Id0] AS [Id00], [t3].[OneToOne_Required_PK_Date] AS [OneToOne_Required_PK_Date0], [t3].[Level1_Optional_Id] AS [Level1_Optional_Id0], [t3].[Level1_Required_Id] AS [Level1_Required_Id0], [t3].[Level2_Name] AS [Level2_Name0], [t3].[OneToMany_Optional_Inverse2Id] AS [OneToMany_Optional_Inverse2Id0], [t3].[OneToMany_Required_Inverse2Id] AS [OneToMany_Required_Inverse2Id0], [t3].[OneToOne_Optional_PK_Inverse2Id] AS [OneToOne_Optional_PK_Inverse2Id0], [t3].[PeriodEnd0] AS [PeriodEnd00], [t3].[PeriodStart0] AS [PeriodStart00], [t3].[Id1] AS [Id10], [t3].[Id00] AS [Id000], [t3].[Id01], [t3].[Id2], [t3].[Level2_Optional_Id0], [t3].[Level2_Required_Id0], [t3].[Level3_Name0], [t3].[OneToMany_Optional_Inverse3Id0], [t3].[OneToMany_Required_Inverse3Id0], [t3].[OneToOne_Optional_PK_Inverse3Id0], [t3].[PeriodEnd1], [t3].[PeriodStart1], [t3].[Id02], [t3].[Id000] AS [Id0000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t0].[Id] AS [Id0], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t].[Id] AS [Id1], [t].[Id0] AS [Id00], [t0].[Id0] AS [Id01], [t1].[Id] AS [Id2], [t1].[Level2_Optional_Id] AS [Level2_Optional_Id0], [t1].[Level2_Required_Id] AS [Level2_Required_Id0], [t1].[Level3_Name] AS [Level3_Name0], [t1].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [t1].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [t1].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [t1].[PeriodEnd] AS [PeriodEnd1], [t1].[PeriodStart] AS [PeriodStart1], [t1].[Id0] AS [Id02], [t1].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + INNER JOIN ( + SELECT [l5].[Id], [l5].[OneToOne_Required_PK_Date], [l5].[Level1_Optional_Id], [l5].[Level1_Required_Id], [l5].[Level2_Name], [l5].[OneToMany_Optional_Inverse2Id], [l5].[OneToMany_Required_Inverse2Id], [l5].[OneToOne_Optional_PK_Inverse2Id], [l5].[PeriodEnd], [l5].[PeriodStart], [l6].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] ON [l5].[Id] = [l6].[Id] + WHERE (([l5].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l5].[Level1_Required_Id] IS NOT NULL)) AND ([l5].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t0] ON [l2].[OneToMany_Required_Inverse3Id] = CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] + END + LEFT JOIN ( + SELECT [l7].[Id], [l7].[Level2_Optional_Id], [l7].[Level2_Required_Id], [l7].[Level3_Name], [l7].[OneToMany_Optional_Inverse3Id], [l7].[OneToMany_Required_Inverse3Id], [l7].[OneToOne_Optional_PK_Inverse3Id], [l7].[PeriodEnd], [l7].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN ( + SELECT [l8].[Id], [l9].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l9] ON [l8].[Id] = [l9].[Id] + WHERE (([l8].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l8].[Level1_Required_Id] IS NOT NULL)) AND ([l8].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l7].[Id] = [t2].[Id] + WHERE ([l7].[Level2_Required_Id] IS NOT NULL) AND ([l7].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] + END = [t1].[OneToMany_Optional_Inverse3Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t3].[OneToMany_Optional_Inverse3Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t4] ON [l].[Id] = [t4].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t4].[Id], [t4].[Id0], [t4].[Id1], [t4].[Id10], [t4].[Id000], [t4].[Id00], [t4].[Id01], [t4].[Id2], [t4].[Id02]"); + } + + public override async Task Multi_level_include_one_to_many_optional_and_one_to_many_optional_produces_valid_sql(bool async) + { + await base.Multi_level_include_one_to_many_optional_and_one_to_many_optional_produces_valid_sql(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t1].[Id], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id1], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id00], [t1].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], [t0].[Id] AS [Id1], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd] AS [PeriodEnd0], [t0].[PeriodStart] AS [PeriodStart0], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[OneToMany_Optional_Inverse3Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[Id00]"); + } + + public override async Task Null_check_in_anonymous_type_projection_should_not_be_removed(bool async) + { + await base.Null_check_in_anonymous_type_projection_should_not_be_removed(async); + + AssertSql( + @"SELECT [l].[Id], [t1].[c], [t1].[Level3_Name], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[Id00], [t1].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT CASE + WHEN ((([t0].[Level2_Required_Id] IS NULL) OR ([t0].[OneToMany_Required_Inverse3Id] IS NULL)) OR (CASE + WHEN ([t0].[PeriodEnd] IS NOT NULL) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[PeriodEnd] + END IS NULL)) OR (CASE + WHEN ([t0].[PeriodEnd] IS NOT NULL) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[PeriodStart] + END IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) + END AS [c], [t0].[Level3_Name], [l0].[Id], [l1].[Id] AS [Id0], [t0].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [l0].[OneToMany_Optional_Inverse2Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Required_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[Level2_Required_Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[Id00]"); + } + + public override async Task Null_check_in_Dto_projection_should_not_be_removed(bool async) + { + await base.Null_check_in_Dto_projection_should_not_be_removed(async); + + AssertSql( + @"SELECT [l].[Id], [t1].[c], [t1].[Level3_Name], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[Id00], [t1].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT CASE + WHEN ((([t0].[Level2_Required_Id] IS NULL) OR ([t0].[OneToMany_Required_Inverse3Id] IS NULL)) OR (CASE + WHEN ([t0].[PeriodEnd] IS NOT NULL) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[PeriodEnd] + END IS NULL)) OR (CASE + WHEN ([t0].[PeriodEnd] IS NOT NULL) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[PeriodStart] + END IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) + END AS [c], [t0].[Level3_Name], [l0].[Id], [l1].[Id] AS [Id0], [t0].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t0].[Id00] AS [Id000], [l0].[OneToMany_Optional_Inverse2Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Required_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t].[Id] AS [Id0], [t].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t0].[Level2_Required_Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t1] ON [l].[Id] = [t1].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[Id00]"); + } + + public override async Task Optional_navigation_with_Include_and_order(bool async) + { + await base.Optional_navigation_with_Include_and_order(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [t].[Level2_Name], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Optional_navigation_with_Include_ThenInclude(bool async) + { + await base.Optional_navigation_with_Include_ThenInclude(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t3].[Id], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[Level3_Name], [t3].[OneToMany_Optional_Inverse3Id], [t3].[OneToMany_Required_Inverse3Id], [t3].[OneToOne_Optional_PK_Inverse3Id], [t3].[PeriodEnd], [t3].[PeriodStart], [t3].[Id0], [t3].[Level3_Optional_Id], [t3].[Level3_Required_Id], [t3].[Level4_Name], [t3].[OneToMany_Optional_Inverse4Id], [t3].[OneToMany_Required_Inverse4Id], [t3].[OneToOne_Optional_PK_Inverse4Id], [t3].[PeriodEnd0], [t3].[PeriodStart0], [t3].[Id1], [t3].[Id00], [t3].[Id01], [t3].[Id000], [t3].[Id0000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Level3_Optional_Id], [t1].[Level3_Required_Id], [t1].[Level4_Name], [t1].[OneToMany_Optional_Inverse4Id], [t1].[OneToMany_Required_Inverse4Id], [t1].[OneToOne_Optional_PK_Inverse4Id], [t1].[PeriodEnd] AS [PeriodEnd0], [t1].[PeriodStart] AS [PeriodStart0], [t0].[Id] AS [Id1], [t0].[Id0] AS [Id00], [t1].[Id0] AS [Id01], [t1].[Id00] AS [Id000], [t1].[Id000] AS [Id0000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t0] ON [l2].[Id] = [t0].[Id] + LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], [t2].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t2] ON [l5].[Id] = [t2].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t1] ON CASE + WHEN ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l2].[Id] + END = [t1].[Level3_Optional_Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t3] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t3].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t3].[Id], [t3].[Id1], [t3].[Id00], [t3].[Id0], [t3].[Id01], [t3].[Id000]"); + } + + public override async Task Optional_navigation_with_order_by_and_Include(bool async) + { + await base.Optional_navigation_with_order_by_and_Include(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [t].[Level2_Name], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Orderby_SelectMany_with_Include1(bool async) + { + await base.Orderby_SelectMany_with_Include1(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Projecting_collection_with_FirstOrDefault(bool async) + { + await base.Projecting_collection_with_FirstOrDefault(async); + + AssertSql( + @"SELECT [t].[Id], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM ( + SELECT TOP(1) [l].[Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + WHERE [l].[Id] = 1 +) AS [t] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t0] ON [t].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [t].[Id], [t0].[Id]"); + } + + public override async Task Project_collection_and_include(bool async) + { + await base.Project_collection_and_include(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[OneToOne_Required_PK_Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Level2_Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[PeriodEnd], [l2].[PeriodStart], [l3].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] ON [l2].[Id] = [l3].[Id] + WHERE (([l2].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l2].[Level1_Required_Id] IS NOT NULL)) AND ([l2].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id]"); + } + + public override async Task Project_collection_and_root_entity(bool async) + { + await base.Project_collection_and_root_entity(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Id]"); + } + + public override async Task Project_collection_navigation(bool async) + { + await base.Project_collection_navigation(async); + + AssertSql( + @"SELECT [l].[Id], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t].[Id]"); + } + + public override async Task Project_collection_navigation_composed(bool async) + { + await base.Project_collection_navigation_composed(async); + + AssertSql( + @"SELECT [l].[Id], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (([l0].[Level2_Name] <> N'Foo') OR ([l0].[Level2_Name] IS NULL)) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +WHERE [l].[Id] < 3 +ORDER BY [l].[Id], [t].[Id]"); + } + + public override async Task Project_collection_navigation_nested(bool async) + { + await base.Project_collection_navigation_nested(async); + + AssertSql( + @"SELECT [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Project_collection_navigation_nested_anonymous(bool async) + { + await base.Project_collection_navigation_nested_anonymous(async); + + AssertSql( + @"SELECT [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Project_collection_navigation_nested_with_take(bool async) + { + await base.Project_collection_navigation_nested_with_take(async); + + AssertSql( + @"SELECT [l].[Id], [t].[Id], [t].[Id0], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] + FROM ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00], ROW_NUMBER() OVER(PARTITION BY [l2].[OneToMany_Optional_Inverse3Id] ORDER BY [l2].[Id], [t2].[Id], [t2].[Id0]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l2].[Id] = [t2].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] + WHERE [t0].[row] <= 50 +) AS [t1] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t1].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t1].[OneToMany_Optional_Inverse3Id], [t1].[Id], [t1].[Id0], [t1].[Id00]"); + } + + public override async Task Project_collection_navigation_using_ef_property(bool async) + { + await base.Project_collection_navigation_using_ef_property(async); + + AssertSql( + @"SELECT [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Project_navigation_and_collection(bool async) + { + await base.Project_navigation_and_collection(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[PeriodEnd] IS NOT NULL)) AND ([t].[PeriodStart] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task SelectMany_navigation_property_followed_by_select_collection_navigation(bool async) + { + await base.SelectMany_navigation_property_followed_by_select_collection_navigation(async); + + AssertSql( + @"SELECT CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END, [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task SelectMany_navigation_property_with_include_and_followed_by_select_collection_navigation(bool async) + { + await base.SelectMany_navigation_property_with_include_and_followed_by_select_collection_navigation(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Level2_Optional_Id], [t2].[Level2_Required_Id], [t2].[Level3_Name], [t2].[OneToMany_Optional_Inverse3Id], [t2].[OneToMany_Required_Inverse3Id], [t2].[OneToOne_Optional_PK_Inverse3Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Required_Inverse3Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level2_Optional_Id], [l5].[Level2_Required_Id], [l5].[Level3_Name], [l5].[OneToMany_Optional_Inverse3Id], [l5].[OneToMany_Required_Inverse3Id], [l5].[OneToOne_Optional_PK_Inverse3Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [l7].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] ON [l6].[Id] = [l7].[Id] + WHERE (([l6].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l6].[Level1_Required_Id] IS NOT NULL)) AND ([l6].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level2_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t2] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t2].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id0]"); + } + + public override async Task SelectMany_with_Include1(bool async) + { + await base.SelectMany_with_Include1(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task SelectMany_with_Include2(bool async) + { + await base.SelectMany_with_Include2(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[Level2_Required_Id]"); + } + + public override async Task SelectMany_with_Include_and_order_by(bool async) + { + await base.SelectMany_with_Include_and_order_by(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [t].[Level2_Name], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task SelectMany_with_Include_ThenInclude(bool async) + { + await base.SelectMany_with_Include_ThenInclude(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Level3_Optional_Id], [t2].[Level3_Required_Id], [t2].[Level4_Name], [t2].[OneToMany_Optional_Inverse4Id], [t2].[OneToMany_Required_Inverse4Id], [t2].[OneToOne_Optional_PK_Inverse4Id], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[Id0], [t2].[Id00], [t2].[Id000] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[Level2_Required_Id] +LEFT JOIN ( + SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [l5].[PeriodEnd], [l5].[PeriodStart], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) +) AS [t2] ON CASE + WHEN ((([t0].[Level2_Required_Id] IS NOT NULL) AND ([t0].[OneToMany_Required_Inverse3Id] IS NOT NULL)) AND ([t0].[PeriodEnd] IS NOT NULL)) AND ([t0].[PeriodStart] IS NOT NULL) THEN [t0].[Id] +END = [t2].[OneToMany_Optional_Inverse4Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t0].[Id00], [t2].[Id], [t2].[Id0], [t2].[Id00]"); + } + + public override async Task SelectMany_with_navigation_and_Distinct(bool async) + { + await base.SelectMany_with_navigation_and_Distinct(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[PeriodEnd], [l].[PeriodStart], [t].[Id], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT DISTINCT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[OneToOne_Required_PK_Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Level2_Name], [l2].[OneToMany_Optional_Inverse2Id], [l2].[OneToMany_Required_Inverse2Id], [l2].[OneToOne_Optional_PK_Inverse2Id], [l2].[PeriodEnd], [l2].[PeriodStart], [l3].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] ON [l2].[Id] = [l3].[Id] + WHERE (([l2].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l2].[Level1_Required_Id] IS NOT NULL)) AND ([l2].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +WHERE (((([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND (CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[PeriodEnd] +END IS NOT NULL)) AND (CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[PeriodStart] +END IS NOT NULL) +ORDER BY [l].[Id], [t].[Id], [t0].[Id]"); + } + + public override async Task SelectMany_with_order_by_and_Include(bool async) + { + await base.SelectMany_with_order_by_and_Include(async); + + AssertSql( + @"SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [l].[Id], [t].[Id0], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Level3_Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0], [t0].[Id00] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [t1].[Id] AS [Id0], [t1].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t1] ON [l2].[Id] = [t1].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t0] ON CASE + WHEN (([t].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t].[Level1_Required_Id] IS NOT NULL)) AND ([t].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t].[Id] +END = [t0].[OneToMany_Optional_Inverse3Id] +ORDER BY [t].[Level2_Name], [l].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Select_nav_prop_collection_one_to_many_required(bool async) + { + await base.Select_nav_prop_collection_one_to_many_required(async); + + AssertSql( + @"SELECT [l].[Id], [t].[c], [t].[Id], [t].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c], [l0].[Id], [l1].[Id] AS [Id0], [l0].[OneToMany_Required_Inverse2Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t] ON [l].[Id] = [t].[OneToMany_Required_Inverse2Id] +ORDER BY [l].[Id], [t].[Id]"); + } + + public override async Task Select_subquery_single_nested_subquery(bool async) + { + await base.Select_subquery_single_nested_subquery(async); + + AssertSql( + @"SELECT [l].[Id], [t0].[Id], [t0].[Id0], [t1].[Id], [t1].[Id0], [t1].[Id1], [t1].[Id00], [t0].[c] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[c], [t].[Id], [t].[Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[OneToMany_Optional_Inverse2Id] + FROM ( + SELECT 1 AS [c], [l0].[Id], [l1].[Id] AS [Id0], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l0].[OneToMany_Optional_Inverse2Id], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +LEFT JOIN ( + SELECT CASE + WHEN ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l2].[Id] + END AS [Id], [l2].[Id] AS [Id0], [t2].[Id] AS [Id1], [t2].[Id0] AS [Id00], [l2].[OneToMany_Optional_Inverse3Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [l2].[Id] = [t2].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) +) AS [t1] ON CASE + WHEN (([t0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t0].[Level1_Required_Id] IS NOT NULL)) AND ([t0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t0].[Id] +END = [t1].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t0].[Id], [t0].[Id0], [t1].[Id], [t1].[Id0], [t1].[Id1]"); + } + + public override async Task Select_subquery_single_nested_subquery2(bool async) + { + await base.Select_subquery_single_nested_subquery2(async); + + AssertSql( + @"SELECT [l].[Id], [t5].[Id], [t5].[Id0], [t5].[Id1], [t5].[Id00], [t5].[Id000], [t5].[Id2], [t5].[Id01], [t5].[Id10], [t5].[Id001], [t5].[Id0000], [t5].[c] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l1].[Id] AS [Id0], [t1].[Id] AS [Id1], [t1].[Id0] AS [Id00], [t1].[Id00] AS [Id000], [t2].[Id] AS [Id2], [t2].[Id0] AS [Id01], [t2].[Id1] AS [Id10], [t2].[Id00] AS [Id001], [t2].[Id000] AS [Id0000], [t1].[c], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c0], [l0].[OneToMany_Optional_Inverse2Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + LEFT JOIN ( + SELECT [t0].[c], [t0].[Id], [t0].[Id0], [t0].[Id00], [t0].[Level2_Required_Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[OneToMany_Optional_Inverse3Id] + FROM ( + SELECT 1 AS [c], [l2].[Id], [t].[Id] AS [Id0], [t].[Id0] AS [Id00], [l2].[Level2_Required_Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[PeriodEnd], [l2].[PeriodStart], [l2].[OneToMany_Optional_Inverse3Id], ROW_NUMBER() OVER(PARTITION BY [l2].[OneToMany_Optional_Inverse3Id] ORDER BY CASE + WHEN ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [l2].[Id] + END) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] + INNER JOIN ( + SELECT [l3].[Id], [l4].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l3] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l4] ON [l3].[Id] = [l4].[Id] + WHERE (([l3].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l3].[Level1_Required_Id] IS NOT NULL)) AND ([l3].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] ON [l2].[Id] = [t].[Id] + WHERE ([l2].[Level2_Required_Id] IS NOT NULL) AND ([l2].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t0] + WHERE [t0].[row] <= 1 + ) AS [t1] ON CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END = [t1].[OneToMany_Optional_Inverse3Id] + LEFT JOIN ( + SELECT CASE + WHEN ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) THEN [l5].[Id] + END AS [Id], [l5].[Id] AS [Id0], [t3].[Id] AS [Id1], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000], [l5].[OneToMany_Optional_Inverse4Id] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l5] + INNER JOIN ( + SELECT [l6].[Id], [t4].[Id] AS [Id0], [t4].[Id0] AS [Id00] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l6] + INNER JOIN ( + SELECT [l7].[Id], [l8].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l7] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l8] ON [l7].[Id] = [l8].[Id] + WHERE (([l7].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l7].[Level1_Required_Id] IS NOT NULL)) AND ([l7].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t4] ON [l6].[Id] = [t4].[Id] + WHERE ([l6].[Level2_Required_Id] IS NOT NULL) AND ([l6].[OneToMany_Required_Inverse3Id] IS NOT NULL) + ) AS [t3] ON [l5].[Id] = [t3].[Id] + WHERE ([l5].[Level3_Required_Id] IS NOT NULL) AND ([l5].[OneToMany_Required_Inverse4Id] IS NOT NULL) + ) AS [t2] ON CASE + WHEN ([t1].[Level2_Required_Id] IS NOT NULL) AND ([t1].[OneToMany_Required_Inverse3Id] IS NOT NULL) THEN [t1].[Id] + END = [t2].[OneToMany_Optional_Inverse4Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) +) AS [t5] ON [l].[Id] = [t5].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t5].[c0], [t5].[Id], [t5].[Id0], [t5].[Id1], [t5].[Id00], [t5].[Id000], [t5].[Id2], [t5].[Id01], [t5].[Id10], [t5].[Id001]"); + } + + public override async Task Skip_on_grouping_element(bool async) + { + await base.Skip_on_grouping_element(async); + + AssertSql( + @"SELECT [t].[Date], [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart] +FROM ( + SELECT [l].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Date] +) AS [t] +LEFT JOIN ( + SELECT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l0].[Date] ORDER BY [l0].[Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + ) AS [t1] + WHERE 1 < [t1].[row] +) AS [t0] ON [t].[Date] = [t0].[Date] +ORDER BY [t].[Date], [t0].[Date], [t0].[Name]"); + } + + public override async Task Skip_Take_Distinct_on_grouping_element(bool async) + { + await base.Skip_Take_Distinct_on_grouping_element(async); + + AssertSql( + @"SELECT [t].[Date], [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart] +FROM ( + SELECT [l].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Date] +) AS [t] +OUTER APPLY ( + SELECT DISTINCT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + WHERE [t].[Date] = [l0].[Date] + ORDER BY [l0].[Name] + OFFSET 1 ROWS FETCH NEXT 5 ROWS ONLY + ) AS [t1] +) AS [t0] +ORDER BY [t].[Date]"); + } + + public override async Task Skip_Take_on_grouping_element(bool async) + { + await base.Skip_Take_on_grouping_element(async); + + AssertSql( + @"SELECT [t].[Date], [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart] +FROM ( + SELECT [l].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Date] +) AS [t] +LEFT JOIN ( + SELECT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l0].[Date] ORDER BY [l0].[Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 6) +) AS [t0] ON [t].[Date] = [t0].[Date] +ORDER BY [t].[Date], [t0].[Date], [t0].[Name]"); + } + + public override async Task Skip_Take_on_grouping_element_inside_collection_projection(bool async) + { + await base.Skip_Take_on_grouping_element_inside_collection_projection(async); + + AssertSql( + @"SELECT [l].[Id], [t2].[Date], [t2].[Id], [t2].[Date0], [t2].[Name], [t2].[PeriodEnd], [t2].[PeriodStart] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +OUTER APPLY ( + SELECT [t].[Date], [t0].[Id], [t0].[Date] AS [Date0], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart] + FROM ( + SELECT [l0].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + WHERE ([l0].[Name] = [l].[Name]) OR (([l0].[Name] IS NULL) AND ([l].[Name] IS NULL)) + GROUP BY [l0].[Date] + ) AS [t] + LEFT JOIN ( + SELECT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l1].[Id], [l1].[Date], [l1].[Name], [l1].[PeriodEnd], [l1].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l1].[Date] ORDER BY [l1].[Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] + WHERE ([l1].[Name] = [l].[Name]) OR (([l1].[Name] IS NULL) AND ([l].[Name] IS NULL)) + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 6) + ) AS [t0] ON [t].[Date] = [t0].[Date] +) AS [t2] +ORDER BY [l].[Id], [t2].[Date], [t2].[Date0], [t2].[Name]"); + } + + public override async Task Skip_Take_on_grouping_element_into_non_entity(bool async) + { + await base.Skip_Take_on_grouping_element_into_non_entity(async); + + AssertSql( + @"SELECT [t].[Date], [t0].[Name], [t0].[Id] +FROM ( + SELECT [l].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Date] +) AS [t] +LEFT JOIN ( + SELECT [t1].[Name], [t1].[Id], [t1].[Date] + FROM ( + SELECT [l0].[Name], [l0].[Id], [l0].[Date], ROW_NUMBER() OVER(PARTITION BY [l0].[Date] ORDER BY [l0].[Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 6) +) AS [t0] ON [t].[Date] = [t0].[Date] +ORDER BY [t].[Date], [t0].[Date], [t0].[Name]"); + } + + public override async Task Skip_Take_on_grouping_element_with_collection_include(bool async) + { + await base.Skip_Take_on_grouping_element_with_collection_include(async); + + AssertSql( + @"SELECT [t].[Date], [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id00] +FROM ( + SELECT [l].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Date] +) AS [t] +OUTER APPLY ( + SELECT [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart], [t2].[Id] AS [Id0], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd] AS [PeriodEnd0], [t2].[PeriodStart] AS [PeriodStart0], [t2].[Id0] AS [Id00] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + WHERE [t].[Date] = [l0].[Date] + ORDER BY [l0].[Name] + OFFSET 1 ROWS FETCH NEXT 5 ROWS ONLY + ) AS [t0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Level2_Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[PeriodEnd], [l1].[PeriodStart], [l2].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] ON [l1].[Id] = [l2].[Id] + WHERE (([l1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l1].[Level1_Required_Id] IS NOT NULL)) AND ([l1].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [t0].[Id] = [t2].[OneToMany_Optional_Inverse2Id] +) AS [t1] +ORDER BY [t].[Date], [t1].[Name], [t1].[Id], [t1].[Id0]"); + } + + public override async Task Skip_Take_on_grouping_element_with_reference_include(bool async) + { + await base.Skip_Take_on_grouping_element_with_reference_include(async); + + AssertSql( + @"SELECT [t].[Date], [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Id0], [t1].[OneToOne_Required_PK_Date], [t1].[Level1_Optional_Id], [t1].[Level1_Required_Id], [t1].[Level2_Name], [t1].[OneToMany_Optional_Inverse2Id], [t1].[OneToMany_Required_Inverse2Id], [t1].[OneToOne_Optional_PK_Inverse2Id], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id00] +FROM ( + SELECT [l].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Date] +) AS [t] +OUTER APPLY ( + SELECT [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart], [t2].[Id] AS [Id0], [t2].[OneToOne_Required_PK_Date], [t2].[Level1_Optional_Id], [t2].[Level1_Required_Id], [t2].[Level2_Name], [t2].[OneToMany_Optional_Inverse2Id], [t2].[OneToMany_Required_Inverse2Id], [t2].[OneToOne_Optional_PK_Inverse2Id], [t2].[PeriodEnd] AS [PeriodEnd0], [t2].[PeriodStart] AS [PeriodStart0], [t2].[Id0] AS [Id00] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + WHERE [t].[Date] = [l0].[Date] + ORDER BY [l0].[Name] + OFFSET 1 ROWS FETCH NEXT 5 ROWS ONLY + ) AS [t0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Level2_Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[PeriodEnd], [l1].[PeriodStart], [l2].[Id] AS [Id0] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] ON [l1].[Id] = [l2].[Id] + WHERE (([l1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l1].[Level1_Required_Id] IS NOT NULL)) AND ([l1].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t2] ON [t0].[Id] = [t2].[Level1_Optional_Id] +) AS [t1] +ORDER BY [t].[Date], [t1].[Name], [t1].[Id], [t1].[Id0]"); + } + + public override async Task Skip_Take_Select_collection_Skip_Take(bool async) + { + await base.Skip_Take_Select_collection_Skip_Take(async); + + AssertSql( + @"@__p_0='1' + +SELECT [t].[Id], [t].[Name], [t0].[Id], [t0].[Name], [t0].[Level1Id], [t0].[Level2Id], [t0].[Id0], [t0].[Date], [t0].[Name0], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id1], [t0].[Id00] +FROM ( + SELECT [l].[Id], [l].[Name] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Id] + OFFSET @__p_0 ROWS FETCH NEXT @__p_0 ROWS ONLY +) AS [t] +OUTER APPLY ( + SELECT CASE + WHEN (([t1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t1].[Level1_Required_Id] IS NOT NULL)) AND ([t1].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t1].[Id] + END AS [Id], [t1].[Level2_Name] AS [Name], [t1].[OneToMany_Required_Inverse2Id] AS [Level1Id], [t1].[Level1_Required_Id] AS [Level2Id], [l1].[Id] AS [Id0], [l1].[Date], [l1].[Name] AS [Name0], [l1].[PeriodEnd], [l1].[PeriodStart], [t1].[Id] AS [Id1], [t1].[Id0] AS [Id00], [t1].[c] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l2].[Id] AS [Id0], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] ON [l0].[Id] = [l2].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[Id] = [l0].[OneToMany_Required_Inverse2Id]) + ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END + OFFSET 1 ROWS FETCH NEXT 3 ROWS ONLY + ) AS [t1] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [t1].[Level1_Required_Id] = [l1].[Id] +) AS [t0] +ORDER BY [t].[Id], [t0].[c], [t0].[Id1], [t0].[Id00]"); + } + + public override async Task Skip_Take_ToList_on_grouping_element(bool async) + { + await base.Skip_Take_ToList_on_grouping_element(async); + + AssertSql( + @"SELECT [t].[Date], [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart] +FROM ( + SELECT [l].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Date] +) AS [t] +LEFT JOIN ( + SELECT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l0].[Date] ORDER BY [l0].[Name]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + ) AS [t1] + WHERE (1 < [t1].[row]) AND ([t1].[row] <= 6) +) AS [t0] ON [t].[Date] = [t0].[Date] +ORDER BY [t].[Date], [t0].[Date], [t0].[Name]"); + } + + public override async Task Take_on_correlated_collection_in_projection(bool async) + { + await base.Take_on_correlated_collection_in_projection(async); + + AssertSql( + @"SELECT [l].[Id], [t0].[Id], [t0].[OneToOne_Required_PK_Date], [t0].[Level1_Optional_Id], [t0].[Level1_Required_Id], [t0].[Level2_Name], [t0].[OneToMany_Optional_Inverse2Id], [t0].[OneToMany_Required_Inverse2Id], [t0].[OneToOne_Optional_PK_Inverse2Id], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id0] +FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id0] + FROM ( + SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l1].[Id] AS [Id0], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Id], [l1].[Id]) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [l0].[Id] = [l1].[Id] + WHERE (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) + ) AS [t] + WHERE [t].[row] <= 50 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +ORDER BY [l].[Id], [t0].[OneToMany_Optional_Inverse2Id], [t0].[Id], [t0].[Id0]"); + } + + public override async Task Take_on_grouping_element(bool async) + { + await base.Take_on_grouping_element(async); + + AssertSql( + @"SELECT [t].[Date], [t0].[Id], [t0].[Date], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart] +FROM ( + SELECT [l].[Date] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + GROUP BY [l].[Date] +) AS [t] +LEFT JOIN ( + SELECT [t1].[Id], [t1].[Date], [t1].[Name], [t1].[PeriodEnd], [t1].[PeriodStart] + FROM ( + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[PeriodEnd], [l0].[PeriodStart], ROW_NUMBER() OVER(PARTITION BY [l0].[Date] ORDER BY [l0].[Name] DESC) AS [row] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + ) AS [t1] + WHERE [t1].[row] <= 10 +) AS [t0] ON [t].[Date] = [t0].[Date] +ORDER BY [t].[Date], [t0].[Date], [t0].[Name] DESC"); + } + + public override async Task Take_Select_collection_Take(bool async) + { + await base.Take_Select_collection_Take(async); + + AssertSql( + @"@__p_0='1' + +SELECT [t].[Id], [t].[Name], [t0].[Id], [t0].[Name], [t0].[Level1Id], [t0].[Level2Id], [t0].[Id0], [t0].[Date], [t0].[Name0], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id1], [t0].[Id00] +FROM ( + SELECT TOP(@__p_0) [l].[Id], [l].[Name] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] + ORDER BY [l].[Id] +) AS [t] +OUTER APPLY ( + SELECT CASE + WHEN (([t1].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([t1].[Level1_Required_Id] IS NOT NULL)) AND ([t1].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [t1].[Id] + END AS [Id], [t1].[Level2_Name] AS [Name], [t1].[OneToMany_Required_Inverse2Id] AS [Level1Id], [t1].[Level1_Required_Id] AS [Level2Id], [l1].[Id] AS [Id0], [l1].[Date], [l1].[Name] AS [Name0], [l1].[PeriodEnd], [l1].[PeriodStart], [t1].[Id] AS [Id1], [t1].[Id0] AS [Id00], [t1].[c] + FROM ( + SELECT TOP(3) [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Required_Inverse2Id], [l0].[PeriodEnd], [l0].[PeriodStart], [l2].[Id] AS [Id0], CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END AS [c] + FROM [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l2] ON [l0].[Id] = [l2].[Id] + WHERE ((([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL)) AND ([t].[Id] = [l0].[OneToMany_Required_Inverse2Id]) + ORDER BY CASE + WHEN (([l0].[OneToOne_Required_PK_Date] IS NOT NULL) AND ([l0].[Level1_Required_Id] IS NOT NULL)) AND ([l0].[OneToMany_Required_Inverse2Id] IS NOT NULL) THEN [l0].[Id] + END + ) AS [t1] + INNER JOIN [Level1] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l1] ON [t1].[Level1_Required_Id] = [l1].[Id] +) AS [t0] +ORDER BY [t].[Id], [t0].[c], [t0].[Id1], [t0].[Id00]"); + } + + public override async Task SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(bool async) + { + var exception = await Assert.ThrowsAsync(() => + base.SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(async)); + + Assert.Equal( + CoreStrings.ExpressionParameterizationExceptionSensitive( + "Convert(value(Microsoft.EntityFrameworkCore.Query.ComplexNavigationsCollectionsQueryTestBase`1+<>c__DisplayClass140_0[Microsoft.EntityFrameworkCore.Query.TemporalComplexNavigationsSharedTypeQuerySqlServerFixture]).ss.Set(), DbSet`1).TemporalAsOf(1/1/2010 12:00:00 AM)"), + exception.Message); + Assert.True(exception.InnerException is InvalidCastException); + } + + [ConditionalTheory(Skip = "issue #26922")] + public override async Task Filtered_include_include_parameter_used_inside_filter_throws(bool async) + { + await base.Filtered_include_include_parameter_used_inside_filter_throws(async); + + AssertSql(""); + } + + [ConditionalTheory(Skip = "issue #26922")] + public override async Task Filtered_include_outer_parameter_used_inside_filter(bool async) + { + await base.Filtered_include_outer_parameter_used_inside_filter(async); + + AssertSql(""); + } + + [ConditionalTheory(Skip = "issue #26922")] + public override async Task Include_inside_subquery(bool async) + { + await base.Include_inside_subquery(async); + + AssertSql(""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + } + } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsSharedTypeQuerySqlServerFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsSharedTypeQuerySqlServerFixture.cs index 7dfc657c260..ade9c7de39e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsSharedTypeQuerySqlServerFixture.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsSharedTypeQuerySqlServerFixture.cs @@ -1,19 +1,106 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Linq; +using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel; namespace Microsoft.EntityFrameworkCore.Query { public class TemporalComplexNavigationsSharedTypeQuerySqlServerFixture : ComplexNavigationsSharedTypeQuerySqlServerFixture { - protected override string StoreName { get; } = "TemporalComplexNavigationsOwned"; + protected override string StoreName { get; } = "TemporalComplexNavigationsSharedType"; + + public DateTime ChangesDate { get; private set; } protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) { base.OnModelCreating(modelBuilder, context); - modelBuilder.Entity().ToTable(tb => tb.IsTemporal()); + modelBuilder.Entity().ToTable(nameof(Level1), tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + } + + protected override void Configure(OwnedNavigationBuilder l2) + { + base.Configure(l2); + + l2.ToTable(nameof(Level1), tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + } + + protected override void Configure(OwnedNavigationBuilder l3) + { + base.Configure(l3); + + l3.ToTable(nameof(Level1), tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + } + + protected override void Configure(OwnedNavigationBuilder l4) + { + base.Configure(l4); + + l4.ToTable(nameof(Level1), tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + } + + protected override void Seed(ComplexNavigationsContext context) + { + base.Seed(context); + + ChangesDate = new DateTime(2010, 1, 1); + + // clean up intermittent history since in the Seed method we do fixup in multiple stages + var tableName = nameof(Level1); + + context.Database.ExecuteSqlRaw($"ALTER TABLE [{tableName}] SET (SYSTEM_VERSIONING = OFF)"); + context.Database.ExecuteSqlRaw($"DELETE FROM [{tableName + "History"}]"); + context.Database.ExecuteSqlRaw($"ALTER TABLE [{tableName}] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[{tableName + "History"}]))"); + + foreach (var entityOne in context.ChangeTracker.Entries().Where(e => e.Entity is Level1).Select(e => e.Entity)) + { + ((Level1)entityOne).Name = ((Level1)entityOne).Name + "Modified"; + } + + foreach (var entityOne in context.ChangeTracker.Entries().Where(e => e.Entity is Level2).Select(e => e.Entity)) + { + ((Level2)entityOne).Name = ((Level2)entityOne).Name + "Modified"; + } + + foreach (var entityOne in context.ChangeTracker.Entries().Where(e => e.Entity is Level3).Select(e => e.Entity)) + { + ((Level3)entityOne).Name = ((Level3)entityOne).Name + "Modified"; + } + + foreach (var entityOne in context.ChangeTracker.Entries().Where(e => e.Entity is Level4).Select(e => e.Entity)) + { + ((Level4)entityOne).Name = ((Level4)entityOne).Name + "Modified"; + } + + context.SaveChanges(); + + context.Database.ExecuteSqlRaw($"ALTER TABLE [{tableName}] SET (SYSTEM_VERSIONING = OFF)"); + context.Database.ExecuteSqlRaw($"ALTER TABLE [{tableName}] DROP PERIOD FOR SYSTEM_TIME"); + + context.Database.ExecuteSqlRaw($"UPDATE [{tableName + "History"}] SET PeriodStart = '2000-01-01T01:00:00.0000000Z'"); + context.Database.ExecuteSqlRaw($"UPDATE [{tableName + "History"}] SET PeriodEnd = '2020-07-01T07:00:00.0000000Z'"); + + context.Database.ExecuteSqlRaw($"ALTER TABLE [{tableName}] ADD PERIOD FOR SYSTEM_TIME ([PeriodStart], [PeriodEnd])"); + context.Database.ExecuteSqlRaw($"ALTER TABLE [{tableName}] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[{tableName + "History"}]))"); } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalTableSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalTableSqlServerTest.cs new file mode 100644 index 00000000000..f9b29822b25 --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalTableSqlServerTest.cs @@ -0,0 +1,526 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.SqlServer.Internal; +using Microsoft.EntityFrameworkCore.TestModels.TransportationModel; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace Microsoft.EntityFrameworkCore.Query +{ + [SqlServerCondition(SqlServerCondition.SupportsTemporalTablesCascadeDelete)] + public class TemporalTableSqlServerTest : NonSharedModelTestBase + { + protected override string StoreName => "TemporalTableSqlServerTest"; + + protected TestSqlLoggerFactory TestSqlLoggerFactory + => (TestSqlLoggerFactory)ListLoggerFactory; + + protected override ITestStoreFactory TestStoreFactory => SqlServerTestStoreFactory.Instance; + + protected void AssertSql(params string[] expected) => TestSqlLoggerFactory.AssertBaseline(expected); + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_basic(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + + var query = context.MainEntitiesDifferentTable.TemporalAsOf(date); + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"SELECT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime], [o].[MainEntityDifferentTableId], [o].[Description], [o].[EndTime], [o].[StartTime] +FROM [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m] +LEFT JOIN [OwnedEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [o] ON [m].[Id] = [o].[MainEntityDifferentTableId]"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_join(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + + var query = context.MainEntitiesDifferentTable + .TemporalAsOf(date) + .Join(context.MainEntitiesDifferentTable, o => o.Id, i => i.Id, (o, i) => new { o, i }); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"SELECT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime], [o].[MainEntityDifferentTableId], [o].[Description], [o].[EndTime], [o].[StartTime], [m0].[Id], [m0].[Description], [m0].[EndTime], [m0].[StartTime], [o0].[MainEntityDifferentTableId], [o0].[Description], [o0].[EndTime], [o0].[StartTime] +FROM [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m] +INNER JOIN [MainEntityDifferentTable] AS [m0] ON [m].[Id] = [m0].[Id] +LEFT JOIN [OwnedEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [o] ON [m].[Id] = [o].[MainEntityDifferentTableId] +LEFT JOIN [OwnedEntityDifferentTable] AS [o0] ON [m0].[Id] = [o0].[MainEntityDifferentTableId]"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_set_operation(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + + var query = context.MainEntitiesDifferentTable + .TemporalAsOf(date) + .Union(context.MainEntitiesDifferentTable.TemporalAsOf(date)); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"SELECT [t].[Id], [t].[Description], [t].[EndTime], [t].[StartTime], [o].[MainEntityDifferentTableId], [o].[Description], [o].[EndTime], [o].[StartTime] +FROM ( + SELECT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime] + FROM [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m] + UNION + SELECT [m0].[Id], [m0].[Description], [m0].[EndTime], [m0].[StartTime] + FROM [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m0] +) AS [t] +LEFT JOIN [OwnedEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [o] ON [t].[Id] = [o].[MainEntityDifferentTableId]"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_FromSql(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + + var query = context.MainEntitiesDifferentTable.FromSqlRaw( + @"SELECT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime] +FROM [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m]"); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + // just making sure we don't do anything weird here - there is no way to extract temporal information + // from the FromSql so owned entity will always be treated as a regular query + AssertSql( + @"SELECT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime], [o].[MainEntityDifferentTableId], [o].[Description], [o].[EndTime], [o].[StartTime] +FROM ( + SELECT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime] + FROM [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m] +) AS [m] +LEFT JOIN [OwnedEntityDifferentTable] AS [o] ON [m].[Id] = [o].[MainEntityDifferentTableId]"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_subquery(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + + var query = context.MainEntitiesDifferentTable + .TemporalAsOf(date) + .Distinct() + .OrderByDescending(x => x.Id) + .Take(3); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"@__p_0='3' + +SELECT [t0].[Id], [t0].[Description], [t0].[EndTime], [t0].[StartTime], [o].[MainEntityDifferentTableId], [o].[Description], [o].[EndTime], [o].[StartTime] +FROM ( + SELECT TOP(@__p_0) [t].[Id], [t].[Description], [t].[EndTime], [t].[StartTime] + FROM ( + SELECT DISTINCT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime] + FROM [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m] + ) AS [t] + ORDER BY [t].[Id] DESC +) AS [t0] +LEFT JOIN [OwnedEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [o] ON [t0].[Id] = [o].[MainEntityDifferentTableId] +ORDER BY [t0].[Id] DESC"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_complex(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + + var query = context.MainEntitiesDifferentTable.TemporalAsOf(date) + .Join(context.MainEntitiesDifferentTable, x => x.Id, x => x.Id, (o, i) => new { o, i }) + .Distinct().OrderByDescending(x => x.o.Id).Take(3) + .Join(context.MainEntitiesDifferentTable, xx => xx.o.Id, x => x.Id, (o, i) => new { o, i }); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"@__p_0='3' + +SELECT [t0].[Id], [t0].[Description], [t0].[EndTime], [t0].[StartTime], [o].[MainEntityDifferentTableId], [o].[Description], [o].[EndTime], [o].[StartTime], [t0].[Id0], [t0].[Description0], [t0].[EndTime0], [t0].[StartTime0], [o0].[MainEntityDifferentTableId], [o0].[Description], [o0].[EndTime], [o0].[StartTime], [m1].[Id], [m1].[Description], [m1].[EndTime], [m1].[StartTime], [o1].[MainEntityDifferentTableId], [o1].[Description], [o1].[EndTime], [o1].[StartTime] +FROM ( + SELECT TOP(@__p_0) [t].[Id], [t].[Description], [t].[EndTime], [t].[StartTime], [t].[Id0], [t].[Description0], [t].[EndTime0], [t].[StartTime0] + FROM ( + SELECT DISTINCT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime], [m0].[Id] AS [Id0], [m0].[Description] AS [Description0], [m0].[EndTime] AS [EndTime0], [m0].[StartTime] AS [StartTime0] + FROM [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m] + INNER JOIN [MainEntityDifferentTable] AS [m0] ON [m].[Id] = [m0].[Id] + ) AS [t] + ORDER BY [t].[Id] DESC +) AS [t0] +INNER JOIN [MainEntityDifferentTable] AS [m1] ON [t0].[Id] = [m1].[Id] +LEFT JOIN [OwnedEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [o] ON [t0].[Id] = [o].[MainEntityDifferentTableId] +LEFT JOIN [OwnedEntityDifferentTable] AS [o0] ON [t0].[Id0] = [o0].[MainEntityDifferentTableId] +LEFT JOIN [OwnedEntityDifferentTable] AS [o1] ON [m1].[Id] = [o1].[MainEntityDifferentTableId] +ORDER BY [t0].[Id] DESC"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_complex_with_nontrivial_alias(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + + var query = context.MainEntitiesDifferentTable + .Join(context.MainEntitiesDifferentTable.TemporalAsOf(date), x => x.Id, x => x.Id, (o, i) => new { o, i }) + .Distinct().OrderByDescending(x => x.o.Id).Take(3) + .Join(context.MainEntitiesDifferentTable, xx => xx.o.Id, x => x.Id, (o, i) => new { o, i }); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"@__p_0='3' + +SELECT [t0].[Id], [t0].[Description], [t0].[EndTime], [t0].[StartTime], [o].[MainEntityDifferentTableId], [o].[Description], [o].[EndTime], [o].[StartTime], [t0].[Id0], [t0].[Description0], [t0].[EndTime0], [t0].[StartTime0], [o0].[MainEntityDifferentTableId], [o0].[Description], [o0].[EndTime], [o0].[StartTime], [m1].[Id], [m1].[Description], [m1].[EndTime], [m1].[StartTime], [o1].[MainEntityDifferentTableId], [o1].[Description], [o1].[EndTime], [o1].[StartTime] +FROM ( + SELECT TOP(@__p_0) [t].[Id], [t].[Description], [t].[EndTime], [t].[StartTime], [t].[Id0], [t].[Description0], [t].[EndTime0], [t].[StartTime0] + FROM ( + SELECT DISTINCT [m].[Id], [m].[Description], [m].[EndTime], [m].[StartTime], [m0].[Id] AS [Id0], [m0].[Description] AS [Description0], [m0].[EndTime] AS [EndTime0], [m0].[StartTime] AS [StartTime0] + FROM [MainEntityDifferentTable] AS [m] + INNER JOIN [MainEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m0] ON [m].[Id] = [m0].[Id] + ) AS [t] + ORDER BY [t].[Id] DESC +) AS [t0] +INNER JOIN [MainEntityDifferentTable] AS [m1] ON [t0].[Id] = [m1].[Id] +LEFT JOIN [OwnedEntityDifferentTable] AS [o] ON [t0].[Id] = [o].[MainEntityDifferentTableId] +LEFT JOIN [OwnedEntityDifferentTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [o0] ON [t0].[Id0] = [o0].[MainEntityDifferentTableId] +LEFT JOIN [OwnedEntityDifferentTable] AS [o1] ON [m1].[Id] = [o1].[MainEntityDifferentTableId] +ORDER BY [t0].[Id] DESC"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_range_operation_negative(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var message = async + ? (await Assert.ThrowsAsync( + () => context.MainEntitiesDifferentTable.TemporalAll().ToListAsync())).Message + : Assert.Throws(() => context.MainEntitiesDifferentTable.TemporalAll().ToList()).Message; + + Assert.Equal( + SqlServerStrings.TemporalNavigationExpansionOnlySupportedForAsOf("AsOf"), + message); + } + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_mapped_to_same_table(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + var query = context.MainEntitiesSameTable.TemporalAsOf(date); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"SELECT [m].[Id], [m].[EndTime], [m].[Name], [m].[StartTime], [m].[EndTime], [m].[OwnedEntity_Name], [m].[OwnedEntity_Number], [m].[StartTime], [m].[OwnedEntity_Nested_Name], [m].[OwnedEntity_Nested_Number] +FROM [MainEntitiesSameTable] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m]"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_many(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + var query = context.MainEntitiesMany.TemporalAsOf(date); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"SELECT [m].[Id], [m].[Name], [m].[PeriodEnd], [m].[PeriodStart], [o].[MainEntityManyId], [o].[Id], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart] +FROM [MainEntitiesMany] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m] +LEFT JOIN [OwnedEntityMany] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [o] ON [m].[Id] = [o].[MainEntityManyId] +ORDER BY [m].[Id], [o].[MainEntityManyId]"); + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_owned_with_union(bool async) + { + var contextFactory = await InitializeAsync(); + using (var context = contextFactory.CreateContext()) + { + var date = new DateTime(2000, 1, 1); + var query = context.MainEntitiesMany.TemporalAsOf(date) + .Union(context.MainEntitiesMany.TemporalAsOf(date).Where(e => e.Id < 30)); + + var _ = async ? await query.ToListAsync() : query.ToList(); + } + + AssertSql( + @"SELECT [t].[Id], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [o].[MainEntityManyId], [o].[Id], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart] +FROM ( + SELECT [m].[Id], [m].[Name], [m].[PeriodEnd], [m].[PeriodStart] + FROM [MainEntitiesMany] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m] + UNION + SELECT [m0].[Id], [m0].[Name], [m0].[PeriodEnd], [m0].[PeriodStart] + FROM [MainEntitiesMany] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [m0] + WHERE [m0].[Id] < 30 +) AS [t] +LEFT JOIN [OwnedEntityMany] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [o] ON [t].[Id] = [o].[MainEntityManyId] +ORDER BY [t].[Id], [o].[MainEntityManyId]"); + } + + public class MainEntityDifferentTable + { + public int Id { get; set; } + public string Description { get; set; } + public OwnedEntityDifferentTable OwnedEntity { get; set; } + } + + public class OwnedEntityDifferentTable + { + public string Description { get; set; } + } + + public class MainEntitySameTable + { + public int Id { get; set; } + public string Name { get; set; } + + public OwnedEntitySameTable OwnedEntity { get; set; } + } + + public class OwnedEntitySameTable + { + public string Name { get; set; } + public int Number { get; set; } + + public OwnedEntitySameTableNested Nested { get; set; } + } + + public class OwnedEntitySameTableNested + { + public string Name { get; set; } + public int Number { get; set; } + } + + public class MainEntityMany + { + public int Id { get; set; } + public string Name { get; set; } + public List OwnedCollection { get; set; } + } + + public class OwnedEntityMany + { + public string Name { get; set; } + } + + public class MyContext26451 : DbContext + { + public MyContext26451(DbContextOptions options) + : base(options) + { + } + + public DbSet MainEntitiesDifferentTable { get; set; } + public DbSet MainEntitiesSameTable { get; set; } + public DbSet MainEntitiesMany { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().ToTable("MainEntityDifferentTable", tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("StartTime"); + ttb.HasPeriodEnd("EndTime"); + ttb.UseHistoryTable("ConfHistory"); + })); + modelBuilder.Entity().Property(me => me.Id).UseIdentityColumn(); + modelBuilder.Entity().OwnsOne(me => me.OwnedEntity).WithOwner(); + modelBuilder.Entity().OwnsOne(me => me.OwnedEntity, oe => + { + oe.ToTable("OwnedEntityDifferentTable", tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("StartTime"); + ttb.HasPeriodEnd("EndTime"); + ttb.UseHistoryTable("OwnedEntityHistory"); + })); + }); + + modelBuilder.Entity(eb => + { + eb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("StartTime").HasColumnName("StartTime"); + ttb.HasPeriodEnd("EndTime").HasColumnName("EndTime"); + })); + + eb.OwnsOne(x => x.OwnedEntity, oeb => + { + oeb.WithOwner(); + oeb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("StartTime").HasColumnName("StartTime"); + ttb.HasPeriodEnd("EndTime").HasColumnName("EndTime"); + })); + oeb.OwnsOne(x => x.Nested, neb => + { + neb.WithOwner(); + neb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("StartTime").HasColumnName("StartTime"); + ttb.HasPeriodEnd("EndTime").HasColumnName("EndTime"); + })); + }); + }); + }); + + modelBuilder.Entity(eb => + { + eb.ToTable(tb => tb.IsTemporal()); + eb.OwnsMany(x => x.OwnedCollection, oeb => oeb.ToTable(tb => tb.IsTemporal())); + }); + } + } + + [ConditionalTheory] + [InlineData(true)] + [InlineData(false)] + public virtual async Task Temporal_can_query_shared_derived_hierarchy(bool async) + { + var contectFactory = await InitializeAsync(OnModelCreating); + using var context = contectFactory.CreateContext(); + var query = context.Set().TemporalAsOf(new DateTime(2000, 1, 1)); + var _ = async ? await query.ToListAsync() : query.ToList(); + + AssertSql( + @"SELECT [v].[Name], [v].[Capacity], [v].[FuelTank_Discriminator], [v].[End], [v].[FuelType], [v].[Start], [v].[GrainGeometry] +FROM [Vehicles] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [v] +INNER JOIN ( + SELECT [v0].[Name], [v0].[Discriminator], [v0].[End], [v0].[SeatingCapacity], [v0].[Start], [v0].[AttachedVehicleName] + FROM [Vehicles] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [v0] + WHERE [v0].[Discriminator] IN (N'PoweredVehicle', N'CompositeVehicle') +) AS [t] ON [v].[Name] = [t].[Name] +WHERE ([v].[Capacity] IS NOT NULL) AND ([v].[FuelTank_Discriminator] IS NOT NULL) +UNION +SELECT [v1].[Name], [v1].[Capacity], [v1].[FuelTank_Discriminator], [v1].[End], [v1].[FuelType], [v1].[Start], [v1].[GrainGeometry] +FROM [Vehicles] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [v1] +INNER JOIN ( + SELECT [v2].[Name], [v2].[Computed], [v2].[Description], [v2].[Engine_Discriminator], [v2].[End], [v2].[Start], [t2].[Name] AS [Name0] + FROM [Vehicles] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [v2] + INNER JOIN ( + SELECT [v3].[Name], [v3].[Discriminator], [v3].[End], [v3].[SeatingCapacity], [v3].[Start], [v3].[AttachedVehicleName] + FROM [Vehicles] FOR SYSTEM_TIME AS OF '2000-01-01T00:00:00.0000000' AS [v3] + WHERE [v3].[Discriminator] IN (N'PoweredVehicle', N'CompositeVehicle') + ) AS [t2] ON [v2].[Name] = [t2].[Name] + WHERE [v2].[Engine_Discriminator] IN (N'ContinuousCombustionEngine', N'IntermittentCombustionEngine', N'SolidRocket') +) AS [t1] ON [v1].[Name] = [t1].[Name] +WHERE ([v1].[Capacity] IS NOT NULL) AND ([v1].[FuelTank_Discriminator] IS NOT NULL)"); + } + + protected Task> InitializeAsync( + Action onModelCreating, bool seed = true) + { + return InitializeAsync( + onModelCreating, shouldLogCategory: _ => true, seed: seed ? c => c.Seed() : null); + } + + protected virtual void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity( + eb => + { + eb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("Start").HasColumnName("Start"); + ttb.HasPeriodEnd("End").HasColumnName("End"); + })); + eb.HasDiscriminator("Discriminator"); + eb.Property("Discriminator").HasColumnName("Discriminator"); + eb.ToTable("Vehicles"); + }); + + modelBuilder.Entity(); + + modelBuilder.Entity() + .ToTable("Vehicles", tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("Start").HasColumnName("Start"); + ttb.HasPeriodEnd("End").HasColumnName("End"); + })); + + modelBuilder.Entity().ToTable("Vehicles", tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("Start").HasColumnName("Start"); + ttb.HasPeriodEnd("End").HasColumnName("End"); + })); + + modelBuilder.Entity().ToTable("Vehicles", tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("Start").HasColumnName("Start"); + ttb.HasPeriodEnd("End").HasColumnName("End"); + })); + + modelBuilder.Entity().ToTable("Vehicles", tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("Start").HasColumnName("Start"); + ttb.HasPeriodEnd("End").HasColumnName("End"); + })); + } + } +} diff --git a/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs b/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs index 26a1ef72333..fe9d99b1af6 100644 --- a/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs +++ b/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs @@ -782,14 +782,25 @@ public void Temporal_doesnt_work_on_TPH() } [ConditionalFact] - public void Temporal_doesnt_work_on_table_splitting() + public void Temporal_doesnt_work_on_table_splitting_with_inconsistent_period_mappings() { var modelBuilder = CreateConventionalModelBuilder(); modelBuilder.Entity().ToTable("Splitting", tb => tb.IsTemporal()); modelBuilder.Entity().ToTable("Splitting", tb => tb.IsTemporal()); modelBuilder.Entity().HasOne(x => x.Details).WithOne().HasForeignKey(x => x.Id); - VerifyError(SqlServerStrings.TemporalNotSupportedForTableSplitting("Splitting"), modelBuilder); + VerifyError(SqlServerStrings.TemporalNotSupportedForTableSplittingWithInconsistentPeriodMapping("start", "Splitting2", "PeriodStart", "Splitting2_PeriodStart", "PeriodStart"), modelBuilder); + } + + [ConditionalFact] + public void Temporal_doesnt_work_on_table_splitting_when_some_types_are_temporal_and_some_are_not() + { + var modelBuilder = CreateConventionalModelBuilder(); + modelBuilder.Entity().ToTable("Splitting"); + modelBuilder.Entity().ToTable("Splitting", tb => tb.IsTemporal()); + modelBuilder.Entity().HasOne(x => x.Details).WithOne().HasForeignKey(x => x.Id); + + VerifyError(SqlServerStrings.TemporalAllEntitiesMappedToSameTableMustBeTemporal("Splitting1"), modelBuilder); } public class Human diff --git a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs index 633c22fa350..2d811678994 100644 --- a/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs +++ b/test/EFCore.SqlServer.Tests/ModelBuilding/SqlServerModelBuilderGenericTest.cs @@ -993,19 +993,23 @@ public virtual void Temporal_table_with_changed_configuration() var modelBuilder = CreateModelBuilder(); var model = modelBuilder.Model; - modelBuilder.Entity().ToTable(tb => tb.IsTemporal(ttb => - { - ttb.UseHistoryTable("HistoryTable", "historySchema"); - ttb.HasPeriodStart("MyPeriodStart").HasColumnName("PeriodStartColumn"); - ttb.HasPeriodEnd("MyPeriodEnd").HasColumnName("PeriodEndColumn"); - })); - - modelBuilder.Entity().ToTable(tb => tb.IsTemporal(ttb => - { - ttb.UseHistoryTable("ChangedHistoryTable", "changedHistorySchema"); - ttb.HasPeriodStart("ChangedMyPeriodStart").HasColumnName("ChangedPeriodStartColumn"); - ttb.HasPeriodEnd("ChangedMyPeriodEnd").HasColumnName("ChangedPeriodEndColumn"); - })); + modelBuilder.Entity().ToTable( + tb => tb.IsTemporal( + ttb => + { + ttb.UseHistoryTable("HistoryTable", "historySchema"); + ttb.HasPeriodStart("MyPeriodStart"); + ttb.HasPeriodEnd("MyPeriodEnd"); + })); + + modelBuilder.Entity().ToTable( + tb => tb.IsTemporal( + ttb => + { + ttb.UseHistoryTable("ChangedHistoryTable", "changedHistorySchema"); + ttb.HasPeriodStart("ChangedMyPeriodStart"); + ttb.HasPeriodEnd("ChangedMyPeriodEnd"); + })); modelBuilder.FinalizeModel(); @@ -1020,12 +1024,61 @@ public virtual void Temporal_table_with_changed_configuration() var periodEnd = entity.GetProperty(entity.GetPeriodEndPropertyName()); Assert.Equal("ChangedMyPeriodStart", periodStart.Name); - Assert.Equal("ChangedPeriodStartColumn", periodStart[RelationalAnnotationNames.ColumnName]); + Assert.Equal("ChangedMyPeriodStart", periodStart[RelationalAnnotationNames.ColumnName]); Assert.True(periodStart.IsShadowProperty()); Assert.Equal(typeof(DateTime), periodStart.ClrType); Assert.Equal(ValueGenerated.OnAddOrUpdate, periodStart.ValueGenerated); Assert.Equal("ChangedMyPeriodEnd", periodEnd.Name); + Assert.Equal("ChangedMyPeriodEnd", periodEnd[RelationalAnnotationNames.ColumnName]); + Assert.True(periodEnd.IsShadowProperty()); + Assert.Equal(typeof(DateTime), periodEnd.ClrType); + Assert.Equal(ValueGenerated.OnAddOrUpdate, periodEnd.ValueGenerated); + } + + [ConditionalFact] + public virtual void Temporal_table_with_period_column_names_changed_configuration() + { + var modelBuilder = CreateModelBuilder(); + var model = modelBuilder.Model; + + modelBuilder.Entity().ToTable( + tb => tb.IsTemporal( + ttb => + { + ttb.UseHistoryTable("HistoryTable", "historySchema"); + ttb.HasPeriodStart("MyPeriodStart").HasColumnName("PeriodStartColumn"); + ttb.HasPeriodEnd("MyPeriodEnd").HasColumnName("PeriodEndColumn"); + })); + + modelBuilder.Entity().ToTable( + tb => tb.IsTemporal( + ttb => + { + ttb.UseHistoryTable("ChangedHistoryTable", "changedHistorySchema"); + ttb.HasPeriodStart("MyPeriodStart").HasColumnName("ChangedPeriodStartColumn"); + ttb.HasPeriodEnd("MyPeriodEnd").HasColumnName("ChangedPeriodEndColumn"); + })); + + modelBuilder.FinalizeModel(); + + var entity = model.FindEntityType(typeof(Customer)); + Assert.True(entity.IsTemporal()); + Assert.Equal(5, entity.GetProperties().Count()); + + Assert.Equal("ChangedHistoryTable", entity.GetHistoryTableName()); + Assert.Equal("changedHistorySchema", entity.GetHistoryTableSchema()); + + var periodStart = entity.GetProperty(entity.GetPeriodStartPropertyName()); + var periodEnd = entity.GetProperty(entity.GetPeriodEndPropertyName()); + + Assert.Equal("MyPeriodStart", periodStart.Name); + Assert.Equal("ChangedPeriodStartColumn", periodStart[RelationalAnnotationNames.ColumnName]); + Assert.True(periodStart.IsShadowProperty()); + Assert.Equal(typeof(DateTime), periodStart.ClrType); + Assert.Equal(ValueGenerated.OnAddOrUpdate, periodStart.ValueGenerated); + + Assert.Equal("MyPeriodEnd", periodEnd.Name); Assert.Equal("ChangedPeriodEndColumn", periodEnd[RelationalAnnotationNames.ColumnName]); Assert.True(periodEnd.IsShadowProperty()); Assert.Equal(typeof(DateTime), periodEnd.ClrType);