diff --git a/src/EFCore.Relational/Extensions/RelationalEntityTypeBuilderExtensions.cs b/src/EFCore.Relational/Extensions/RelationalEntityTypeBuilderExtensions.cs index 6e7e9b2a29d..753be37a68c 100644 --- a/src/EFCore.Relational/Extensions/RelationalEntityTypeBuilderExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalEntityTypeBuilderExtensions.cs @@ -57,7 +57,7 @@ public static EntityTypeBuilder ToTable( { Check.NotNull(buildAction, nameof(buildAction)); - buildAction(new TableBuilder(null, null, entityTypeBuilder.Metadata)); + buildAction(new TableBuilder(null, null, entityTypeBuilder)); return entityTypeBuilder; } @@ -82,7 +82,7 @@ public static EntityTypeBuilder ToTable( entityTypeBuilder.Metadata.SetTableName(name); entityTypeBuilder.Metadata.SetSchema(null); - buildAction(new TableBuilder(name, null, entityTypeBuilder.Metadata)); + buildAction(new TableBuilder(name, null, entityTypeBuilder)); return entityTypeBuilder; } @@ -120,7 +120,7 @@ public static EntityTypeBuilder ToTable( { Check.NotNull(buildAction, nameof(buildAction)); - buildAction(new TableBuilder(null, null, entityTypeBuilder.Metadata)); + buildAction(new TableBuilder(null, null, entityTypeBuilder)); return entityTypeBuilder; } @@ -147,7 +147,7 @@ public static EntityTypeBuilder ToTable( entityTypeBuilder.Metadata.SetTableName(name); entityTypeBuilder.Metadata.SetSchema(null); - buildAction(new TableBuilder(name, null, entityTypeBuilder.Metadata)); + buildAction(new TableBuilder(name, null, entityTypeBuilder)); return entityTypeBuilder; } @@ -198,7 +198,7 @@ public static EntityTypeBuilder ToTable( entityTypeBuilder.Metadata.SetTableName(name); entityTypeBuilder.Metadata.SetSchema(schema); - buildAction(new TableBuilder(name, schema, entityTypeBuilder.Metadata)); + buildAction(new TableBuilder(name, schema, entityTypeBuilder)); return entityTypeBuilder; } @@ -246,7 +246,7 @@ public static EntityTypeBuilder ToTable( entityTypeBuilder.Metadata.SetTableName(name); entityTypeBuilder.Metadata.SetSchema(schema); - buildAction(new TableBuilder(name, schema, entityTypeBuilder.Metadata)); + buildAction(new TableBuilder(name, schema, entityTypeBuilder)); return entityTypeBuilder; } @@ -283,11 +283,11 @@ public static OwnedNavigationBuilder ToTable( /// The same builder instance so that multiple calls can be chained. public static OwnedNavigationBuilder ToTable( this OwnedNavigationBuilder referenceOwnershipBuilder, - Action buildAction) + Action buildAction) { Check.NotNull(buildAction, nameof(buildAction)); - buildAction(new TableBuilder(null, null, referenceOwnershipBuilder.OwnedEntityType)); + buildAction(new OwnedNavigationTableBuilder(referenceOwnershipBuilder)); return referenceOwnershipBuilder; } @@ -303,13 +303,13 @@ public static OwnedNavigationBuilder ToTable( /// The same builder instance so that multiple calls can be chained. public static OwnedNavigationBuilder ToTable( this OwnedNavigationBuilder referenceOwnershipBuilder, - Action> buildAction) + Action> buildAction) where TOwnerEntity : class where TRelatedEntity : class { Check.NotNull(buildAction, nameof(buildAction)); - buildAction(new TableBuilder(null, null, referenceOwnershipBuilder.OwnedEntityType)); + buildAction(new OwnedNavigationTableBuilder(referenceOwnershipBuilder)); return referenceOwnershipBuilder; } @@ -360,14 +360,14 @@ public static OwnedNavigationBuilder ToTable buildAction) + Action buildAction) { Check.NullButNotEmpty(name, nameof(name)); Check.NotNull(buildAction, nameof(buildAction)); referenceOwnershipBuilder.OwnedEntityType.SetTableName(name); referenceOwnershipBuilder.OwnedEntityType.SetSchema(null); - buildAction(new TableBuilder(name, null, referenceOwnershipBuilder.OwnedEntityType)); + buildAction(new OwnedNavigationTableBuilder(referenceOwnershipBuilder)); return referenceOwnershipBuilder; } @@ -405,7 +405,7 @@ public static OwnedNavigationBuilder ToTable ToTable( this OwnedNavigationBuilder referenceOwnershipBuilder, string? name, - Action> buildAction) + Action> buildAction) where TOwnerEntity : class where TRelatedEntity : class { @@ -414,7 +414,7 @@ public static OwnedNavigationBuilder ToTable(name, null, referenceOwnershipBuilder.OwnedEntityType)); + buildAction(new OwnedNavigationTableBuilder(referenceOwnershipBuilder)); return referenceOwnershipBuilder; } @@ -483,7 +483,7 @@ public static OwnedNavigationBuilder ToTable( this OwnedNavigationBuilder referenceOwnershipBuilder, string name, string? schema, - Action buildAction) + Action buildAction) { Check.NotNull(name, nameof(name)); Check.NullButNotEmpty(schema, nameof(schema)); @@ -491,7 +491,7 @@ public static OwnedNavigationBuilder ToTable( referenceOwnershipBuilder.OwnedEntityType.SetTableName(name); referenceOwnershipBuilder.OwnedEntityType.SetSchema(schema); - buildAction(new TableBuilder(name, schema, referenceOwnershipBuilder.OwnedEntityType)); + buildAction(new OwnedNavigationTableBuilder(referenceOwnershipBuilder)); return referenceOwnershipBuilder; } @@ -552,7 +552,7 @@ public static OwnedNavigationBuilder ToTable referenceOwnershipBuilder, string name, string? schema, - Action> buildAction) + Action> buildAction) where TOwnerEntity : class where TRelatedEntity : class { @@ -562,7 +562,7 @@ public static OwnedNavigationBuilder ToTable(name, schema, referenceOwnershipBuilder.OwnedEntityType)); + buildAction(new OwnedNavigationTableBuilder(referenceOwnershipBuilder)); return referenceOwnershipBuilder; } diff --git a/src/EFCore.Relational/Metadata/Builders/OwnedNavigationTableBuilder.cs b/src/EFCore.Relational/Metadata/Builders/OwnedNavigationTableBuilder.cs new file mode 100644 index 00000000000..5747c733bc6 --- /dev/null +++ b/src/EFCore.Relational/Metadata/Builders/OwnedNavigationTableBuilder.cs @@ -0,0 +1,81 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel; +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace Microsoft.EntityFrameworkCore.Metadata.Builders +{ + /// + /// Instances of this class are returned from methods when using the API + /// and it is not designed to be directly constructed in your application code. + /// + public class OwnedNavigationTableBuilder + { + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + public OwnedNavigationTableBuilder(OwnedNavigationBuilder ownedNavigationBuilder) + { + OwnedNavigationBuilder = ownedNavigationBuilder; + } + + /// + /// The entity type being configured. + /// + public virtual IMutableEntityType Metadata => OwnedNavigationBuilder.OwnedEntityType; + + /// + /// The entity type builder. + /// + public virtual OwnedNavigationBuilder OwnedNavigationBuilder { get; } + + /// + /// Configures the table to be ignored by migrations. + /// + /// + /// See Database migrations for more information. + /// + /// A value indicating whether the table should be managed by migrations. + /// The same builder instance so that multiple calls can be chained. + public virtual OwnedNavigationTableBuilder ExcludeFromMigrations(bool excluded = true) + { + Metadata.SetIsTableExcludedFromMigrations(excluded); + + return this; + } + + #region Hidden System.Object members + + /// + /// Returns a string that represents the current object. + /// + /// A string that represents the current object. + [EditorBrowsable(EditorBrowsableState.Never)] + public override string? ToString() + => base.ToString(); + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// if the specified object is equal to the current object; otherwise, . + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object? obj) + => base.Equals(obj); + + /// + /// Serves as the default hash function. + /// + /// A hash code for the current object. + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + => base.GetHashCode(); + + #endregion + } +} diff --git a/src/EFCore.Relational/Metadata/Builders/OwnedNavigationTableBuilder`.cs b/src/EFCore.Relational/Metadata/Builders/OwnedNavigationTableBuilder`.cs new file mode 100644 index 00000000000..d7e08162ab7 --- /dev/null +++ b/src/EFCore.Relational/Metadata/Builders/OwnedNavigationTableBuilder`.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace Microsoft.EntityFrameworkCore.Metadata.Builders +{ + /// + /// Instances of this class are returned from methods when using the API + /// and it is not designed to be directly constructed in your application code. + /// + /// The entity type being configured. + public class OwnedNavigationTableBuilder : OwnedNavigationTableBuilder + where TEntity : class + { + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + public OwnedNavigationTableBuilder(OwnedNavigationBuilder referenceOwnershipBuilder) + : base(referenceOwnershipBuilder) + { + } + + /// + /// Configures the table to be ignored by migrations. + /// + /// + /// See Database migrations for more information. + /// + /// A value indicating whether the table should be managed by migrations. + /// The same builder instance so that multiple calls can be chained. + public new virtual OwnedNavigationTableBuilder ExcludeFromMigrations(bool excluded = true) + => (OwnedNavigationTableBuilder)base.ExcludeFromMigrations(excluded); + } +} diff --git a/src/EFCore.Relational/Metadata/Builders/TableBuilder.cs b/src/EFCore.Relational/Metadata/Builders/TableBuilder.cs index 32076a6d81a..cad28c62e8d 100644 --- a/src/EFCore.Relational/Metadata/Builders/TableBuilder.cs +++ b/src/EFCore.Relational/Metadata/Builders/TableBuilder.cs @@ -21,15 +21,20 @@ public class TableBuilder /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public TableBuilder(string? name, string? schema, IMutableEntityType entityType) + public TableBuilder(string? name, string? schema, EntityTypeBuilder entityTypeBuilder) { - Metadata = entityType; + EntityTypeBuilder = entityTypeBuilder; } /// /// The entity type being configured. /// - public virtual IMutableEntityType Metadata { get; } + public virtual IMutableEntityType Metadata => EntityTypeBuilder.Metadata; + + /// + /// The entity type builder. + /// + public virtual EntityTypeBuilder EntityTypeBuilder { get; } /// /// Configures the table to be ignored by migrations. diff --git a/src/EFCore.Relational/Metadata/Builders/TableBuilder`.cs b/src/EFCore.Relational/Metadata/Builders/TableBuilder`.cs index 65e6261c1b3..eca55534bfb 100644 --- a/src/EFCore.Relational/Metadata/Builders/TableBuilder`.cs +++ b/src/EFCore.Relational/Metadata/Builders/TableBuilder`.cs @@ -22,8 +22,8 @@ public class TableBuilder : TableBuilder /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public TableBuilder(string? name, string? schema, IMutableEntityType entityType) - : base(name, schema, entityType) + public TableBuilder(string? name, string? schema, EntityTypeBuilder entityTypeBuilder) + : base(name, schema, entityTypeBuilder) { } diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 4562466f863..0087fc7968f 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -1435,11 +1435,24 @@ outerKey is NewArrayExpression newArrayExpression return null; } + var entityProjectionExpression = GetEntityProjectionExpression(entityShaperExpression); var foreignKey = navigation.ForeignKey; if (navigation.IsCollection) { + SelectExpression innerSelectExpression; + if (!AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) || !enabled26469) + { + 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 +1500,6 @@ outerKey is NewArrayExpression newArrayExpression Expression.Quote(correlationPredicate)); } - var entityProjectionExpression = GetEntityProjectionExpression(entityShaperExpression); var innerShaper = entityProjectionExpression.BindNavigation(navigation); if (innerShaper == null) { @@ -1530,7 +1542,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 (!AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) || !enabled26469) + { + innerSelectExpression = BuildInnerSelectExpressionForOwnedTypeMappedToDifferentTable( + entityProjectionExpression, + navigation); + } + else + { + innerSelectExpression = _sqlExpressionFactory.Select(targetEntityType); + } + var innerShapedQuery = CreateShapedQueryExpression(targetEntityType, innerSelectExpression); var makeNullable = foreignKey.PrincipalKey.Properties @@ -1584,6 +1608,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/Extensions/SqlServerTableBuilderExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerTableBuilderExtensions.cs index 514eb95c9da..005b71e7f4e 100644 --- a/src/EFCore.SqlServer/Extensions/SqlServerTableBuilderExtensions.cs +++ b/src/EFCore.SqlServer/Extensions/SqlServerTableBuilderExtensions.cs @@ -3,6 +3,7 @@ using System; using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Builders; // ReSharper disable once CheckNamespace namespace Microsoft.EntityFrameworkCore @@ -28,7 +29,7 @@ public static TemporalTableBuilder IsTemporal( { tableBuilder.Metadata.SetIsTemporal(temporal); - return new TemporalTableBuilder(tableBuilder.Metadata); + return new TemporalTableBuilder(tableBuilder.EntityTypeBuilder); } /// @@ -47,7 +48,7 @@ public static TableBuilder IsTemporal( { tableBuilder.Metadata.SetIsTemporal(true); - buildAction(new TemporalTableBuilder(tableBuilder.Metadata)); + buildAction(new TemporalTableBuilder(tableBuilder.EntityTypeBuilder)); return tableBuilder; } @@ -70,7 +71,7 @@ public static TemporalTableBuilder IsTemporal( { tableBuilder.Metadata.SetIsTemporal(temporal); - return new TemporalTableBuilder(tableBuilder.Metadata); + return new TemporalTableBuilder(tableBuilder.EntityTypeBuilder); } /// @@ -90,7 +91,90 @@ public static TableBuilder IsTemporal( where TEntity : class { tableBuilder.Metadata.SetIsTemporal(true); - buildAction(new TemporalTableBuilder(tableBuilder.Metadata)); + buildAction(new TemporalTableBuilder(tableBuilder.EntityTypeBuilder)); + + return tableBuilder; + } + + /// + /// Configures the table as temporal. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The builder for the table being configured. + /// A value indicating whether the table is temporal. + /// An object that can be used to configure the temporal table. + public static OwnedNavigationTemporalTableBuilder IsTemporal( + this OwnedNavigationTableBuilder tableBuilder, + bool temporal = true) + { + tableBuilder.Metadata.SetIsTemporal(temporal); + + return new OwnedNavigationTemporalTableBuilder(tableBuilder.OwnedNavigationBuilder); + } + + /// + /// Configures the table as temporal. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The builder for the table being configured. + /// An action that performs configuration of the temporal table. + /// The same builder instance so that multiple calls can be chained. + public static OwnedNavigationTableBuilder IsTemporal( + this OwnedNavigationTableBuilder tableBuilder, + Action buildAction) + { + tableBuilder.Metadata.SetIsTemporal(true); + + buildAction(new OwnedNavigationTemporalTableBuilder(tableBuilder.OwnedNavigationBuilder)); + + return tableBuilder; + } + + /// + /// Configures the table as temporal. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The entity type being configured. + /// The builder for the table being configured. + /// A value indicating whether the table is temporal. + /// An object that can be used to configure the temporal table. + public static OwnedNavigationTemporalTableBuilder IsTemporal( + this OwnedNavigationTableBuilder tableBuilder, + bool temporal = true) + where TEntity : class + { + tableBuilder.Metadata.SetIsTemporal(temporal); + + return new OwnedNavigationTemporalTableBuilder(tableBuilder.OwnedNavigationBuilder); + } + + /// + /// Configures the table as temporal. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The entity type being configured. + /// The builder for the table being configured. + /// An action that performs configuration of the temporal table. + /// The same builder instance so that multiple calls can be chained. + public static OwnedNavigationTableBuilder IsTemporal( + this OwnedNavigationTableBuilder tableBuilder, + Action> buildAction) + where TEntity : class + { + tableBuilder.Metadata.SetIsTemporal(true); + buildAction(new OwnedNavigationTemporalTableBuilder(tableBuilder.OwnedNavigationBuilder)); return tableBuilder; } diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerModelValidator.cs b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerModelValidator.cs index 28234ddc34b..ac8a50f0ab6 100644 --- a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerModelValidator.cs +++ b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerModelValidator.cs @@ -349,7 +349,65 @@ protected override void ValidateSharedTableCompatibility( if (mappedTypes.Any(t => t.IsTemporal()) && mappedTypes.Select(t => t.GetRootType()).Distinct().Count() > 1) { - throw new InvalidOperationException(SqlServerStrings.TemporalNotSupportedForTableSplitting(tableName)); + if (AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) && enabled26469) + { + 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/Builders/OwnedNavigationTemporalPeriodPropertyBuilder.cs b/src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalPeriodPropertyBuilder.cs new file mode 100644 index 00000000000..584429b48c9 --- /dev/null +++ b/src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalPeriodPropertyBuilder.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Microsoft.EntityFrameworkCore.SqlServer.Metadata.Builders +{ + /// + /// Instances of this class are returned from methods when using the API + /// and it is not designed to be directly constructed in your application code. + /// + public class OwnedNavigationTemporalPeriodPropertyBuilder + { + private readonly PropertyBuilder _propertyBuilder; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + public OwnedNavigationTemporalPeriodPropertyBuilder( + PropertyBuilder propertyBuilder) + { + _propertyBuilder = propertyBuilder; + } + + /// + /// Configures the column name the period property maps to. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The name of the column. + /// The same builder instance so that multiple calls can be chained. + public virtual OwnedNavigationTemporalPeriodPropertyBuilder HasColumnName(string name) + { + _propertyBuilder.HasColumnName(name); + + return this; + } + + #region Hidden System.Object members + + /// + /// Returns a string that represents the current object. + /// + /// A string that represents the current object. + [EditorBrowsable(EditorBrowsableState.Never)] + public override string? ToString() + => base.ToString(); + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// if the specified object is equal to the current object; otherwise, . + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object? obj) + => base.Equals(obj); + + /// + /// Serves as the default hash function. + /// + /// A hash code for the current object. + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + => base.GetHashCode(); + + #endregion + } +} diff --git a/src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalTableBuilder.cs b/src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalTableBuilder.cs new file mode 100644 index 00000000000..d27e9ded8cd --- /dev/null +++ b/src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalTableBuilder.cs @@ -0,0 +1,151 @@ +// 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.ComponentModel; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Microsoft.EntityFrameworkCore.SqlServer.Metadata.Builders +{ + /// + /// Instances of this class are returned from methods when using the API + /// and it is not designed to be directly constructed in your application code. + /// + public class OwnedNavigationTemporalTableBuilder + { + private readonly OwnedNavigationBuilder _referenceOwnershipBuilder; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + public OwnedNavigationTemporalTableBuilder(OwnedNavigationBuilder referenceOwnershipBuilder) + { + _referenceOwnershipBuilder = referenceOwnershipBuilder; + } + + /// + /// Configures a history table for the entity mapped to a temporal table. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The name of the history table. + /// The same builder instance so that multiple calls can be chained. + public virtual OwnedNavigationTemporalTableBuilder UseHistoryTable(string name) + { + _referenceOwnershipBuilder.OwnedEntityType.SetHistoryTableName(name); + + return this; + } + + /// + /// Configures a history table for the entity mapped to a temporal table. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The name of the history table. + /// The schema of the history table. + /// The same builder instance so that multiple calls can be chained. + public virtual OwnedNavigationTemporalTableBuilder UseHistoryTable(string name, string? schema) + { + _referenceOwnershipBuilder.OwnedEntityType.SetHistoryTableName(name); + _referenceOwnershipBuilder.OwnedEntityType.SetHistoryTableSchema(schema); + + return this; + } + + /// + /// Returns an object that can be used to configure a period start property of the entity type mapped to a temporal table. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The name of the period start property. + /// An object that can be used to configure the period start property. + public virtual OwnedNavigationTemporalPeriodPropertyBuilder HasPeriodStart(string propertyName) + { + _referenceOwnershipBuilder.OwnedEntityType.SetPeriodStartPropertyName(propertyName); + var property = ConfigurePeriodProperty(propertyName); + +#pragma warning disable EF1001 // Internal EF Core API usage. + return new OwnedNavigationTemporalPeriodPropertyBuilder(new PropertyBuilder(property)); +#pragma warning restore EF1001 // Internal EF Core API usage. + } + + /// + /// Returns an object that can be used to configure a period end property of the entity type mapped to a temporal table. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The name of the period end property. + /// An object that can be used to configure the period end property. + public virtual OwnedNavigationTemporalPeriodPropertyBuilder HasPeriodEnd(string propertyName) + { + _referenceOwnershipBuilder.OwnedEntityType.SetPeriodEndPropertyName(propertyName); + var property = ConfigurePeriodProperty(propertyName); + +#pragma warning disable EF1001 // Internal EF Core API usage. + return new OwnedNavigationTemporalPeriodPropertyBuilder(new PropertyBuilder(property)); +#pragma warning restore EF1001 // Internal EF Core API usage. + } + + private IMutableProperty ConfigurePeriodProperty(string propertyName) + { + // TODO: Configure the property explicitly, but remove it if it's no longer used, issue #15898 + var conventionPropertyBuilder = _referenceOwnershipBuilder.GetInfrastructure().Property( + typeof(DateTime), + propertyName, + setTypeConfigurationSource: false); + + // if convention builder is null, it means the property with this name exists, but it has incorrect type + // we will throw in the model validation + if (conventionPropertyBuilder != null) + { + conventionPropertyBuilder.ValueGenerated(ValueGenerated.OnAddOrUpdate); + } + + return _referenceOwnershipBuilder.OwnedEntityType.FindProperty(propertyName)!; + } + + #region Hidden System.Object members + + /// + /// Returns a string that represents the current object. + /// + /// A string that represents the current object. + [EditorBrowsable(EditorBrowsableState.Never)] + public override string? ToString() + => base.ToString(); + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// if the specified object is equal to the current object; otherwise, . + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object? obj) + => base.Equals(obj); + + /// + /// Serves as the default hash function. + /// + /// A hash code for the current object. + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() + => base.GetHashCode(); + + #endregion + } +} diff --git a/src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalTableBuilder`.cs b/src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalTableBuilder`.cs new file mode 100644 index 00000000000..d9ee2db0121 --- /dev/null +++ b/src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalTableBuilder`.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Microsoft.EntityFrameworkCore.SqlServer.Metadata.Builders +{ + /// + /// Instances of this class are returned from methods when using the API + /// and it is not designed to be directly constructed in your application code. + /// + /// The entity type being configured. + public class OwnedNavigationTemporalTableBuilder : OwnedNavigationTemporalTableBuilder + where TEntity : class + { + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + public OwnedNavigationTemporalTableBuilder(OwnedNavigationBuilder referenceOwnershipBuilder) + : base(referenceOwnershipBuilder) + { + } + + /// + /// Configures a history table for the entity mapped to a temporal table. + /// + /// + /// See Using SQL Server temporal tables with EF Core + /// for more information. + /// + /// The name of the history table. + /// The schema of the history table. + /// The same builder instance so that multiple calls can be chained. + public new virtual OwnedNavigationTemporalTableBuilder UseHistoryTable(string name, string? schema = null) + => (OwnedNavigationTemporalTableBuilder)base.UseHistoryTable(name, schema); + } +} diff --git a/src/EFCore.SqlServer/Metadata/Builders/TemporalPeriodPropertyBuilder.cs b/src/EFCore.SqlServer/Metadata/Builders/TemporalPeriodPropertyBuilder.cs index 2a0a71f48a3..e66ca3cfa4d 100644 --- a/src/EFCore.SqlServer/Metadata/Builders/TemporalPeriodPropertyBuilder.cs +++ b/src/EFCore.SqlServer/Metadata/Builders/TemporalPeriodPropertyBuilder.cs @@ -14,8 +14,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Builders /// public class TemporalPeriodPropertyBuilder { - private readonly IMutableEntityType _entityType; - private readonly string _periodPropertyName; + private readonly PropertyBuilder _propertyBuilder; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -24,10 +23,9 @@ public class TemporalPeriodPropertyBuilder /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public TemporalPeriodPropertyBuilder(IMutableEntityType entityType, string periodPropertyName) + public TemporalPeriodPropertyBuilder(PropertyBuilder propertyBuilder) { - _entityType = entityType; - _periodPropertyName = periodPropertyName; + _propertyBuilder = propertyBuilder; } /// @@ -41,7 +39,9 @@ public TemporalPeriodPropertyBuilder(IMutableEntityType entityType, string perio /// The same builder instance so that multiple calls can be chained. public virtual TemporalPeriodPropertyBuilder HasColumnName(string name) { - _entityType.GetProperty(_periodPropertyName).SetColumnName(name); + // when column name is set explicitly, use the regular (i.e. non-convention) builder + // so that the column name doesn't get uniquified + _propertyBuilder.HasColumnName(name); return this; } diff --git a/src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder.cs b/src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder.cs index 1bd6df1035d..2edc18f372f 100644 --- a/src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder.cs +++ b/src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder.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 System.ComponentModel; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -14,7 +15,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Builders /// public class TemporalTableBuilder { - private readonly IMutableEntityType _entityType; + private readonly EntityTypeBuilder _entityTypeBuilder; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -23,9 +24,9 @@ public class TemporalTableBuilder /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public TemporalTableBuilder(IMutableEntityType entityType) + public TemporalTableBuilder(EntityTypeBuilder entityTypeBuilder) { - _entityType = entityType; + _entityTypeBuilder = entityTypeBuilder; } /// @@ -39,7 +40,7 @@ public TemporalTableBuilder(IMutableEntityType entityType) /// The same builder instance so that multiple calls can be chained. public virtual TemporalTableBuilder UseHistoryTable(string name) { - _entityType.SetHistoryTableName(name); + _entityTypeBuilder.Metadata.SetHistoryTableName(name); return this; } @@ -56,8 +57,8 @@ public virtual TemporalTableBuilder UseHistoryTable(string name) /// The same builder instance so that multiple calls can be chained. public virtual TemporalTableBuilder UseHistoryTable(string name, string? schema) { - _entityType.SetHistoryTableName(name); - _entityType.SetHistoryTableSchema(schema); + _entityTypeBuilder.Metadata.SetHistoryTableName(name); + _entityTypeBuilder.Metadata.SetHistoryTableSchema(schema); return this; } @@ -73,9 +74,12 @@ public virtual TemporalTableBuilder UseHistoryTable(string name, string? schema) /// An object that can be used to configure the period start property. public virtual TemporalPeriodPropertyBuilder HasPeriodStart(string propertyName) { - _entityType.SetPeriodStartPropertyName(propertyName); + _entityTypeBuilder.Metadata.SetPeriodStartPropertyName(propertyName); + var property = ConfigurePeriodProperty(propertyName); - return new TemporalPeriodPropertyBuilder(_entityType, propertyName); +#pragma warning disable EF1001 // Internal EF Core API usage. + return new TemporalPeriodPropertyBuilder(new PropertyBuilder(property)); +#pragma warning disable EF1001 // Internal EF Core API usage. } /// @@ -89,9 +93,30 @@ public virtual TemporalPeriodPropertyBuilder HasPeriodStart(string propertyName) /// An object that can be used to configure the period end property. public virtual TemporalPeriodPropertyBuilder HasPeriodEnd(string propertyName) { - _entityType.SetPeriodEndPropertyName(propertyName); + _entityTypeBuilder.Metadata.SetPeriodEndPropertyName(propertyName); + var property = ConfigurePeriodProperty(propertyName); - return new TemporalPeriodPropertyBuilder(_entityType, propertyName); +#pragma warning disable EF1001 // Internal EF Core API usage. + return new TemporalPeriodPropertyBuilder(new PropertyBuilder(property)); +#pragma warning disable EF1001 // Internal EF Core API usage. + } + + private IMutableProperty ConfigurePeriodProperty(string propertyName) + { + // TODO: Configure the property explicitly, but remove it if it's no longer used, issue #15898 + var conventionPropertyBuilder = _entityTypeBuilder.GetInfrastructure().Property( + typeof(DateTime), + propertyName, + setTypeConfigurationSource: false); + + // if convention builder is null, it means the property with this name exists, but it has incorrect type + // we will throw in the model validation + if (conventionPropertyBuilder != null) + { + conventionPropertyBuilder.ValueGenerated(ValueGenerated.OnAddOrUpdate); + } + + return _entityTypeBuilder.Metadata.FindProperty(propertyName)!; } #region Hidden System.Object members diff --git a/src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder`.cs b/src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder`.cs index 4cc376082bc..ca857e8c27d 100644 --- a/src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder`.cs +++ b/src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder`.cs @@ -22,8 +22,8 @@ public class TemporalTableBuilder : TemporalTableBuilder /// doing so can result in application failures when updating to a new Entity Framework Core release. /// [EntityFrameworkInternal] - public TemporalTableBuilder(IMutableEntityType entityType) - : base(entityType) + public TemporalTableBuilder(EntityTypeBuilder entityTypeBuilder) + : base(entityTypeBuilder) { } diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs index 96ac9408605..6d3a0fed5d9 100644 --- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs +++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs @@ -66,8 +66,18 @@ public override ConventionSet CreateConventionSet() var sqlServerInMemoryTablesConvention = new SqlServerMemoryOptimizedTablesConvention(Dependencies, RelationalDependencies); conventionSet.EntityTypeAnnotationChangedConventions.Add(sqlServerInMemoryTablesConvention); + + ReplaceConvention( + conventionSet.ForeignKeyPropertiesChangedConventions, + (RelationalValueGenerationConvention)valueGenerationConvention); + ReplaceConvention( - conventionSet.EntityTypeAnnotationChangedConventions, (RelationalValueGenerationConvention)valueGenerationConvention); + conventionSet.ForeignKeyOwnershipChangedConventions, + (RelationalValueGenerationConvention)valueGenerationConvention); + + ReplaceConvention( + 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..3f58701f68f 100644 --- a/src/EFCore.SqlServer/Query/Internal/SqlServerNavigationExpansionExtensibilityHelper.cs +++ b/src/EFCore.SqlServer/Query/Internal/SqlServerNavigationExpansionExtensibilityHelper.cs @@ -35,25 +35,44 @@ 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); + } - if (source is TemporalAsOfQueryRootExpression asOf) + 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) + { + if (!AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) || !enabled26469) + { + 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..92eabb5b3c3 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,122 @@ protected override void GenerateLimitOffset(SelectExpression selectExpression) /// protected override Expression VisitExtension(Expression extensionExpression) { - if (extensionExpression is TemporalTableExpression temporalTableExpression) + if (AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) && enabled26469) { - Sql.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(temporalTableExpression.Name, temporalTableExpression.Schema)) +#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(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..39b00cd4ad0 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,70 @@ 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; + if (AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) && enabled26469) { - 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); + // 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 + { + 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 +144,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..056792245f5 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,16 @@ public SqlServerSqlNullabilityProcessor( /// protected override TableExpressionBase Visit(TableExpressionBase tableExpressionBase) { - return tableExpressionBase is TemporalTableExpression temporalTableExpression - ? temporalTableExpression - : base.Visit(tableExpressionBase); + if (AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue26469", out var enabled26469) && enabled26469) + { +#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.Relational.Tests/ModelBuilding/RelationalModelBuilderGenericTestBase.cs b/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderGenericTestBase.cs index f5598af1808..fc48f207555 100644 --- a/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderGenericTestBase.cs +++ b/test/EFCore.Relational.Tests/ModelBuilding/RelationalModelBuilderGenericTestBase.cs @@ -55,6 +55,50 @@ public override TestTableBuilder ExcludeFromMigrations(bool excluded = => Wrap(TableBuilder.ExcludeFromMigrations(excluded)); } + public abstract class TestOwnedNavigationTableBuilder + where TEntity : class + { + public abstract TestOwnedNavigationTableBuilder ExcludeFromMigrations(bool excluded = true); + } + + public class GenericTestOwnedNavigationTableBuilder : TestOwnedNavigationTableBuilder, IInfrastructure> + where TEntity : class + { + public GenericTestOwnedNavigationTableBuilder(OwnedNavigationTableBuilder tableBuilder) + { + TableBuilder = tableBuilder; + } + + protected OwnedNavigationTableBuilder TableBuilder { get; } + + public OwnedNavigationTableBuilder Instance => TableBuilder; + + protected virtual TestOwnedNavigationTableBuilder Wrap(OwnedNavigationTableBuilder tableBuilder) + => new GenericTestOwnedNavigationTableBuilder(tableBuilder); + + public override TestOwnedNavigationTableBuilder ExcludeFromMigrations(bool excluded = true) + => Wrap(TableBuilder.ExcludeFromMigrations(excluded)); + } + + public class NonGenericTestOwnedNavigationTableBuilder : TestOwnedNavigationTableBuilder, IInfrastructure + where TEntity : class + { + public NonGenericTestOwnedNavigationTableBuilder(OwnedNavigationTableBuilder tableBuilder) + { + TableBuilder = tableBuilder; + } + + protected OwnedNavigationTableBuilder TableBuilder { get; } + + public OwnedNavigationTableBuilder Instance => TableBuilder; + + protected virtual TestOwnedNavigationTableBuilder Wrap(OwnedNavigationTableBuilder tableBuilder) + => new NonGenericTestOwnedNavigationTableBuilder(tableBuilder); + + public override TestOwnedNavigationTableBuilder ExcludeFromMigrations(bool excluded = true) + => Wrap(TableBuilder.ExcludeFromMigrations(excluded)); + } + public abstract class TestCheckConstraintBuilder { public abstract TestCheckConstraintBuilder HasName(string name); diff --git a/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs b/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs index e5550344414..1bfaa8d5183 100644 --- a/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs +++ b/test/EFCore.Relational.Tests/ModelBuilding/RelationalTestModelBuilderExtensions.cs @@ -235,7 +235,7 @@ public static ModelBuilderTest.TestOwnedNavigationBuilder ToTable( this ModelBuilderTest.TestOwnedNavigationBuilder builder, string? name, - Action> buildAction) + Action> buildAction) where TOwnerEntity : class where TRelatedEntity : class { @@ -243,11 +243,11 @@ public static ModelBuilderTest.TestOwnedNavigationBuilder> genericBuilder: genericBuilder.Instance.ToTable(name, - b => buildAction(new RelationalModelBuilderTest.GenericTestTableBuilder(b))); + b => buildAction(new RelationalModelBuilderTest.GenericTestOwnedNavigationTableBuilder(b))); break; case IInfrastructure nongenericBuilder: nongenericBuilder.Instance.ToTable(name, - b => buildAction(new RelationalModelBuilderTest.NonGenericTestTableBuilder(b))); + b => buildAction(new RelationalModelBuilderTest.NonGenericTestOwnedNavigationTableBuilder(b))); break; } @@ -258,7 +258,7 @@ public static ModelBuilderTest.TestOwnedNavigationBuilder builder, string name, string? schema, - Action> buildAction) + Action> buildAction) where TOwnerEntity : class where TRelatedEntity : class { @@ -266,11 +266,11 @@ public static ModelBuilderTest.TestOwnedNavigationBuilder> genericBuilder: genericBuilder.Instance.ToTable(name, schema, - b => buildAction(new RelationalModelBuilderTest.GenericTestTableBuilder(b))); + b => buildAction(new RelationalModelBuilderTest.GenericTestOwnedNavigationTableBuilder(b))); break; case IInfrastructure nongenericBuilder: nongenericBuilder.Instance.ToTable(name, schema, - b => buildAction(new RelationalModelBuilderTest.NonGenericTestTableBuilder(b))); + b => buildAction(new RelationalModelBuilderTest.NonGenericTestOwnedNavigationTableBuilder(b))); break; } diff --git a/test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs b/test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs index 84162ce1f53..906661fe9ed 100644 --- a/test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs +++ b/test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs @@ -212,13 +212,13 @@ public override new Type[] { typeof(EntityTypeBuilder), typeof(string), typeof(string), typeof(Action) }), typeof(RelationalEntityTypeBuilderExtensions).GetMethod( nameof(RelationalEntityTypeBuilderExtensions.ToTable), - new Type[] { typeof(OwnedNavigationBuilder), typeof(Action) }), + new Type[] { typeof(OwnedNavigationBuilder), typeof(Action) }), typeof(RelationalEntityTypeBuilderExtensions).GetMethod( nameof(RelationalEntityTypeBuilderExtensions.ToTable), - new Type[] { typeof(OwnedNavigationBuilder), typeof(string), typeof(Action) }), + new Type[] { typeof(OwnedNavigationBuilder), typeof(string), typeof(Action) }), typeof(RelationalEntityTypeBuilderExtensions).GetMethod( nameof(RelationalEntityTypeBuilderExtensions.ToTable), - new Type[] { typeof(OwnedNavigationBuilder), typeof(string), typeof(string), typeof(Action) }) + new Type[] { typeof(OwnedNavigationBuilder), typeof(string), typeof(string), typeof(Action) }) }; public override HashSet AsyncMethodExceptions { get; } = new() 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/TemporalOwnedQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalOwnedQuerySqlServerTest.cs new file mode 100644 index 00000000000..239e6cc01c3 --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalOwnedQuerySqlServerTest.cs @@ -0,0 +1,1738 @@ +// 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.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit.Abstractions; + +namespace Microsoft.EntityFrameworkCore.Query +{ + [SqlServerCondition(SqlServerCondition.SupportsTemporalTablesCascadeDelete)] + public class TemporalOwnedQuerySqlServerTest : OwnedQueryRelationalTestBase + { + public TemporalOwnedQuerySqlServerTest(TemporalOwnedQuerySqlServerFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + protected override bool CanExecuteQueryString + => true; + + protected override Expression RewriteServerQueryExpression(Expression serverQueryExpression) + { + var temporalEntityTypes = new List + { + typeof(OwnedPerson), + typeof(Branch), + typeof(LeafA), + typeof(LeafB), + typeof(Barton), + typeof(Star), + typeof(Planet), + typeof(Moon), + }; + + var rewriter = new TemporalPointInTimeQueryRewriter(Fixture.ChangesDate, temporalEntityTypes); + + return rewriter.Visit(serverQueryExpression); + } + + public override async Task Query_with_owned_entity_equality_operator(bool async) + { + await base.Query_with_owned_entity_equality_operator(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[Id], [t0].[ClientId], [t0].[Id], [t0].[OrderDate], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[OrderClientId], [t0].[OrderId], [t0].[Id0], [t0].[Detail], [t0].[PeriodEnd0], [t0].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +CROSS JOIN ( + SELECT [o0].[Id] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + WHERE [o0].[Discriminator] = N'LeafB' +) AS [t] +LEFT JOIN ( + SELECT [o1].[ClientId], [o1].[Id], [o1].[OrderDate], [o1].[PeriodEnd], [o1].[PeriodStart], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id] AS [Id0], [o2].[Detail], [o2].[PeriodEnd] AS [PeriodEnd0], [o2].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o2] ON ([o1].[ClientId] = [o2].[OrderClientId]) AND ([o1].[Id] = [o2].[OrderId]) +) AS [t0] ON [o].[Id] = [t0].[ClientId] +WHERE 0 = 1 +ORDER BY [o].[Id], [t].[Id], [t0].[ClientId], [t0].[Id], [t0].[OrderClientId], [t0].[OrderId]"); + } + + public override async Task Query_for_base_type_loads_all_owned_navs(bool async) + { + await base.Query_for_base_type_loads_all_owned_navs(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task No_ignored_include_warning_when_implicit_load(bool async) + { + await base.No_ignored_include_warning_when_implicit_load(async); + + AssertSql( + @"SELECT COUNT(*) +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o]"); + } + + public override async Task Query_for_branch_type_loads_all_owned_navs(bool async) + { + await base.Query_for_branch_type_loads_all_owned_navs(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE [o].[Discriminator] IN (N'Branch', N'LeafA') +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Query_for_branch_type_loads_all_owned_navs_tracking(bool async) + { + await base.Query_for_branch_type_loads_all_owned_navs_tracking(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE [o].[Discriminator] IN (N'Branch', N'LeafA') +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Query_for_leaf_type_loads_all_owned_navs(bool async) + { + await base.Query_for_leaf_type_loads_all_owned_navs(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE [o].[Discriminator] = N'LeafA' +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Query_when_subquery(bool async) + { + await base.Query_when_subquery(async); + + AssertSql( + @"@__p_0='5' + +SELECT [t0].[Id], [t0].[Discriminator], [t0].[Name], [t0].[PeriodEnd], [t0].[PeriodStart], [t1].[ClientId], [t1].[Id], [t1].[OrderDate], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[OrderClientId], [t1].[OrderId], [t1].[Id0], [t1].[Detail], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t0].[PersonAddress_AddressLine], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t0].[PersonAddress_PlaceType], [t0].[PersonAddress_ZipCode], [t0].[PersonAddress_Country_Name], [t0].[PersonAddress_Country_PlanetId], [t0].[BranchAddress_BranchName], [t0].[BranchAddress_PlaceType], [t0].[BranchAddress_Country_Name], [t0].[BranchAddress_Country_PlanetId], [t0].[LeafBAddress_LeafBType], [t0].[LeafBAddress_PlaceType], [t0].[LeafBAddress_Country_Name], [t0].[LeafBAddress_Country_PlanetId], [t0].[LeafAAddress_LeafType], [t0].[LeafAAddress_PlaceType], [t0].[LeafAAddress_Country_Name], [t0].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT TOP(@__p_0) [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t].[PersonAddress_AddressLine], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] + FROM ( + SELECT DISTINCT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ) AS [t] + ORDER BY [t].[Id] +) AS [t0] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t1] ON [t0].[Id] = [t1].[ClientId] +ORDER BY [t0].[Id], [t1].[ClientId], [t1].[Id], [t1].[OrderClientId], [t1].[OrderId]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_projecting_scalar(bool async) + { + await base.Navigation_rewrite_on_owned_reference_projecting_scalar(async); + + AssertSql( + @"SELECT [o].[PersonAddress_Country_Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE [o].[PersonAddress_Country_Name] = N'USA'"); + } + + public override async Task Navigation_rewrite_on_owned_reference_projecting_entity(bool async) + { + await base.Navigation_rewrite_on_owned_reference_projecting_entity(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE [o].[PersonAddress_Country_Name] = N'USA' +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Navigation_rewrite_on_owned_collection(bool async) + { + await base.Navigation_rewrite_on_owned_collection(async); + + AssertSql( + @"SELECT [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o1].[ClientId], [o1].[Id], [o1].[OrderDate], [o1].[PeriodEnd], [o1].[PeriodStart], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id] AS [Id0], [o2].[Detail], [o2].[PeriodEnd] AS [PeriodEnd0], [o2].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o2] ON ([o1].[ClientId] = [o2].[OrderClientId]) AND ([o1].[Id] = [o2].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE ( + SELECT COUNT(*) + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + WHERE [o].[Id] = [o0].[ClientId]) > 0 +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Navigation_rewrite_on_owned_collection_with_composition(bool async) + { + await base.Navigation_rewrite_on_owned_collection_with_composition(async); + + AssertSql( + @"SELECT COALESCE(( + SELECT TOP(1) CASE + WHEN [o0].[Id] <> 42 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) + END + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + WHERE [o].[Id] = [o0].[ClientId] + ORDER BY [o0].[Id]), CAST(0 AS bit)) +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +ORDER BY [o].[Id]"); + } + + public override async Task Navigation_rewrite_on_owned_collection_with_composition_complex(bool async) + { + await base.Navigation_rewrite_on_owned_collection_with_composition_complex(async); + + AssertSql( + @"SELECT ( + SELECT TOP(1) [o1].[PersonAddress_Country_Name] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON [o0].[ClientId] = [o1].[Id] + WHERE [o].[Id] = [o0].[ClientId] + ORDER BY [o0].[Id]) +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o]"); + } + + public override async Task SelectMany_on_owned_collection(bool async) + { + await base.SelectMany_on_owned_collection(async); + + AssertSql( + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o].[Id], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail], [o1].[PeriodEnd], [o1].[PeriodStart] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o1].[OrderClientId], [o1].[OrderId]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity(bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity(async); + + AssertSql( + @"SELECT [p].[Id], [p].[Name], [p].[PeriodEnd], [p].[PeriodStart], [p].[StarId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id]"); + } + + public override async Task Filter_owned_entity_chained_with_regular_entity_followed_by_projecting_owned_collection(bool async) + { + await base.Filter_owned_entity_chained_with_regular_entity_followed_by_projecting_owned_collection(async); + + AssertSql( + @"SELECT [o].[Id], [p].[Id], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE ([p].[Id] <> 42) OR ([p].[Id] IS NULL) +ORDER BY [o].[Id], [p].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + 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].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [p].[Name], [p].[PeriodEnd], [p].[PeriodStart], [p].[StarId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +ORDER BY [o].[Id], [p].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Project_multiple_owned_navigations_with_expansion_on_owned_collections(bool async) + { + await base.Project_multiple_owned_navigations_with_expansion_on_owned_collections(async); + + AssertSql( + @"SELECT ( + SELECT COUNT(*) + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON [o0].[ClientId] = [o1].[Id] + LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p0] ON [o1].[PersonAddress_Country_PlanetId] = [p0].[Id] + LEFT JOIN [Star] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' 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].[Name], [p].[PeriodEnd], [p].[PeriodStart], [p].[StarId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +ORDER BY [o].[Id]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_filter(bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_filter(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [p].[Id], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE ([p].[Id] <> 7) OR ([p].[Id] IS NULL) +ORDER BY [o].[Id], [p].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_property(bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_property(async); + + AssertSql( + @"SELECT [p].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection(bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection(async); + + AssertSql( + @"SELECT [o].[Id], [p].[Id], [m].[Id], [m].[Diameter], [m].[PeriodEnd], [m].[PeriodStart], [m].[PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN [Moon] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [m] ON [p].[Id] = [m].[PlanetId] +ORDER BY [o].[Id], [p].[Id]"); + } + + public override async Task SelectMany_on_owned_reference_followed_by_regular_entity_and_collection(bool async) + { + await base.SelectMany_on_owned_reference_followed_by_regular_entity_and_collection(async); + + AssertSql( + @"SELECT [m].[Id], [m].[Diameter], [m].[PeriodEnd], [m].[PeriodStart], [m].[PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +INNER JOIN [Moon] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [m] ON [p].[Id] = [m].[PlanetId]"); + } + + public override async Task SelectMany_on_owned_reference_with_entity_in_between_ending_in_owned_collection(bool async) + { + await base.SelectMany_on_owned_reference_with_entity_in_between_ending_in_owned_collection(async); + + AssertSql( + @"SELECT [e].[Id], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [e].[StarId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN [Star] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] ON [p].[StarId] = [s].[Id] +INNER JOIN [Element] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e] ON [s].[Id] = [e].[StarId]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference(bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference(async); + + AssertSql( + @"SELECT [s].[Id], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart], [o].[Id], [p].[Id], [e].[Id], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [e].[StarId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN [Star] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] ON [p].[StarId] = [s].[Id] +LEFT JOIN [Element] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e] ON [s].[Id] = [e].[StarId] +ORDER BY [o].[Id], [p].[Id], [s].[Id]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_and_scalar( + bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_and_scalar(async); + + AssertSql( + @"SELECT [s].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN [Star] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] ON [p].[StarId] = [s].[Id]"); + } + + public override async Task + Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_in_predicate_and_projection(bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_another_reference_in_predicate_and_projection( + async); + + AssertSql( + @"SELECT [s].[Id], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart], [o].[Id], [p].[Id], [e].[Id], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [e].[StarId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN [Star] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] ON [p].[StarId] = [s].[Id] +LEFT JOIN [Element] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e] ON [s].[Id] = [e].[StarId] +WHERE [s].[Name] = N'Sol' +ORDER BY [o].[Id], [p].[Id], [s].[Id]"); + } + + public override async Task Query_with_OfType_eagerly_loads_correct_owned_navigations(bool async) + { + await base.Query_with_OfType_eagerly_loads_correct_owned_navigations(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE [o].[Discriminator] = N'LeafA' +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Unmapped_property_projection_loads_owned_navigations(bool async) + { + await base.Unmapped_property_projection_loads_owned_navigations(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE [o].[Id] = 1 +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Client_method_skip_loads_owned_navigations(bool async) + { + await base.Client_method_skip_loads_owned_navigations(async); + + AssertSql( + @"@__p_0='1' + +SELECT [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[ClientId], [t0].[Id], [t0].[OrderDate], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[OrderClientId], [t0].[OrderId], [t0].[Id0], [t0].[Detail], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t].[PersonAddress_AddressLine], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ORDER BY [o].[Id] + OFFSET @__p_0 ROWS +) AS [t] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t0] ON [t].[Id] = [t0].[ClientId] +ORDER BY [t].[Id], [t0].[ClientId], [t0].[Id], [t0].[OrderClientId], [t0].[OrderId]"); + } + + public override async Task Client_method_take_loads_owned_navigations(bool async) + { + await base.Client_method_take_loads_owned_navigations(async); + + AssertSql( + @"@__p_0='2' + +SELECT [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[ClientId], [t0].[Id], [t0].[OrderDate], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[OrderClientId], [t0].[OrderId], [t0].[Id0], [t0].[Detail], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t].[PersonAddress_AddressLine], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT TOP(@__p_0) [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ORDER BY [o].[Id] +) AS [t] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t0] ON [t].[Id] = [t0].[ClientId] +ORDER BY [t].[Id], [t0].[ClientId], [t0].[Id], [t0].[OrderClientId], [t0].[OrderId]"); + } + + public override async Task Client_method_skip_take_loads_owned_navigations(bool async) + { + await base.Client_method_skip_take_loads_owned_navigations(async); + + AssertSql( + @"@__p_0='1' +@__p_1='2' + +SELECT [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[ClientId], [t0].[Id], [t0].[OrderDate], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[OrderClientId], [t0].[OrderId], [t0].[Id0], [t0].[Detail], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t].[PersonAddress_AddressLine], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ORDER BY [o].[Id] + OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY +) AS [t] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t0] ON [t].[Id] = [t0].[ClientId] +ORDER BY [t].[Id], [t0].[ClientId], [t0].[Id], [t0].[OrderClientId], [t0].[OrderId]"); + } + + public override async Task Client_method_skip_loads_owned_navigations_variation_2(bool async) + { + await base.Client_method_skip_loads_owned_navigations_variation_2(async); + + AssertSql( + @"@__p_0='1' + +SELECT [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[ClientId], [t0].[Id], [t0].[OrderDate], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[OrderClientId], [t0].[OrderId], [t0].[Id0], [t0].[Detail], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t].[PersonAddress_AddressLine], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ORDER BY [o].[Id] + OFFSET @__p_0 ROWS +) AS [t] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t0] ON [t].[Id] = [t0].[ClientId] +ORDER BY [t].[Id], [t0].[ClientId], [t0].[Id], [t0].[OrderClientId], [t0].[OrderId]"); + } + + public override async Task Client_method_take_loads_owned_navigations_variation_2(bool async) + { + await base.Client_method_take_loads_owned_navigations_variation_2(async); + + AssertSql( + @"@__p_0='2' + +SELECT [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[ClientId], [t0].[Id], [t0].[OrderDate], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[OrderClientId], [t0].[OrderId], [t0].[Id0], [t0].[Detail], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t].[PersonAddress_AddressLine], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT TOP(@__p_0) [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ORDER BY [o].[Id] +) AS [t] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t0] ON [t].[Id] = [t0].[ClientId] +ORDER BY [t].[Id], [t0].[ClientId], [t0].[Id], [t0].[OrderClientId], [t0].[OrderId]"); + } + + public override async Task Client_method_skip_take_loads_owned_navigations_variation_2(bool async) + { + await base.Client_method_skip_take_loads_owned_navigations_variation_2(async); + + AssertSql( + @"@__p_0='1' +@__p_1='2' + +SELECT [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t0].[ClientId], [t0].[Id], [t0].[OrderDate], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[OrderClientId], [t0].[OrderId], [t0].[Id0], [t0].[Detail], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t].[PersonAddress_AddressLine], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ORDER BY [o].[Id] + OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY +) AS [t] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t0] ON [t].[Id] = [t0].[ClientId] +ORDER BY [t].[Id], [t0].[ClientId], [t0].[Id], [t0].[OrderClientId], [t0].[OrderId]"); + } + + public override async Task Where_owned_collection_navigation_ToList_Count(bool async) + { + await base.Where_owned_collection_navigation_ToList_Count(async); + + AssertSql( + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail], [o2].[PeriodEnd], [o2].[PeriodStart] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o2] ON ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId]) +WHERE ( + SELECT COUNT(*) + FROM [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId]"); + } + + public override async Task Where_collection_navigation_ToArray_Count(bool async) + { + await base.Where_collection_navigation_ToArray_Count(async); + + AssertSql( + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail], [o2].[PeriodEnd], [o2].[PeriodStart] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o2] ON ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId]) +WHERE ( + SELECT COUNT(*) + FROM [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId]"); + } + + public override async Task Where_collection_navigation_AsEnumerable_Count(bool async) + { + await base.Where_collection_navigation_AsEnumerable_Count(async); + + AssertSql( + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail], [o2].[PeriodEnd], [o2].[PeriodStart] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o2] ON ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId]) +WHERE ( + SELECT COUNT(*) + FROM [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId]"); + } + + public override async Task Where_collection_navigation_ToList_Count_member(bool async) + { + await base.Where_collection_navigation_ToList_Count_member(async); + + AssertSql( + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail], [o2].[PeriodEnd], [o2].[PeriodStart] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o2] ON ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId]) +WHERE ( + SELECT COUNT(*) + FROM [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId]"); + } + + public override async Task Where_collection_navigation_ToArray_Length_member(bool async) + { + await base.Where_collection_navigation_ToArray_Length_member(async); + + AssertSql( + @"SELECT [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId], [o2].[Id], [o2].[Detail], [o2].[PeriodEnd], [o2].[PeriodStart] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o2] ON ([o0].[ClientId] = [o2].[OrderClientId]) AND ([o0].[Id] = [o2].[OrderId]) +WHERE ( + SELECT COUNT(*) + FROM [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] + WHERE ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId])) = 0 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id], [o2].[OrderClientId], [o2].[OrderId]"); + } + + public override async Task Can_query_on_indexer_properties(bool async) + { + await base.Can_query_on_indexer_properties(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE [o].[Name] = N'Mona Cy' +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Can_query_on_owned_indexer_properties(bool async) + { + await base.Can_query_on_owned_indexer_properties(async); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE [o].[PersonAddress_ZipCode] = 38654"); + } + + public override async Task Can_query_on_indexer_property_when_property_name_from_closure(bool async) + { + await base.Can_query_on_indexer_property_when_property_name_from_closure(async); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE [o].[Name] = N'Mona Cy'"); + } + + public override async Task Can_project_indexer_properties(bool async) + { + await base.Can_project_indexer_properties(async); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o]"); + } + + public override async Task Can_project_owned_indexer_properties(bool async) + { + await base.Can_project_owned_indexer_properties(async); + + AssertSql( + @"SELECT [o].[PersonAddress_AddressLine] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o]"); + } + + public override async Task Can_project_indexer_properties_converted(bool async) + { + await base.Can_project_indexer_properties_converted(async); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o]"); + } + + public override async Task Can_project_owned_indexer_properties_converted(bool async) + { + await base.Can_project_owned_indexer_properties_converted(async); + + AssertSql( + @"SELECT [o].[PersonAddress_AddressLine] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o]"); + } + + public override async Task Can_OrderBy_indexer_properties(bool async) + { + await base.Can_OrderBy_indexer_properties(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +ORDER BY [o].[Name], [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Can_OrderBy_indexer_properties_converted(bool async) + { + await base.Can_OrderBy_indexer_properties_converted(async); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +ORDER BY [o].[Name], [o].[Id]"); + } + + public override async Task Can_OrderBy_owned_indexer_properties(bool async) + { + await base.Can_OrderBy_owned_indexer_properties(async); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +ORDER BY [o].[PersonAddress_ZipCode], [o].[Id]"); + } + + public override async Task Can_OrderBy_owened_indexer_properties_converted(bool async) + { + await base.Can_OrderBy_owened_indexer_properties_converted(async); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +ORDER BY [o].[PersonAddress_ZipCode], [o].[Id]"); + } + + public override async Task Can_group_by_indexer_property(bool isAsync) + { + await base.Can_group_by_indexer_property(isAsync); + + AssertSql( + @"SELECT COUNT(*) +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +GROUP BY [o].[Name]"); + } + + public override async Task Can_group_by_converted_indexer_property(bool isAsync) + { + await base.Can_group_by_converted_indexer_property(isAsync); + + AssertSql( + @"SELECT COUNT(*) +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +GROUP BY [o].[Name]"); + } + + public override async Task Can_group_by_owned_indexer_property(bool isAsync) + { + await base.Can_group_by_owned_indexer_property(isAsync); + + AssertSql( + @"SELECT COUNT(*) +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +GROUP BY [o].[PersonAddress_ZipCode]"); + } + + public override async Task Can_group_by_converted_owned_indexer_property(bool isAsync) + { + await base.Can_group_by_converted_owned_indexer_property(isAsync); + + AssertSql( + @"SELECT COUNT(*) +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +GROUP BY [o].[PersonAddress_ZipCode]"); + } + + public override async Task Can_join_on_indexer_property_on_query(bool isAsync) + { + await base.Can_join_on_indexer_property_on_query(isAsync); + + AssertSql( + @"SELECT [o].[Id], [o0].[PersonAddress_Country_Name] AS [Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[PersonAddress_ZipCode] = [o0].[PersonAddress_ZipCode]"); + } + + public override async Task Projecting_indexer_property_ignores_include(bool isAsync) + { + await base.Projecting_indexer_property_ignores_include(isAsync); + + AssertSql( + @"SELECT [o].[PersonAddress_ZipCode] AS [Nation] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o]"); + } + + public override async Task Projecting_indexer_property_ignores_include_converted(bool isAsync) + { + await base.Projecting_indexer_property_ignores_include_converted(isAsync); + + AssertSql( + @"SELECT [o].[PersonAddress_ZipCode] AS [Nation] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o]"); + } + + public override async Task Indexer_property_is_pushdown_into_subquery(bool isAsync) + { + await base.Indexer_property_is_pushdown_into_subquery(isAsync); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE ( + SELECT TOP(1) [o0].[Name] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + WHERE [o0].[Id] = [o].[Id]) = N'Mona Cy'"); + } + + public override async Task Can_query_indexer_property_on_owned_collection(bool isAsync) + { + await base.Can_query_indexer_property_on_owned_collection(isAsync); + + AssertSql( + @"SELECT [o].[Name] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE ( + SELECT COUNT(*) + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + WHERE ([o].[Id] = [o0].[ClientId]) AND (DATEPART(year, [o0].[OrderDate]) = 2018)) = 1"); + } + + public override async Task Query_for_base_type_loads_all_owned_navs_split(bool async) + { + await base.Query_for_base_type_loads_all_owned_navs_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]", + // + @"SELECT [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail], [o1].[PeriodEnd], [o1].[PeriodStart], [o].[Id], [o0].[ClientId], [o0].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +INNER JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]"); + } + + public override async Task Query_for_branch_type_loads_all_owned_navs_split(bool async) + { + await base.Query_for_branch_type_loads_all_owned_navs_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE [o].[Discriminator] IN (N'Branch', N'LeafA') +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +WHERE [o].[Discriminator] IN (N'Branch', N'LeafA') +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]", + // + @"SELECT [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail], [o1].[PeriodEnd], [o1].[PeriodStart], [o].[Id], [o0].[ClientId], [o0].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +INNER JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +WHERE [o].[Discriminator] IN (N'Branch', N'LeafA') +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]"); + } + + public override async Task Query_when_subquery_split(bool async) + { + await base.Query_when_subquery_split(async); + + AssertSql( + @"@__p_0='5' + +SELECT TOP(@__p_0) [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd], [t].[PeriodStart], [t].[PersonAddress_AddressLine], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT DISTINCT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +) AS [t] +ORDER BY [t].[Id]", + // + @"@__p_0='5' + +SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [t0].[Id] +FROM ( + SELECT TOP(@__p_0) [t].[Id] + FROM ( + SELECT DISTINCT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ) AS [t] + ORDER BY [t].[Id] +) AS [t0] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [t0].[Id] = [o0].[ClientId] +ORDER BY [t0].[Id], [o0].[ClientId], [o0].[Id]", + // + @"@__p_0='5' + +SELECT [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail], [o1].[PeriodEnd], [o1].[PeriodStart], [t0].[Id], [o0].[ClientId], [o0].[Id] +FROM ( + SELECT TOP(@__p_0) [t].[Id] + FROM ( + SELECT DISTINCT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] + ) AS [t] + ORDER BY [t].[Id] +) AS [t0] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [t0].[Id] = [o0].[ClientId] +INNER JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +ORDER BY [t0].[Id], [o0].[ClientId], [o0].[Id]"); + } + + 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].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [p].[Name], [p].[PeriodEnd], [p].[PeriodStart], [p].[StarId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +ORDER BY [o].[Id], [p].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o].[Id], [p].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +ORDER BY [o].[Id], [p].[Id], [o0].[ClientId], [o0].[Id]", + // + @"SELECT [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail], [o1].[PeriodEnd], [o1].[PeriodStart], [o].[Id], [p].[Id], [o0].[ClientId], [o0].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +INNER JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +ORDER BY [o].[Id], [p].[Id], [o0].[ClientId], [o0].[Id]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection_split(bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection_split(async); + + AssertSql( + @"SELECT [o].[Id], [p].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +ORDER BY [o].[Id], [p].[Id]", + // + @"SELECT [m].[Id], [m].[Diameter], [m].[PeriodEnd], [m].[PeriodStart], [m].[PlanetId], [o].[Id], [p].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +INNER JOIN [Moon] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [m] ON [p].[Id] = [m].[PlanetId] +ORDER BY [o].[Id], [p].[Id]"); + } + + public override async Task Query_with_OfType_eagerly_loads_correct_owned_navigations_split(bool async) + { + await base.Query_with_OfType_eagerly_loads_correct_owned_navigations_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE [o].[Discriminator] = N'LeafA' +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +WHERE [o].[Discriminator] = N'LeafA' +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]", + // + @"SELECT [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail], [o1].[PeriodEnd], [o1].[PeriodStart], [o].[Id], [o0].[ClientId], [o0].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +INNER JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +WHERE [o].[Discriminator] = N'LeafA' +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]"); + } + + public override async Task Unmapped_property_projection_loads_owned_navigations_split(bool async) + { + await base.Unmapped_property_projection_loads_owned_navigations_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE [o].[Id] = 1 +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +WHERE [o].[Id] = 1 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]", + // + @"SELECT [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail], [o1].[PeriodEnd], [o1].[PeriodStart], [o].[Id], [o0].[ClientId], [o0].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +INNER JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +WHERE [o].[Id] = 1 +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]"); + } + + public override async Task Can_query_on_indexer_properties_split(bool async) + { + await base.Can_query_on_indexer_properties_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +WHERE [o].[Name] = N'Mona Cy' +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +WHERE [o].[Name] = N'Mona Cy' +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]", + // + @"SELECT [o1].[OrderClientId], [o1].[OrderId], [o1].[Id], [o1].[Detail], [o1].[PeriodEnd], [o1].[PeriodStart], [o].[Id], [o0].[ClientId], [o0].[Id] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +INNER JOIN [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] ON [o].[Id] = [o0].[ClientId] +INNER JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +WHERE [o].[Name] = N'Mona Cy' +ORDER BY [o].[Id], [o0].[ClientId], [o0].[Id]"); + } + + public override async Task GroupBy_with_multiple_aggregates_on_owned_navigation_properties(bool async) + { + await base.GroupBy_with_multiple_aggregates_on_owned_navigation_properties(async); + + AssertSql( + @"SELECT AVG(CAST([s].[Id] AS float)) AS [p1], COALESCE(SUM([s].[Id]), 0) AS [p2], MAX(CAST(LEN([s].[Name]) AS int)) AS [p3] +FROM ( + SELECT 1 AS [Key], [o].[PersonAddress_Country_PlanetId] + FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +) AS [t] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON [t].[PersonAddress_Country_PlanetId] = [p].[Id] +LEFT JOIN [Star] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] ON [p].[StarId] = [s].[Id] +GROUP BY [t].[Key]"); + } + + public override async Task Ordering_by_identifying_projection(bool async) + { + await base.Ordering_by_identifying_projection(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +ORDER BY [o].[PersonAddress_PlaceType], [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Using_from_sql_on_owner_generates_join_with_table_for_owned_shared_dependents(bool async) + { + await base.Using_from_sql_on_owner_generates_join_with_table_for_owned_shared_dependents(async); + + AssertSql( + @"SELECT [m].[Id], [m].[Discriminator], [m].[Name], [m].[PeriodEnd], [m].[PeriodStart], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t2].[Id], [t2].[Id0], [t4].[Id], [t4].[Id0], [t6].[ClientId], [t6].[Id], [t6].[OrderDate], [t6].[PeriodEnd], [t6].[PeriodStart], [t6].[OrderClientId], [t6].[OrderId], [t6].[Id0], [t6].[Detail], [t6].[PeriodEnd0], [t6].[PeriodStart0], [t].[PersonAddress_AddressLine], [t].[PeriodEnd], [t].[PeriodStart], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[Id1], [t].[PersonAddress_Country_Name], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[PersonAddress_Country_PlanetId], [t0].[BranchAddress_BranchName], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[BranchAddress_PlaceType], [t0].[Id1], [t0].[BranchAddress_Country_Name], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t0].[BranchAddress_Country_PlanetId], [t2].[LeafBAddress_LeafBType], [t2].[PeriodEnd], [t2].[PeriodStart], [t2].[LeafBAddress_PlaceType], [t2].[Id1], [t2].[LeafBAddress_Country_Name], [t2].[PeriodEnd0], [t2].[PeriodStart0], [t2].[LeafBAddress_Country_PlanetId], [t4].[LeafAAddress_LeafType], [t4].[PeriodEnd], [t4].[PeriodStart], [t4].[LeafAAddress_PlaceType], [t4].[Id1], [t4].[LeafAAddress_Country_Name], [t4].[PeriodEnd0], [t4].[PeriodStart0], [t4].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT * FROM ""OwnedPerson"" +) AS [m] +LEFT JOIN ( + SELECT [o].[Id], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o0].[Id] AS [Id0], [o].[Id] AS [Id1], [o].[PersonAddress_Country_Name], [o].[PeriodEnd] AS [PeriodEnd0], [o].[PeriodStart] AS [PeriodStart0], [o].[PersonAddress_Country_PlanetId] + FROM [OwnedPerson] AS [o] + INNER JOIN [OwnedPerson] AS [o0] ON [o].[Id] = [o0].[Id] + WHERE [o].[PersonAddress_ZipCode] IS NOT NULL +) AS [t] ON [m].[Id] = CASE + WHEN [t].[PersonAddress_ZipCode] IS NOT NULL THEN [t].[Id] +END +LEFT JOIN ( + SELECT [o1].[Id], [o1].[BranchAddress_BranchName], [o1].[PeriodEnd], [o1].[PeriodStart], [o1].[BranchAddress_PlaceType], [t1].[Id] AS [Id0], [o1].[Id] AS [Id1], [o1].[BranchAddress_Country_Name], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0], [o1].[BranchAddress_Country_PlanetId] + FROM [OwnedPerson] AS [o1] + INNER JOIN ( + SELECT [o2].[Id] + FROM [OwnedPerson] AS [o2] + WHERE [o2].[Discriminator] IN (N'Branch', N'LeafA') + ) AS [t1] ON [o1].[Id] = [t1].[Id] + WHERE [o1].[BranchAddress_BranchName] IS NOT NULL +) AS [t0] ON [m].[Id] = CASE + WHEN [t0].[BranchAddress_BranchName] IS NOT NULL THEN [t0].[Id] +END +LEFT JOIN ( + SELECT [o3].[Id], [o3].[LeafBAddress_LeafBType], [o3].[PeriodEnd], [o3].[PeriodStart], [o3].[LeafBAddress_PlaceType], [t3].[Id] AS [Id0], [o3].[Id] AS [Id1], [o3].[LeafBAddress_Country_Name], [o3].[PeriodEnd] AS [PeriodEnd0], [o3].[PeriodStart] AS [PeriodStart0], [o3].[LeafBAddress_Country_PlanetId] + FROM [OwnedPerson] AS [o3] + INNER JOIN ( + SELECT [o4].[Id] + FROM [OwnedPerson] AS [o4] + WHERE [o4].[Discriminator] = N'LeafB' + ) AS [t3] ON [o3].[Id] = [t3].[Id] + WHERE [o3].[LeafBAddress_LeafBType] IS NOT NULL +) AS [t2] ON [m].[Id] = CASE + WHEN [t2].[LeafBAddress_LeafBType] IS NOT NULL THEN [t2].[Id] +END +LEFT JOIN ( + SELECT [o5].[Id], [o5].[LeafAAddress_LeafType], [o5].[PeriodEnd], [o5].[PeriodStart], [o5].[LeafAAddress_PlaceType], [t5].[Id] AS [Id0], [o5].[Id] AS [Id1], [o5].[LeafAAddress_Country_Name], [o5].[PeriodEnd] AS [PeriodEnd0], [o5].[PeriodStart] AS [PeriodStart0], [o5].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] AS [o5] + INNER JOIN ( + SELECT [o6].[Id] + FROM [OwnedPerson] AS [o6] + WHERE [o6].[Discriminator] = N'LeafA' + ) AS [t5] ON [o5].[Id] = [t5].[Id] + WHERE [o5].[LeafAAddress_LeafType] IS NOT NULL +) AS [t4] ON [m].[Id] = CASE + WHEN [t4].[LeafAAddress_LeafType] IS NOT NULL THEN [t4].[Id] +END +LEFT JOIN ( + SELECT [o7].[ClientId], [o7].[Id], [o7].[OrderDate], [o7].[PeriodEnd], [o7].[PeriodStart], [o8].[OrderClientId], [o8].[OrderId], [o8].[Id] AS [Id0], [o8].[Detail], [o8].[PeriodEnd] AS [PeriodEnd0], [o8].[PeriodStart] AS [PeriodStart0] + FROM [Order] AS [o7] + LEFT JOIN [OrderDetail] AS [o8] ON ([o7].[ClientId] = [o8].[OrderClientId]) AND ([o7].[Id] = [o8].[OrderId]) +) AS [t6] ON [m].[Id] = [t6].[ClientId] +ORDER BY [m].[Id], [t].[Id], [t].[Id0], [t0].[Id], [t0].[Id0], [t2].[Id], [t2].[Id0], [t4].[Id], [t4].[Id0], [t6].[ClientId], [t6].[Id], [t6].[OrderClientId], [t6].[OrderId]"); + } + + public override async Task Projecting_collection_correlated_with_keyless_entity_after_navigation_works_using_parent_identifiers(bool async) + { + 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].[Name], [p].[PeriodEnd], [p].[PeriodStart], [p].[StarId] +FROM [Fink] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [f] +LEFT JOIN [Barton] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [b] ON [f].[BartonId] = [b].[Id] +LEFT JOIN [Planet] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [p] ON ([b].[Throned_Value] <> [p].[Id]) OR ([b].[Throned_Value] IS NULL) +ORDER BY [f].[Id], [b].[Id]"); + } + + public override async Task Filter_on_indexer_using_closure(bool async) + { + await base.Filter_on_indexer_using_closure(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PeriodEnd], [o].[PeriodStart], [t].[ClientId], [t].[Id], [t].[OrderDate], [t].[PeriodEnd], [t].[PeriodStart], [t].[OrderClientId], [t].[OrderId], [t].[Id0], [t].[Detail], [t].[PeriodEnd0], [t].[PeriodStart0], [o].[PersonAddress_AddressLine], [o].[PeriodEnd], [o].[PeriodStart], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o] +LEFT JOIN ( + SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o0].[PeriodEnd], [o0].[PeriodStart], [o1].[OrderClientId], [o1].[OrderId], [o1].[Id] AS [Id0], [o1].[Detail], [o1].[PeriodEnd] AS [PeriodEnd0], [o1].[PeriodStart] AS [PeriodStart0] + FROM [Order] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o0] + LEFT JOIN [OrderDetail] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [o1] ON ([o0].[ClientId] = [o1].[OrderClientId]) AND ([o0].[Id] = [o1].[OrderId]) +) AS [t] ON [o].[Id] = [t].[ClientId] +WHERE [o].[PersonAddress_ZipCode] = 38654 +ORDER BY [o].[Id], [t].[ClientId], [t].[Id], [t].[OrderClientId], [t].[OrderId]"); + } + + public override async Task Query_loads_reference_nav_automatically_in_projection(bool async) + { + await base.Query_loads_reference_nav_automatically_in_projection(async); + + AssertSql( + @"SELECT TOP(2) [b].[Id], [b].[PeriodEnd], [b].[PeriodStart], [b].[Simple], [b].[Throned_Property], [b].[Throned_Value] +FROM [Fink] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [f] +LEFT JOIN [Barton] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [b] ON [f].[BartonId] = [b].[Id]"); + } + + public override async Task Simple_query_entity_with_owned_collection(bool async) + { + await base.Simple_query_entity_with_owned_collection(async); + + AssertSql( + @"SELECT [s].[Id], [s].[Name], [s].[PeriodEnd], [s].[PeriodStart], [e].[Id], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [e].[StarId] +FROM [Star] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [s] +LEFT JOIN [Element] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e] ON [s].[Id] = [e].[StarId] +ORDER BY [s].[Id]"); + } + + // not AssertQuery so original (non-temporal) query gets executed, but data is modified + // so results don't match expectations + public override Task Owned_entity_without_owner_does_not_throw_for_identity_resolution(bool async, bool useAsTracking) + => Task.CompletedTask; + + public override Task Preserve_includes_when_applying_skip_take_after_anonymous_type_select(bool async) + => Task.CompletedTask; + + public override Task Query_on_collection_entry_works_for_owned_collection(bool async) + => Task.CompletedTask; + + public override Task NoTracking_Include_with_cycles_does_not_throw_when_performing_identity_resolution( + bool async, + bool useAsTracking) + => Task.CompletedTask; + + public override Task Filter_on_indexer_using_function_argument(bool async) + => Task.CompletedTask; + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + public class TemporalOwnedQuerySqlServerFixture : RelationalOwnedQueryFixture + { + protected override ITestStoreFactory TestStoreFactory + => SqlServerTestStoreFactory.Instance; + + protected override string StoreName { get; } = "TemporalOwnedQueryTest"; + + public DateTime ChangesDate { get; private set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + modelBuilder.Entity( + eb => + { + eb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + eb.IndexerProperty("Name"); + var ownedPerson = new OwnedPerson { Id = 1 }; + ownedPerson["Name"] = "Mona Cy"; + eb.HasData(ownedPerson); + + eb.OwnsOne( + p => p.PersonAddress, ab => + { + ab.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + ab.IndexerProperty("AddressLine"); + ab.IndexerProperty(typeof(int), "ZipCode"); + ab.HasData( + new + { + OwnedPersonId = 1, + PlaceType = "Land", + AddressLine = "804 S. Lakeshore Road", + ZipCode = 38654 + }, + new + { + OwnedPersonId = 2, + PlaceType = "Land", + AddressLine = "7 Church Dr.", + ZipCode = 28655 + }, + new + { + OwnedPersonId = 3, + PlaceType = "Land", + AddressLine = "72 Hickory Rd.", + ZipCode = 07728 + }, + new + { + OwnedPersonId = 4, + PlaceType = "Land", + AddressLine = "28 Strawberry St.", + ZipCode = 19053 + }); + + ab.OwnsOne( + a => a.Country, cb => + { + cb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + cb.HasData( + new + { + OwnedAddressOwnedPersonId = 1, + PlanetId = 1, + Name = "USA" + }, + new + { + OwnedAddressOwnedPersonId = 2, + PlanetId = 1, + Name = "USA" + }, + new + { + OwnedAddressOwnedPersonId = 3, + PlanetId = 1, + Name = "USA" + }, + new + { + OwnedAddressOwnedPersonId = 4, + PlanetId = 1, + Name = "USA" + }); + + cb.HasOne(cc => cc.Planet).WithMany().HasForeignKey(ee => ee.PlanetId) + .OnDelete(DeleteBehavior.Restrict); + }); + }); + + eb.OwnsMany( + p => p.Orders, ob => + { + ob.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + ob.IndexerProperty("OrderDate"); + ob.HasData( + new + { + Id = -10, + ClientId = 1, + OrderDate = Convert.ToDateTime("2018-07-11 10:01:41") + }, + new + { + Id = -11, + ClientId = 1, + OrderDate = Convert.ToDateTime("2015-03-03 04:37:59") + }, + new + { + Id = -20, + ClientId = 2, + OrderDate = Convert.ToDateTime("2015-05-25 20:35:48") + }, + new + { + Id = -30, + ClientId = 3, + OrderDate = Convert.ToDateTime("2014-11-10 04:32:42") + }, + new + { + Id = -40, + ClientId = 4, + OrderDate = Convert.ToDateTime("2016-04-25 19:23:56") + } + ); + + ob.OwnsMany(e => e.Details, odb => + { + odb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + odb.HasData( + new + { + Id = -100, + OrderId = -10, + OrderClientId = 1, + Detail = "Discounted Order" + }, + new + { + Id = -101, + OrderId = -10, + OrderClientId = 1, + Detail = "Full Price Order" + }, + new + { + Id = -200, + OrderId = -20, + OrderClientId = 2, + Detail = "Internal Order" + }, + new + { + Id = -300, + OrderId = -30, + OrderClientId = 3, + Detail = "Bulk Order" + }); + }); + }); + }); + + modelBuilder.Entity( + eb => + { + eb.HasData(new { Id = 2, Name = "Antigonus Mitul" }); + + eb.OwnsOne( + p => p.BranchAddress, ab => + { + ab.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + ab.IndexerProperty("BranchName").IsRequired(); + ab.HasData( + new + { + BranchId = 2, + PlaceType = "Land", + BranchName = "BranchA" + }, + new + { + BranchId = 3, + PlaceType = "Land", + BranchName = "BranchB" + }); + + ab.OwnsOne( + a => a.Country, cb => + { + cb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + cb.HasData( + new + { + OwnedAddressBranchId = 2, + PlanetId = 1, + Name = "Canada" + }, + new + { + OwnedAddressBranchId = 3, + PlanetId = 1, + Name = "Canada" + }); + }); + }); + }); + + modelBuilder.Entity( + eb => + { + var leafA = new LeafA { Id = 3 }; + leafA["Name"] = "Madalena Morana"; + eb.HasData(leafA); + + eb.OwnsOne( + p => p.LeafAAddress, ab => + { + ab.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + ab.IndexerProperty("LeafType"); + + ab.HasData( + new + { + LeafAId = 3, + PlaceType = "Land", + LeafType = 1 + }); + + ab.OwnsOne( + a => a.Country, cb => + { + cb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + cb.HasOne(c => c.Planet).WithMany().HasForeignKey(c => c.PlanetId) + .OnDelete(DeleteBehavior.Restrict); + + cb.HasData( + new + { + OwnedAddressLeafAId = 3, + PlanetId = 1, + Name = "Mexico" + }); + }); + }); + }); + + modelBuilder.Entity( + eb => + { + var leafB = new LeafB { Id = 4 }; + leafB["Name"] = "Vanda Waldemar"; + eb.HasData(leafB); + + eb.OwnsOne( + p => p.LeafBAddress, ab => + { + ab.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + ab.IndexerProperty("LeafBType").IsRequired(); + ab.HasData( + new + { + LeafBId = 4, + PlaceType = "Land", + LeafBType = "Green" + }); + + ab.OwnsOne( + a => a.Country, cb => + { + cb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + cb.HasOne(c => c.Planet).WithMany().HasForeignKey(c => c.PlanetId) + .OnDelete(DeleteBehavior.Restrict); + + cb.HasData( + new + { + OwnedAddressLeafBId = 4, + PlanetId = 1, + Name = "Panama" + }); + }); + }); + }); + + modelBuilder.Entity(pb => + { + pb.ToTable(tb => tb.IsTemporal()); + pb.HasData(new Planet { Id = 1, StarId = 1, Name = "Earth" }); + }); + + modelBuilder.Entity(mb => + { + mb.ToTable(tb => tb.IsTemporal()); + mb.HasData( + new Moon + { + Id = 1, + PlanetId = 1, + Diameter = 3474 + }); + }); + + modelBuilder.Entity( + sb => + { + sb.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + sb.HasData(new Star { Id = 1, Name = "Sol" }); + sb.OwnsMany( + s => s.Composition, ob => + { + ob.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + ob.HasKey(e => e.Id); + ob.HasData( + new + { + Id = "H", + Name = "Hydrogen", + StarId = 1 + }, + new + { + Id = "He", + Name = "Helium", + StarId = 1 + }); + }); + }); + + modelBuilder.Entity( + b => + { + b.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + b.OwnsOne( + e => e.Throned, b => + { + b.ToTable(tb => tb.IsTemporal(ttb => + { + ttb.HasPeriodStart("PeriodStart").HasColumnName("PeriodStart"); + ttb.HasPeriodEnd("PeriodEnd").HasColumnName("PeriodEnd"); + })); + b.HasData( + new + { + BartonId = 1, + Property = "Property", + Value = 42 + }); + }); + b.HasData( + new Barton { Id = 1, Simple = "Simple" }, + new Barton { Id = 2, Simple = "Not" }); + }); + + modelBuilder.Entity() + .ToTable(tb => tb.IsTemporal()) + .HasData(new { Id = 1, BartonId = 1 }); + } + + protected override void Seed(PoolableDbContext context) + { + base.Seed(context); + + ChangesDate = new DateTime(2010, 1, 1); + + var ownedPeople = context.Set().AsTracking().ToList(); + foreach (var ownedPerson in ownedPeople) + { + ownedPerson["Name"] = "Modified" + ownedPerson["Name"]; + var orders = ownedPerson.Orders; + foreach (var order in orders) + { + order["OrderDate"] = new DateTime(1000, 1, 1); + var details = order.Details; + foreach (var detail in details) + { + detail.Detail = "Modified" + detail.Detail; + } + } + } + + var stars = context.Set().AsTracking().ToList(); + foreach (var star in stars) + { + star.Name = "Modified" + star.Name; + if (star.Composition.Any()) + { + foreach (var comp in star.Composition) + { + comp.Name = "Modified" + comp.Name; + } + } + } + + var planets = context.Set().AsTracking().ToList(); + foreach (var planet in planets) + { + planet.Name = "Modified" + planet.Name; + } + + var moons = context.Set().AsTracking().ToList(); + foreach (var moon in moons) + { + moon.Diameter += 1000; + } + + var finks = context.Set().AsTracking().ToList(); + context.Set().RemoveRange(finks); + + var bartons = context.Set().Include(x => x.Throned).AsTracking().ToList(); + foreach (var barton in bartons) + { + barton.Simple = "Modified" + barton.Simple; + if (barton.Throned != null) + { + barton.Throned.Property = "Modified" + barton.Throned.Property; + } + } + + context.SaveChanges(); + + var tableNames = new List + { + nameof(Barton), + nameof(Element), + nameof(Fink), + nameof(Moon), + nameof(Order), + nameof(OrderDetail), + nameof(OwnedPerson), + nameof(Planet), + nameof(Star), + }; + + foreach (var tableName in tableNames) + { + 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);