diff --git a/.editorconfig b/.editorconfig index a241d5f86..7915b52ff 100644 --- a/.editorconfig +++ b/.editorconfig @@ -232,14 +232,6 @@ dotnet_naming_rule.const_field_naming.symbols = const_field_symbol dotnet_naming_rule.const_field_naming.style = pascal_case_style dotnet_naming_rule.const_field_naming.severity = suggestion -# Private Fields -dotnet_naming_symbols.private_field_symbol.applicable_kinds = field -dotnet_naming_symbols.private_field_symbol.applicable_accessibilities = private - -dotnet_naming_rule.private_field_naming.symbols = private_field_symbol -dotnet_naming_rule.private_field_naming.style = _camelCase -dotnet_naming_rule.private_field_naming.severity = suggestion - # Parameters dotnet_naming_symbols.parameter_symbol.applicable_kinds = parameter dotnet_naming_symbols.parameter_symbol.applicable_accessibilities = * diff --git a/Dependencies.targets b/Dependencies.targets index 3191b6805..6a796c88f 100644 --- a/Dependencies.targets +++ b/Dependencies.targets @@ -1,9 +1,7 @@ - 6.0.2 - [$(DotnetRuntimeVersion), 7.0.0) - $(DotnetRuntimeVersion) - $(DotnetRuntimeVersion) + 7.* + 7.0.0 @@ -12,41 +10,40 @@ - + - - + + - + - + - - - - - - - - - - - + + + + + + + + + + + - - + + - - - - - + + + + + - - + \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index ff50c725d..0b71e81a6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -22,7 +22,10 @@ - net6.0 + net6.0;net7.0 + net7.0 + net6.0 + net7.0 diff --git a/Version.props b/Version.props index e03581613..b1397fd7c 100644 --- a/Version.props +++ b/Version.props @@ -4,7 +4,7 @@ Use the following values for the different release types: - "alpha" - EF Core release independent, code quality unstable, major changes - "beta" - EF Core release independent, code quality stable, can introduce breaking changes - - "silver" - EF Core release independent, code quality stable, can introduce breaking changes + - "silver" - EF Core release independent, code quality stable, only minor changes are expected - "preview" - EF Core release targeted, code quality stable, can introduce breaking changes - "rc" - EF Core release targeted, code quality production ready, only minor changes are expected @@ -12,8 +12,8 @@ - "rtm" - EF Core release independent, code quality production ready, major release - "servicing" - EF Core release independent, code quality production ready, mainly bugfixes --> - 6.0.2 - servicing + 7.0.0 + alpha 1 - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll diff --git a/src/EFCore.MySql.Json.Newtonsoft/EFCore.MySql.Json.Newtonsoft.csproj b/src/EFCore.MySql.Json.Newtonsoft/EFCore.MySql.Json.Newtonsoft.csproj index 9b91c6fc6..8b733b84d 100644 --- a/src/EFCore.MySql.Json.Newtonsoft/EFCore.MySql.Json.Newtonsoft.csproj +++ b/src/EFCore.MySql.Json.Newtonsoft/EFCore.MySql.Json.Newtonsoft.csproj @@ -2,7 +2,7 @@ JSON support using Newtonsoft.Json (JSON.NET) for Pomelo's MySQL provider for Entity Framework Core. - $(DefaultNetCoreTargetFramework) + $(PomeloTargetFrameworks) 3.6 Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft @@ -57,16 +57,16 @@ - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll diff --git a/src/EFCore.MySql.NTS/EFCore.MySql.NTS.csproj b/src/EFCore.MySql.NTS/EFCore.MySql.NTS.csproj index b772c5c0b..e9d596e1e 100644 --- a/src/EFCore.MySql.NTS/EFCore.MySql.NTS.csproj +++ b/src/EFCore.MySql.NTS/EFCore.MySql.NTS.csproj @@ -2,7 +2,7 @@ NetTopologySuite support for Pomelo's MySQL provider for Entity Framework Core. - $(DefaultNetCoreTargetFramework) + $(PomeloTargetFrameworks) 3.6 Pomelo.EntityFrameworkCore.MySql.NetTopologySuite Pomelo.EntityFrameworkCore.MySql @@ -57,16 +57,16 @@ - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll diff --git a/src/EFCore.MySql/EFCore.MySql.csproj b/src/EFCore.MySql/EFCore.MySql.csproj index 2624ed51b..f72e20e6c 100644 --- a/src/EFCore.MySql/EFCore.MySql.csproj +++ b/src/EFCore.MySql/EFCore.MySql.csproj @@ -2,7 +2,7 @@ Pomelo's MySQL database provider for Entity Framework Core. - $(DefaultNetCoreTargetFramework) + $(PomeloTargetFrameworks) 3.6 Pomelo.EntityFrameworkCore.MySql Pomelo.EntityFrameworkCore.MySql @@ -30,16 +30,16 @@ - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational\Debug\$(EfCoreTargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll @@ -60,7 +60,6 @@ - diff --git a/src/EFCore.MySql/Extensions/MySqlDbContextOptionsBuilderExtensions.cs b/src/EFCore.MySql/Extensions/MySqlDbContextOptionsBuilderExtensions.cs index e187baf1b..582345df0 100644 --- a/src/EFCore.MySql/Extensions/MySqlDbContextOptionsBuilderExtensions.cs +++ b/src/EFCore.MySql/Extensions/MySqlDbContextOptionsBuilderExtensions.cs @@ -91,27 +91,27 @@ public static DbContextOptionsBuilder UseMySql( /// The options builder so that further configuration can be chained. public static DbContextOptionsBuilder UseMySql( [NotNull] this DbContextOptionsBuilder optionsBuilder, - [NotNull] string connectionString, + [CanBeNull] string connectionString, [NotNull] ServerVersion serverVersion, [CanBeNull] Action mySqlOptionsAction = null) { Check.NotNull(optionsBuilder, nameof(optionsBuilder)); - Check.NotEmpty(connectionString, nameof(connectionString)); - - var resolvedConnectionString = new NamedConnectionStringResolver(optionsBuilder.Options) - .ResolveConnectionString(connectionString); + Check.NullButNotEmpty(connectionString, nameof(connectionString)); - var csb = new MySqlConnectionStringBuilder(resolvedConnectionString) + if (connectionString is not null) { - AllowUserVariables = true, - UseAffectedRows = false - }; + var resolvedConnectionString = new NamedConnectionStringResolver(optionsBuilder.Options) + .ResolveConnectionString(connectionString); - resolvedConnectionString = csb.ConnectionString; + // TODO: Move to MySqlRelationalConnection. + var csb = new MySqlConnectionStringBuilder(resolvedConnectionString) { AllowUserVariables = true, UseAffectedRows = false }; + + connectionString = csb.ConnectionString; + } var extension = (MySqlOptionsExtension)GetOrCreateExtension(optionsBuilder) .WithServerVersion(serverVersion) - .WithConnectionString(resolvedConnectionString); + .WithConnectionString(connectionString); ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); ConfigureWarnings(optionsBuilder); @@ -160,6 +160,7 @@ public static DbContextOptionsBuilder UseMySql( .ResolveConnectionString(connection.ConnectionString) : null; + // TODO: Move to MySqlRelationalConnection. var csb = new MySqlConnectionStringBuilder(resolvedConnectionString); if (!csb.AllowUserVariables || diff --git a/src/EFCore.MySql/Extensions/MySqlModelExtensions.cs b/src/EFCore.MySql/Extensions/MySqlModelExtensions.cs index d31fff6ab..cffb119dc 100644 --- a/src/EFCore.MySql/Extensions/MySqlModelExtensions.cs +++ b/src/EFCore.MySql/Extensions/MySqlModelExtensions.cs @@ -19,8 +19,18 @@ public static class MySqlModelExtensions /// /// The model. /// The default . - public static MySqlValueGenerationStrategy? GetValueGenerationStrategy([NotNull] this IModel model) - => (MySqlValueGenerationStrategy?)model[MySqlAnnotationNames.ValueGenerationStrategy]; + public static MySqlValueGenerationStrategy? GetValueGenerationStrategy([NotNull] this IReadOnlyModel model) + { + // Allow users to use the underlying type value instead of the enum itself. + // Workaround for: https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1205 + if (model[MySqlAnnotationNames.ValueGenerationStrategy] is { } annotation && + ObjectToEnumConverter.GetEnumValue(annotation) is { } enumValue) + { + return enumValue; + } + + return null; + } /// /// Attempts to set the to use for properties @@ -63,7 +73,7 @@ public static void SetValueGenerationStrategy([NotNull] this IMutableModel model /// /// The model. /// The default character set. - public static string GetCharSet([NotNull] this IModel model) + public static string GetCharSet([NotNull] this IReadOnlyModel model) => model[MySqlAnnotationNames.CharSet] as string; /// @@ -104,7 +114,7 @@ public static string SetCharSet([NotNull] this IConventionModel model, string ch /// /// The model. /// The character set delegation modes. - public static DelegationModes? GetCharSetDelegation([NotNull] this IModel model) + public static DelegationModes? GetCharSetDelegation([NotNull] this IReadOnlyModel model) => ObjectToEnumConverter.GetEnumValue(model[MySqlAnnotationNames.CharSetDelegation]) ?? (model[MySqlAnnotationNames.CharSetDelegation] is bool explicitlyDelegateToChildren ? explicitlyDelegateToChildren @@ -153,7 +163,7 @@ public static void SetCharSetDelegation([NotNull] this IMutableModel model, Dele /// /// The model. /// The actual character set delegation modes. - public static DelegationModes GetActualCharSetDelegation([NotNull] this IModel model) + public static DelegationModes GetActualCharSetDelegation([NotNull] this IReadOnlyModel model) { var delegationModes = model.GetCharSetDelegation() ?? DelegationModes.Default; return delegationModes == DelegationModes.Default @@ -170,7 +180,7 @@ public static DelegationModes GetActualCharSetDelegation([NotNull] this IModel m /// /// The model. /// The collation delegation modes. - public static DelegationModes? GetCollationDelegation([NotNull] this IModel model) + public static DelegationModes? GetCollationDelegation([NotNull] this IReadOnlyModel model) => ObjectToEnumConverter.GetEnumValue(model[MySqlAnnotationNames.CollationDelegation]) ?? (model[MySqlAnnotationNames.CollationDelegation] is bool explicitlyDelegateToChildren ? explicitlyDelegateToChildren @@ -219,7 +229,7 @@ public static void SetCollationDelegation([NotNull] this IMutableModel model, De /// /// The model. /// The actual collation delegation modes. - public static DelegationModes GetActualCollationDelegation([NotNull] this IModel model) + public static DelegationModes GetActualCollationDelegation([NotNull] this IReadOnlyModel model) { var delegationModes = model.GetCollationDelegation() ?? DelegationModes.Default; return delegationModes == DelegationModes.Default @@ -240,7 +250,7 @@ public static DelegationModes GetActualCollationDelegation([NotNull] this IModel /// An empty string means that no explicit collation will be applied, while means that the default /// collation `ascii_general_ci` will be applied. /// - public static string GetGuidCollation([NotNull] this IModel model) + public static string GetGuidCollation([NotNull] this IReadOnlyModel model) => model[MySqlAnnotationNames.GuidCollation] as string; /// @@ -288,7 +298,7 @@ public static string SetGuidCollation([NotNull] this IConventionModel model, str /// /// if no collation should be set, otherwise the concrete collation to apply. /// - public static string GetActualGuidCollation([NotNull] this IModel model, [CanBeNull] string defaultCollation) + public static string GetActualGuidCollation([NotNull] this IReadOnlyModel model, [CanBeNull] string defaultCollation) => model.GetGuidCollation() switch { null => defaultCollation, diff --git a/src/EFCore.MySql/Extensions/MySqlPropertyExtensions.cs b/src/EFCore.MySql/Extensions/MySqlPropertyExtensions.cs index c99d0f939..465a76332 100644 --- a/src/EFCore.MySql/Extensions/MySqlPropertyExtensions.cs +++ b/src/EFCore.MySql/Extensions/MySqlPropertyExtensions.cs @@ -2,10 +2,12 @@ // Licensed under the MIT. See LICENSE in the project root for license information. using System; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Pomelo.EntityFrameworkCore.MySql.Internal; using Pomelo.EntityFrameworkCore.MySql.Metadata.Internal; @@ -28,45 +30,168 @@ public static class MySqlPropertyExtensions /// /// /// The strategy, or if none was set. - public static MySqlValueGenerationStrategy? GetValueGenerationStrategy([NotNull] this IReadOnlyProperty property, StoreObjectIdentifier storeObject = default) + public static MySqlValueGenerationStrategy GetValueGenerationStrategy([NotNull] this IReadOnlyProperty property) { - var annotation = property[MySqlAnnotationNames.ValueGenerationStrategy]; - if (annotation != null) + // Allow users to use the underlying type value instead of the enum itself. + // Workaround for: https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1205 + if (property[MySqlAnnotationNames.ValueGenerationStrategy] is { } annotationValue && + ObjectToEnumConverter.GetEnumValue(annotationValue) is { } enumValue) { - // Allow users to use the underlying type value instead of the enum itself. - // Workaround for: https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1205 - //return ObjectToEnumConverter.GetEnumValue(annotation); - return ObjectToEnumConverter.GetEnumValue(annotation); + return enumValue; } - if (property.GetContainingForeignKeys().Any(fk => !fk.IsBaseLinking()) || - property.TryGetDefaultValue(storeObject, out _) || - property.GetDefaultValueSql() != null || - property.GetComputedColumnSql() != null) + if (property.ValueGenerated == ValueGenerated.OnAdd) { - return null; + if (property.IsForeignKey() + || property.TryGetDefaultValue(out _) + || property.GetDefaultValueSql() != null + || property.GetComputedColumnSql() != null) + { + return MySqlValueGenerationStrategy.None; + } + + if (IsCompatibleIdentityColumn(property)) + { + return MySqlValueGenerationStrategy.IdentityColumn; + } + + return GetDefaultValueGenerationStrategy(property); } - if (storeObject != default && - property.ValueGenerated == ValueGenerated.Never) + if (property.ValueGenerated == ValueGenerated.OnAddOrUpdate) { - return property.FindSharedStoreObjectRootProperty(storeObject) - ?.GetValueGenerationStrategy(storeObject); + if (IsCompatibleComputedColumn(property)) + { + return MySqlValueGenerationStrategy.ComputedColumn; + } } - if (property.ValueGenerated == ValueGenerated.OnAdd && - IsCompatibleIdentityColumn(property)) + return MySqlValueGenerationStrategy.None; + } + + public static MySqlValueGenerationStrategy GetValueGenerationStrategy( + this IReadOnlyProperty property, + in StoreObjectIdentifier storeObject) + => GetValueGenerationStrategy(property, storeObject, null); + + internal static MySqlValueGenerationStrategy GetValueGenerationStrategy( + this IReadOnlyProperty property, + in StoreObjectIdentifier storeObject, + [CanBeNull] ITypeMappingSource typeMappingSource) + { + if (property.FindOverrides(storeObject)?.FindAnnotation(MySqlAnnotationNames.ValueGenerationStrategy) is { } @override) { - return MySqlValueGenerationStrategy.IdentityColumn; + return ObjectToEnumConverter.GetEnumValue(@override.Value) ?? MySqlValueGenerationStrategy.None; } - if (property.ValueGenerated == ValueGenerated.OnAddOrUpdate && - IsCompatibleComputedColumn(property)) + var annotation = property.FindAnnotation(MySqlAnnotationNames.ValueGenerationStrategy); + if (annotation?.Value is { } annotationValue + && ObjectToEnumConverter.GetEnumValue(annotationValue) is { } enumValue + && StoreObjectIdentifier.Create(property.DeclaringEntityType, storeObject.StoreObjectType) == storeObject) { - return MySqlValueGenerationStrategy.ComputedColumn; + return enumValue; } - return null; + var table = storeObject; + var sharedTableRootProperty = property.FindSharedStoreObjectRootProperty(storeObject); + if (sharedTableRootProperty != null) + { + return sharedTableRootProperty.GetValueGenerationStrategy(storeObject, typeMappingSource) + == MySqlValueGenerationStrategy.IdentityColumn + && table.StoreObjectType == StoreObjectType.Table + && !property.GetContainingForeignKeys().Any( + fk => + !fk.IsBaseLinking() + || (StoreObjectIdentifier.Create(fk.PrincipalEntityType, StoreObjectType.Table) + is StoreObjectIdentifier principal + && fk.GetConstraintName(table, principal) != null)) + ? MySqlValueGenerationStrategy.IdentityColumn + : MySqlValueGenerationStrategy.None; + } + + if (property.ValueGenerated == ValueGenerated.OnAdd) + { + if (table.StoreObjectType != StoreObjectType.Table + || property.TryGetDefaultValue(storeObject, out _) + || property.GetDefaultValueSql(storeObject) != null + || property.GetComputedColumnSql(storeObject) != null + || property.GetContainingForeignKeys() + .Any( + fk => + !fk.IsBaseLinking() + || (StoreObjectIdentifier.Create(fk.PrincipalEntityType, StoreObjectType.Table) + is StoreObjectIdentifier principal + && fk.GetConstraintName(table, principal) != null))) + { + return MySqlValueGenerationStrategy.None; + } + + if (IsCompatibleIdentityColumn(property)) + { + return MySqlValueGenerationStrategy.IdentityColumn; + } + + var defaultStrategy = GetDefaultValueGenerationStrategy(property, storeObject, typeMappingSource); + if (defaultStrategy != MySqlValueGenerationStrategy.None) + { + if (annotation != null) + { + return (MySqlValueGenerationStrategy?)annotation.Value ?? MySqlValueGenerationStrategy.None; + } + } + + return defaultStrategy; + } + + if (property.ValueGenerated == ValueGenerated.OnAddOrUpdate) + { + if (IsCompatibleComputedColumn(property)) + { + return MySqlValueGenerationStrategy.ComputedColumn; + } + } + + return MySqlValueGenerationStrategy.None; + } + + /// + /// Returns the to use for the property. + /// + /// + /// If no strategy is set for the property, then the strategy to use will be taken from the . + /// + /// The property overrides. + /// The strategy, or if none was set. + public static MySqlValueGenerationStrategy? GetValueGenerationStrategy(this IReadOnlyRelationalPropertyOverrides overrides) + => overrides.FindAnnotation(MySqlAnnotationNames.ValueGenerationStrategy) is { } @override + ? ObjectToEnumConverter.GetEnumValue(@override.Value) ?? + MySqlValueGenerationStrategy.None + : null; + + private static MySqlValueGenerationStrategy GetDefaultValueGenerationStrategy(IReadOnlyProperty property) + { + var modelStrategy = property.DeclaringEntityType.Model.GetValueGenerationStrategy(); + + if (modelStrategy == MySqlValueGenerationStrategy.IdentityColumn && + IsCompatibleAutoIncrementColumn(property)) + { + return MySqlValueGenerationStrategy.IdentityColumn; + } + + return MySqlValueGenerationStrategy.None; + } + + private static MySqlValueGenerationStrategy GetDefaultValueGenerationStrategy( + IReadOnlyProperty property, + in StoreObjectIdentifier storeObject, + [CanBeNull] ITypeMappingSource typeMappingSource) + { + var modelStrategy = property.DeclaringEntityType.Model.GetValueGenerationStrategy(); + + return modelStrategy == MySqlValueGenerationStrategy.IdentityColumn + && IsCompatibleAutoIncrementColumn(property, storeObject, typeMappingSource) + ? MySqlValueGenerationStrategy.IdentityColumn + : MySqlValueGenerationStrategy.None; } /// @@ -75,12 +200,11 @@ public static class MySqlPropertyExtensions /// The property. /// The strategy to use. public static void SetValueGenerationStrategy( - [NotNull] this IMutableProperty property, MySqlValueGenerationStrategy? value) - { - CheckValueGenerationStrategy(property, value); - - property.SetOrRemoveAnnotation(MySqlAnnotationNames.ValueGenerationStrategy, value); - } + [NotNull] this IMutableProperty property, + MySqlValueGenerationStrategy? value) + => property.SetOrRemoveAnnotation( + MySqlAnnotationNames.ValueGenerationStrategy, + CheckValueGenerationStrategy(property, value)); /// /// Sets the to use for the property. @@ -88,45 +212,128 @@ public static void SetValueGenerationStrategy( /// The property. /// The strategy to use. /// Indicates whether the configuration was specified using a data annotation. - public static MySqlValueGenerationStrategy? SetValueGenerationStrategy([NotNull] this IConventionProperty property, MySqlValueGenerationStrategy? value, bool fromDataAnnotation = false) - { - CheckValueGenerationStrategy(property, value); + public static MySqlValueGenerationStrategy? SetValueGenerationStrategy( + [NotNull] this IConventionProperty property, + MySqlValueGenerationStrategy? value, + bool fromDataAnnotation = false) + => (MySqlValueGenerationStrategy?)property.SetOrRemoveAnnotation( + MySqlAnnotationNames.ValueGenerationStrategy, + CheckValueGenerationStrategy(property, value), + fromDataAnnotation) + ?.Value; - property.SetOrRemoveAnnotation(MySqlAnnotationNames.ValueGenerationStrategy, value, fromDataAnnotation); + /// + /// Sets the to use for the property for a particular table. + /// + /// The property. + /// The strategy to use. + /// The identifier of the table containing the column. + public static void SetValueGenerationStrategy( + this IMutableProperty property, + MySqlValueGenerationStrategy? value, + in StoreObjectIdentifier storeObject) + => property.GetOrCreateOverrides(storeObject) + .SetValueGenerationStrategy(value); - return value; - } + /// + /// Sets the to use for the property for a particular table. + /// + /// The property. + /// The strategy to use. + /// The identifier of the table containing the column. + /// Indicates whether the configuration was specified using a data annotation. + /// The configured value. + public static MySqlValueGenerationStrategy? SetValueGenerationStrategy( + this IConventionProperty property, + MySqlValueGenerationStrategy? value, + in StoreObjectIdentifier storeObject, + bool fromDataAnnotation = false) + => property.GetOrCreateOverrides(storeObject, fromDataAnnotation) + .SetValueGenerationStrategy(value, fromDataAnnotation); /// - /// Returns the for the . + /// Sets the to use for the property for a particular table. + /// + /// The property overrides. + /// The strategy to use. + public static void SetValueGenerationStrategy( + this IMutableRelationalPropertyOverrides overrides, + MySqlValueGenerationStrategy? value) + => overrides.SetOrRemoveAnnotation( + MySqlAnnotationNames.ValueGenerationStrategy, + CheckValueGenerationStrategy(overrides.Property, value)); + + /// + /// Sets the to use for the property for a particular table. + /// + /// The property overrides. + /// The strategy to use. + /// Indicates whether the configuration was specified using a data annotation. + /// The configured value. + public static MySqlValueGenerationStrategy? SetValueGenerationStrategy( + this IConventionRelationalPropertyOverrides overrides, + MySqlValueGenerationStrategy? value, + bool fromDataAnnotation = false) + => (MySqlValueGenerationStrategy?)overrides.SetOrRemoveAnnotation( + MySqlAnnotationNames.ValueGenerationStrategy, + CheckValueGenerationStrategy(overrides.Property, value), + fromDataAnnotation)?.Value; + + /// + /// Returns the for the . /// /// The property. /// The for the . - public static ConfigurationSource? GetValueGenerationStrategyConfigurationSource(this IConventionProperty property) + public static ConfigurationSource? GetValueGenerationStrategyConfigurationSource( + this IConventionProperty property) => property.FindAnnotation(MySqlAnnotationNames.ValueGenerationStrategy)?.GetConfigurationSource(); - private static void CheckValueGenerationStrategy(IReadOnlyProperty property, MySqlValueGenerationStrategy? value) + /// + /// Returns the for the for a particular table. + /// + /// The property. + /// The identifier of the table containing the column. + /// The for the . + public static ConfigurationSource? GetValueGenerationStrategyConfigurationSource( + this IConventionProperty property, + in StoreObjectIdentifier storeObject) + => property.FindOverrides(storeObject)?.GetValueGenerationStrategyConfigurationSource(); + + /// + /// Returns the for the for a particular table. + /// + /// The property overrides. + /// The for the . + public static ConfigurationSource? GetValueGenerationStrategyConfigurationSource( + this IConventionRelationalPropertyOverrides overrides) + => overrides.FindAnnotation(MySqlAnnotationNames.ValueGenerationStrategy)?.GetConfigurationSource(); + + private static MySqlValueGenerationStrategy? CheckValueGenerationStrategy(IReadOnlyProperty property, MySqlValueGenerationStrategy? value) { - if (value != null) + if (value == null) { - var propertyType = property.ClrType; + return null; + } - if (value == MySqlValueGenerationStrategy.IdentityColumn - && !IsCompatibleIdentityColumn(property)) - { - throw new ArgumentException( - MySqlStrings.IdentityBadType( - property.Name, property.DeclaringEntityType.DisplayName(), propertyType.ShortDisplayName())); - } + var propertyType = property.ClrType; - if (value == MySqlValueGenerationStrategy.ComputedColumn - && !IsCompatibleComputedColumn(property)) - { - throw new ArgumentException( - MySqlStrings.ComputedBadType( - property.Name, property.DeclaringEntityType.DisplayName(), propertyType.ShortDisplayName())); - } + if (value == MySqlValueGenerationStrategy.IdentityColumn + && !IsCompatibleIdentityColumn(property)) + { + throw new ArgumentException( + MySqlStrings.IdentityBadType( + property.Name, property.DeclaringEntityType.DisplayName(), propertyType.ShortDisplayName())); + } + + if (value == MySqlValueGenerationStrategy.ComputedColumn + && !IsCompatibleComputedColumn(property)) + { + throw new ArgumentException( + MySqlStrings.ComputedBadType( + property.Name, property.DeclaringEntityType.DisplayName(), propertyType.ShortDisplayName())); } + + return value; } /// @@ -138,6 +345,13 @@ public static bool IsCompatibleIdentityColumn(IReadOnlyProperty property) => IsCompatibleAutoIncrementColumn(property) || IsCompatibleCurrentTimestampColumn(property); + private static bool IsCompatibleIdentityColumn( + IReadOnlyProperty property, + in StoreObjectIdentifier storeObject, + [CanBeNull] ITypeMappingSource typeMappingSource) + => IsCompatibleAutoIncrementColumn(property, storeObject, typeMappingSource) || + IsCompatibleCurrentTimestampColumn(property, storeObject, typeMappingSource); + /// /// Returns a value indicating whether the property is compatible with an `AUTO_INCREMENT` column. /// @@ -151,6 +365,23 @@ public static bool IsCompatibleAutoIncrementColumn(IReadOnlyProperty property) type == typeof(decimal); } + private static bool IsCompatibleAutoIncrementColumn( + IReadOnlyProperty property, + in StoreObjectIdentifier storeObject, + [CanBeNull] ITypeMappingSource typeMappingSource) + { + if (storeObject.StoreObjectType != StoreObjectType.Table) + { + return false; + } + + var valueConverter = GetConverter(property, storeObject, typeMappingSource); + var type = (valueConverter?.ProviderClrType ?? property.ClrType).UnwrapNullableType(); + + return (type.IsInteger() + || type == typeof(decimal)); + } + /// /// Returns a value indicating whether the property is compatible with a `CURRENT_TIMESTAMP` column default. /// @@ -164,6 +395,23 @@ public static bool IsCompatibleCurrentTimestampColumn(IReadOnlyProperty property type == typeof(DateTimeOffset); } + private static bool IsCompatibleCurrentTimestampColumn( + IReadOnlyProperty property, + in StoreObjectIdentifier storeObject, + [CanBeNull] ITypeMappingSource typeMappingSource) + { + if (storeObject.StoreObjectType != StoreObjectType.Table) + { + return false; + } + + var valueConverter = GetConverter(property, storeObject, typeMappingSource); + var type = (valueConverter?.ProviderClrType ?? property.ClrType).UnwrapNullableType(); + + return type == typeof(DateTime) || + type == typeof(DateTimeOffset); + } + /// /// Returns a value indicating whether the property is compatible with . /// @@ -188,7 +436,16 @@ private static bool HasExternalConverter(IReadOnlyProperty property) } private static ValueConverter GetConverter(IReadOnlyProperty property) - => property.FindTypeMapping()?.Converter ?? property.GetValueConverter(); + => property.GetValueConverter() ?? + property.FindTypeMapping()?.Converter; + + private static ValueConverter GetConverter( + IReadOnlyProperty property, + StoreObjectIdentifier storeObject, + [CanBeNull] ITypeMappingSource typeMappingSource) + => property.GetValueConverter() + ?? (property.FindRelationalTypeMapping(storeObject) + ?? typeMappingSource?.FindMapping((IProperty)property))?.Converter; /// /// Returns the name of the charset used by the column of the property. diff --git a/src/EFCore.MySql/Extensions/MySqlServiceCollectionExtensions.cs b/src/EFCore.MySql/Extensions/MySqlServiceCollectionExtensions.cs index 830d25cc9..57d0ff134 100644 --- a/src/EFCore.MySql/Extensions/MySqlServiceCollectionExtensions.cs +++ b/src/EFCore.MySql/Extensions/MySqlServiceCollectionExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Pomelo Foundation. All rights reserved. // Licensed under the MIT. See LICENSE in the project root for license information. +using System; using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; using Pomelo.EntityFrameworkCore.MySql.Internal; using Pomelo.EntityFrameworkCore.MySql.Migrations.Internal; @@ -8,6 +9,7 @@ using Pomelo.EntityFrameworkCore.MySql.Update.Internal; using Pomelo.EntityFrameworkCore.MySql.ValueGeneration.Internal; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Conventions; using Microsoft.EntityFrameworkCore.Migrations; @@ -20,16 +22,77 @@ using Pomelo.EntityFrameworkCore.MySql.Diagnostics.Internal; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Metadata; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure; using Pomelo.EntityFrameworkCore.MySql.Metadata.Internal; using Pomelo.EntityFrameworkCore.MySql.Migrations; using Pomelo.EntityFrameworkCore.MySql.Query.ExpressionVisitors.Internal; using Pomelo.EntityFrameworkCore.MySql.Query.Internal; +using Pomelo.EntityFrameworkCore.MySql.Storage; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class MySqlServiceCollectionExtensions { + /// + /// + /// Registers the given Entity Framework context as a service in the + /// and configures it to connect to a MySQL compatible database. + /// + /// + /// Use this method when using dependency injection in your application, such as with ASP.NET Core. + /// For applications that don't use dependency injection, consider creating + /// instances directly with its constructor. The method can then be + /// overridden to configure the Pomelo.EntityFrameworkCore.MySql provider and connection string. + /// + /// + /// To configure the for the context, either override the + /// method in your derived context, or supply + /// an optional action to configure the for the context. + /// + /// + /// For more information on how to use this method, see the Entity Framework Core documentation at https://aka.ms/efdocs. + /// For more information on using dependency injection, see https://go.microsoft.com/fwlink/?LinkId=526890. + /// + /// + /// The type of context to be registered. + /// The to add services to. + /// The connection string of the database to connect to. + /// + /// + /// The version of the database server. + /// + /// + /// Create an object for this parameter by calling the static method + /// , + /// by calling the static method (which retrieves the server version directly + /// from the database server), + /// by parsing a version string using the static methods + /// or , + /// or by directly instantiating an object from the (for MySQL) or + /// (for MariaDB) classes. + /// + /// + /// An optional action to allow additional MySQL specific configuration. + /// An optional action to configure the for the context. + /// The same service collection so that multiple calls can be chained. + public static IServiceCollection AddMySql( + this IServiceCollection serviceCollection, + string connectionString, + ServerVersion serverVersion, + Action mySqlOptionsAction = null, + Action optionsAction = null) + where TContext : DbContext + { + Check.NotNull(serviceCollection, nameof(serviceCollection)); + + return serviceCollection.AddDbContext((_, options) => + { + optionsAction?.Invoke(options); + options.UseMySql(connectionString, serverVersion, mySqlOptionsAction); + }); + } + public static IServiceCollection AddEntityFrameworkMySql([NotNull] this IServiceCollection serviceCollection) { Check.NotNull(serviceCollection, nameof(serviceCollection)); @@ -45,6 +108,7 @@ public static IServiceCollection AddEntityFrameworkMySql([NotNull] this IService .TryAdd() //.TryAdd() // What is that? .TryAdd() + .TryAdd() .TryAdd() .TryAdd() .TryAdd(p => p.GetService()) @@ -53,6 +117,7 @@ public static IServiceCollection AddEntityFrameworkMySql([NotNull] this IService .TryAdd() .TryAdd() .TryAdd() + .TryAdd() .TryAdd() .TryAdd() .TryAdd() diff --git a/src/EFCore.MySql/Infrastructure/MariaDbServerVersion.cs b/src/EFCore.MySql/Infrastructure/MariaDbServerVersion.cs index 9db204ad9..b1b776083 100644 --- a/src/EFCore.MySql/Infrastructure/MariaDbServerVersion.cs +++ b/src/EFCore.MySql/Infrastructure/MariaDbServerVersion.cs @@ -82,6 +82,8 @@ internal MariaDbServerVersionSupport([NotNull] ServerVersion serverVersion) public override bool InformationSchemaCheckConstraintsTable => ServerVersion.Version >= new Version(10, 3, 10) || ServerVersion.Version.Major == 10 && ServerVersion.Version.Minor == 2 && ServerVersion.Version.Build >= 22; // MySQL is missing the explicit TABLE_NAME column that MariaDB supports, so always join the TABLE_CONSTRAINTS table when accessing CHECK_CONSTRAINTS for any database server that supports CHECK_CONSTRAINTS. public override bool IdentifyJsonColumsByCheckConstraints => true; + public override bool Returning => ServerVersion.Version >= new Version(10, 5, 0); + public override bool CommonTableExpressions => ServerVersion.Version >= new Version(10, 2, 1); } } } diff --git a/src/EFCore.MySql/Infrastructure/MySqlServerVersion.cs b/src/EFCore.MySql/Infrastructure/MySqlServerVersion.cs index d88fa4c43..81c79ae7e 100644 --- a/src/EFCore.MySql/Infrastructure/MySqlServerVersion.cs +++ b/src/EFCore.MySql/Infrastructure/MySqlServerVersion.cs @@ -85,6 +85,8 @@ internal MySqlServerVersionSupport([NotNull] ServerVersion serverVersion) public override bool FullTextParser => ServerVersion.Version >= new Version(5, 7, 3); public override bool InformationSchemaCheckConstraintsTable => ServerVersion.Version >= new Version(8, 0, 16); // MySQL is missing the explicit TABLE_NAME column that MariaDB supports, so always join the TABLE_CONSTRAINTS table when accessing CHECK_CONSTRAINTS for any database server that supports CHECK_CONSTRAINTS. public override bool MySqlBugLimit0Offset0ExistsWorkaround => true; + public override bool DescendingIndexes => ServerVersion.Version >= new Version(8, 0, 1); + public override bool CommonTableExpressions => ServerVersion.Version >= new Version(8, 0, 1); } } } diff --git a/src/EFCore.MySql/Infrastructure/ServerVersionSupport.cs b/src/EFCore.MySql/Infrastructure/ServerVersionSupport.cs index 0d0acb3f9..c595770c3 100644 --- a/src/EFCore.MySql/Infrastructure/ServerVersionSupport.cs +++ b/src/EFCore.MySql/Infrastructure/ServerVersionSupport.cs @@ -84,5 +84,8 @@ public virtual bool PropertyOrVersion(string propertyNameOrServerVersion) public virtual bool InformationSchemaCheckConstraintsTable => false; public virtual bool IdentifyJsonColumsByCheckConstraints => false; public virtual bool MySqlBugLimit0Offset0ExistsWorkaround => false; + public virtual bool DescendingIndexes => false; + public virtual bool Returning => false; + public virtual bool CommonTableExpressions => false; } } diff --git a/src/EFCore.MySql/Internal/MySqlModelValidator.cs b/src/EFCore.MySql/Internal/MySqlModelValidator.cs index 0853c60d0..005b57069 100644 --- a/src/EFCore.MySql/Internal/MySqlModelValidator.cs +++ b/src/EFCore.MySql/Internal/MySqlModelValidator.cs @@ -1,6 +1,8 @@ // Copyright (c) Pomelo Foundation. All rights reserved. // Licensed under the MIT. See LICENSE in the project root for license information. +using System; +using System.Linq; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; @@ -38,15 +40,50 @@ public MySqlModelValidator( { } - /// - /// 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 Validate(IModel model, IDiagnosticsLogger logger) + /// + protected override void ValidateStoredProcedures( + IModel model, + IDiagnosticsLogger logger) { - base.Validate(model, logger); + base.ValidateStoredProcedures(model, logger); + + foreach (var entityType in model.GetEntityTypes()) + { + if (entityType.GetDeleteStoredProcedure() is { } deleteStoredProcedure) + { + ValidateSproc(deleteStoredProcedure, logger); + } + + if (entityType.GetInsertStoredProcedure() is { } insertStoredProcedure) + { + ValidateSproc(insertStoredProcedure, logger); + } + + if (entityType.GetUpdateStoredProcedure() is { } updateStoredProcedure) + { + ValidateSproc(updateStoredProcedure, logger); + } + } + + static void ValidateSproc(IStoredProcedure sproc, IDiagnosticsLogger logger) + { + var entityType = sproc.EntityType; + var storeObjectIdentifier = sproc.GetStoreIdentifier(); + + if (sproc.ResultColumns.Any()) + { + throw new InvalidOperationException(MySqlStrings.StoredProcedureResultColumnsNotSupported( + entityType.DisplayName(), + storeObjectIdentifier.DisplayName())); + } + + if (sproc.IsRowsAffectedReturned) + { + throw new InvalidOperationException(MySqlStrings.StoredProcedureReturnValueNotSupported( + entityType.DisplayName(), + storeObjectIdentifier.DisplayName())); + } + } } } } diff --git a/src/EFCore.MySql/Metadata/Conventions/MySqlValueGenerationConvention.cs b/src/EFCore.MySql/Metadata/Conventions/MySqlValueGenerationConvention.cs index c61137cbd..91aa2f788 100644 --- a/src/EFCore.MySql/Metadata/Conventions/MySqlValueGenerationConvention.cs +++ b/src/EFCore.MySql/Metadata/Conventions/MySqlValueGenerationConvention.cs @@ -1,12 +1,14 @@ // Copyright (c) Pomelo Foundation. All rights reserved. // Licensed under the MIT. See LICENSE in the project root for license information. +using System.Linq; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Metadata.Conventions; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; using Pomelo.EntityFrameworkCore.MySql.Metadata.Internal; namespace Pomelo.EntityFrameworkCore.MySql.Metadata.Conventions @@ -62,13 +64,15 @@ public override void ProcessPropertyAnnotationChanged( /// The store value generation strategy to set for the given property. protected override ValueGenerated? GetValueGenerated(IConventionProperty property) { - var tableName = property.DeclaringEntityType.GetTableName(); - if (tableName == null) + var declaringTable = property.GetMappedStoreObjects(StoreObjectType.Table).FirstOrDefault(); + if (declaringTable.Name == null) { return null; } - return GetValueGenerated(property, StoreObjectIdentifier.Table(tableName, property.DeclaringEntityType.GetSchema())); + // If the first mapping can be value generated then we'll consider all mappings to be value generated + // as this is a client-side configuration and can't be specified per-table. + return GetValueGenerated(property, declaringTable, Dependencies.TypeMappingSource); } /// @@ -77,7 +81,9 @@ public override void ProcessPropertyAnnotationChanged( /// The property. /// The identifier of the store object. /// The store value generation strategy to set for the given property. - public static new ValueGenerated? GetValueGenerated([NotNull] IReadOnlyProperty property, in StoreObjectIdentifier storeObject) + public static new ValueGenerated? GetValueGenerated( + [NotNull] IReadOnlyProperty property, + in StoreObjectIdentifier storeObject) { var valueGenerated = RelationalValueGenerationConvention.GetValueGenerated(property, storeObject); if (valueGenerated != null) @@ -85,19 +91,31 @@ public override void ProcessPropertyAnnotationChanged( return valueGenerated; } - var valueGenerationStrategy = property.GetValueGenerationStrategy(storeObject); - if (valueGenerationStrategy.HasValue) + return property.GetValueGenerationStrategy(storeObject) switch { - switch (valueGenerationStrategy.Value) - { - case MySqlValueGenerationStrategy.IdentityColumn: - return ValueGenerated.OnAdd; - case MySqlValueGenerationStrategy.ComputedColumn: - return ValueGenerated.OnAddOrUpdate; - } + MySqlValueGenerationStrategy.IdentityColumn => ValueGenerated.OnAdd, + MySqlValueGenerationStrategy.ComputedColumn => ValueGenerated.OnAddOrUpdate, + _ => null + }; + } + + private ValueGenerated? GetValueGenerated( + IReadOnlyProperty property, + in StoreObjectIdentifier storeObject, + ITypeMappingSource typeMappingSource) + { + var valueGenerated = RelationalValueGenerationConvention.GetValueGenerated(property, storeObject); + if (valueGenerated != null) + { + return valueGenerated; } - return null; + return property.GetValueGenerationStrategy(storeObject, typeMappingSource) switch + { + MySqlValueGenerationStrategy.IdentityColumn => ValueGenerated.OnAdd, + MySqlValueGenerationStrategy.ComputedColumn => ValueGenerated.OnAddOrUpdate, + _ => null + }; } } } diff --git a/src/EFCore.MySql/Metadata/Internal/MySqlAnnotationProvider.cs b/src/EFCore.MySql/Metadata/Internal/MySqlAnnotationProvider.cs index 0d1202030..bb27141ce 100644 --- a/src/EFCore.MySql/Metadata/Internal/MySqlAnnotationProvider.cs +++ b/src/EFCore.MySql/Metadata/Internal/MySqlAnnotationProvider.cs @@ -165,7 +165,7 @@ public override IEnumerable For(IColumn column, bool designTime) var properties = column.PropertyMappings.Select(m => m.Property).ToArray(); if (column.PropertyMappings.Where( - m => m.TableMapping.IsSharedTablePrincipal && + m => (m.TableMapping.IsSharedTablePrincipal ?? true) && m.TableMapping.EntityType == m.Property.DeclaringEntityType) .Select(m => m.Property) .FirstOrDefault(p => p.GetValueGenerationStrategy(table) == MySqlValueGenerationStrategy.IdentityColumn) is IProperty identityProperty) diff --git a/src/EFCore.MySql/Migrations/Internal/MySqlHistoryRepository.cs b/src/EFCore.MySql/Migrations/Internal/MySqlHistoryRepository.cs index 335b665e6..e77348d72 100644 --- a/src/EFCore.MySql/Migrations/Internal/MySqlHistoryRepository.cs +++ b/src/EFCore.MySql/Migrations/Internal/MySqlHistoryRepository.cs @@ -165,14 +165,14 @@ protected override string MigrationIdColumnName => _migrationIdColumnName ??= EnsureModel() .FindEntityType(typeof(HistoryRow))! .FindProperty(nameof(HistoryRow.MigrationId))! - .GetColumnBaseName(); + .GetColumnName(); // Original implementation. protected override string ProductVersionColumnName => _productVersionColumnName ??= EnsureModel() .FindEntityType(typeof(HistoryRow))! .FindProperty(nameof(HistoryRow.ProductVersion))! - .GetColumnBaseName(); + .GetColumnName(); #endregion Necessary implementation because we cannot directly override EnsureModel } diff --git a/src/EFCore.MySql/Migrations/Internal/MySqlMigrationsModelDiffer.cs b/src/EFCore.MySql/Migrations/Internal/MySqlMigrationsModelDiffer.cs index 233c34734..63f97c0c6 100644 --- a/src/EFCore.MySql/Migrations/Internal/MySqlMigrationsModelDiffer.cs +++ b/src/EFCore.MySql/Migrations/Internal/MySqlMigrationsModelDiffer.cs @@ -7,15 +7,12 @@ using System.Linq; using System.Reflection; using System.Text.RegularExpressions; -using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Internal; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Update; using Microsoft.EntityFrameworkCore.Update.Internal; using Pomelo.EntityFrameworkCore.MySql.Internal; using Pomelo.EntityFrameworkCore.MySql.Metadata.Internal; @@ -33,16 +30,14 @@ protected static class InternalLocalAnnotationNames } public MySqlMigrationsModelDiffer( - [NotNull] IRelationalTypeMappingSource typeMappingSource, - [NotNull] IMigrationsAnnotationProvider migrationsAnnotations, - [NotNull] IChangeDetector changeDetector, - [NotNull] IUpdateAdapterFactory updateAdapterFactory, - [NotNull] CommandBatchPreparerDependencies commandBatchPreparerDependencies) + IRelationalTypeMappingSource typeMappingSource, + IMigrationsAnnotationProvider migrationsAnnotationProvider, + IRowIdentityMapFactory rowIdentityMapFactory, + CommandBatchPreparerDependencies commandBatchPreparerDependencies) : base( typeMappingSource, - migrationsAnnotations, - changeDetector, - updateAdapterFactory, + migrationsAnnotationProvider, + rowIdentityMapFactory, commandBatchPreparerDependencies) { AssertAllMigrationOperationProperties(); diff --git a/src/EFCore.MySql/Migrations/MySqlMigrationsSqlGenerator.cs b/src/EFCore.MySql/Migrations/MySqlMigrationsSqlGenerator.cs index cdf892234..ac08ae455 100644 --- a/src/EFCore.MySql/Migrations/MySqlMigrationsSqlGenerator.cs +++ b/src/EFCore.MySql/Migrations/MySqlMigrationsSqlGenerator.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Linq; using System.Reflection; +using System.Text; using System.Text.RegularExpressions; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; @@ -15,12 +16,14 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Update; using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.Logging; using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; using Pomelo.EntityFrameworkCore.MySql.Internal; using Pomelo.EntityFrameworkCore.MySql.Metadata.Internal; using Pomelo.EntityFrameworkCore.MySql.Storage.Internal; +using Pomelo.EntityFrameworkCore.MySql.Update.Internal; namespace Pomelo.EntityFrameworkCore.MySql.Migrations { @@ -51,17 +54,17 @@ public class MySqlMigrationsSqlGenerator : MigrationsSqlGenerator "multipolygon", }; - private readonly IRelationalAnnotationProvider _annotationProvider; + private readonly ICommandBatchPreparer _commandBatchPreparer; private readonly IMySqlOptions _options; private readonly RelationalTypeMapping _stringTypeMapping; public MySqlMigrationsSqlGenerator( [NotNull] MigrationsSqlGeneratorDependencies dependencies, - [NotNull] IRelationalAnnotationProvider annotationProvider, + [NotNull] ICommandBatchPreparer commandBatchPreparer, [NotNull] IMySqlOptions options) : base(dependencies) { - _annotationProvider = annotationProvider; + _commandBatchPreparer = commandBatchPreparer; _options = options; _stringTypeMapping = dependencies.TypeMappingSource.GetMapping(typeof(string)); } @@ -457,7 +460,7 @@ protected override void Generate( .Append(" ON ") .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Table, operation.Schema)) .Append(" (") - .Append(ColumnListWithIndexPrefixLength(operation, operation.Columns)) + .Append(ColumnListWithIndexPrefixLengthAndSortOrder(operation, operation.Columns, operation[MySqlAnnotationNames.IndexPrefixLength] as int[], operation.IsDescending)) .Append(")"); IndexOptions(operation, model, builder); @@ -504,6 +507,7 @@ protected override void Generate( { Check.NotNull(operation, nameof(operation)); Check.NotNull(builder, nameof(builder)); + if (!_options.ServerVersion.Supports.Sequences) { throw new InvalidOperationException( @@ -518,7 +522,7 @@ protected override void Generate( // https://github.com/aspnet/EntityFrameworkCore/blob/master/src/EFCore.Relational/Migrations/MigrationsSqlGenerator.cs#L535-L543 var oldValue = operation.ClrType; operation.ClrType = typeof(long); - if (operation.StartValue <= 0 ) + if (operation.StartValue <= 0) { operation.MinValue = operation.StartValue; } @@ -526,6 +530,55 @@ protected override void Generate( operation.ClrType = oldValue; } + protected override void Generate(AlterSequenceOperation operation, IModel model, MigrationCommandListBuilder builder) + { + Check.NotNull(operation, nameof(operation)); + Check.NotNull(builder, nameof(builder)); + + if (!_options.ServerVersion.Supports.Sequences) + { + throw new InvalidOperationException( + $"Cannot alter sequence '{operation.Name}' because sequences are not supported in server version {_options.ServerVersion}."); + } + + base.Generate(operation, model, builder); + } + + protected override void Generate(DropSequenceOperation operation, IModel model, MigrationCommandListBuilder builder) + { + Check.NotNull(operation, nameof(operation)); + Check.NotNull(builder, nameof(builder)); + + if (!_options.ServerVersion.Supports.Sequences) + { + throw new InvalidOperationException( + $"Cannot alter sequence '{operation.Name}' because sequences are not supported in server version {_options.ServerVersion}."); + } + + base.Generate(operation, model, builder); + } + + protected override void Generate(RenameSequenceOperation operation, IModel model, MigrationCommandListBuilder builder) + { + Check.NotNull(operation, nameof(operation)); + Check.NotNull(builder, nameof(builder)); + + if (!_options.ServerVersion.Supports.Sequences) + { + throw new InvalidOperationException( + $"Cannot alter sequence '{operation.Name}' because sequences are not supported in server version {_options.ServerVersion}."); + } + + builder + .Append("ALTER TABLE ") + .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.Name, operation.Schema)) + .Append(" RENAME ") + .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(operation.NewName, operation.NewSchema)) + .AppendLine(Dependencies.SqlGenerationHelper.StatementTerminator); + + EndStatement(builder); + } + /// /// Builds commands for the given /// by making calls on the given . @@ -1333,7 +1386,7 @@ protected override void PrimaryKeyConstraint( IndexTraits(operation, model, builder); builder.Append("(") - .Append(ColumnListWithIndexPrefixLength(operation, operation.Columns)) + .Append(ColumnListWithIndexPrefixLengthAndSortOrder(operation, operation.Columns, operation[MySqlAnnotationNames.IndexPrefixLength] as int[])) .Append(")"); } @@ -1359,7 +1412,7 @@ protected override void UniqueConstraint( IndexTraits(operation, model, builder); builder.Append("(") - .Append(ColumnListWithIndexPrefixLength(operation, operation.Columns)) + .Append(ColumnListWithIndexPrefixLengthAndSortOrder(operation, operation.Columns, operation[MySqlAnnotationNames.IndexPrefixLength] as int[])) .Append(")"); } @@ -1529,14 +1582,38 @@ protected override void ForeignKeyAction(ReferentialAction referentialAction, } } - private string ColumnListWithIndexPrefixLength(MigrationOperation operation, string[] columns) - => operation[MySqlAnnotationNames.IndexPrefixLength] is int[] prefixValues - ? ColumnList( - columns, - (c, i) => prefixValues.Length > i && prefixValues[i] > 0 - ? $"({prefixValues[i]})" - : null) - : ColumnList(columns); + /// + /// Use VALUES batches for INSERT commands where possible. + /// + protected override void Generate(InsertDataOperation operation, IModel model, MigrationCommandListBuilder builder, bool terminate = true) + { + var sqlBuilder = new StringBuilder(); + + var modificationCommands = GenerateModificationCommands(operation, model).ToList(); + var updateSqlGenerator = (IMySqlUpdateSqlGenerator)Dependencies.UpdateSqlGenerator; + + foreach (var batch in _commandBatchPreparer.CreateCommandBatches(modificationCommands, moreCommandSets: true)) + { + updateSqlGenerator.AppendBulkInsertOperation(sqlBuilder, batch.ModificationCommands, commandPosition: 0, out _); + } + + builder.Append(sqlBuilder.ToString()); + + if (terminate) + { + builder.EndCommand(); + } + } + + /// + /// There is no need to check for explicit index collation/descending support, because ASC and DESC modifiers are being silently + /// ignored in versions of MySQL and MariaDB, that do not support them. + /// + private string ColumnListWithIndexPrefixLengthAndSortOrder(MigrationOperation operation, string[] columns, int[] prefixValues, bool[] isDescending = null) + => ColumnList( + columns, + (c, i) + => $"{(prefixValues is not null && prefixValues.Length > i && prefixValues[i] > 0 ? $"({prefixValues[i]})" : null)}{(isDescending is not null && (isDescending.Length == 0 || isDescending[i]) ? " DESC" : null)}"); protected virtual string ColumnList([NotNull] string[] columns, Func columnPostfix) => string.Join(", ", columns.Select((c, i) => Dependencies.SqlGenerationHelper.DelimitIdentifier(c) + columnPostfix?.Invoke(c, i))); diff --git a/src/EFCore.MySql/Properties/MySqlStrings.Designer.cs b/src/EFCore.MySql/Properties/MySqlStrings.Designer.cs index f7c8efb6e..d0ce5bef8 100644 --- a/src/EFCore.MySql/Properties/MySqlStrings.Designer.cs +++ b/src/EFCore.MySql/Properties/MySqlStrings.Designer.cs @@ -153,6 +153,22 @@ public static string QueryUnableToTranslateMethodWithStringComparison([CanBeNull GetString("QueryUnableToTranslateMethodWithStringComparison", nameof(declaringTypeName), nameof(methodName), nameof(optionName)), declaringTypeName, methodName, optionName); + /// + /// The entity type '{entityType}' is mapped to the stored procedure '{sproc}', which is configured with result columns. MySQL stored procedures do not support result columns; use output parameters instead. + /// + public static string StoredProcedureResultColumnsNotSupported(object entityType, object sproc) + => string.Format( + GetString("StoredProcedureResultColumnsNotSupported", nameof(entityType), nameof(sproc)), + entityType, sproc); + + /// + /// The entity type '{entityType}' is mapped to the stored procedure '{sproc}', which is configured with a return value. MySQL stored procedures do not support return values; use an output parameter instead. + /// + public static string StoredProcedureReturnValueNotSupported(object entityType, object sproc) + => string.Format( + GetString("StoredProcedureReturnValueNotSupported", nameof(entityType), nameof(sproc)), + entityType, sproc); + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/EFCore.MySql/Properties/MySqlStrings.resx b/src/EFCore.MySql/Properties/MySqlStrings.resx index 81345fa64..8d2943c90 100644 --- a/src/EFCore.MySql/Properties/MySqlStrings.resx +++ b/src/EFCore.MySql/Properties/MySqlStrings.resx @@ -234,4 +234,10 @@ The default value '{defaultValue}' is being ignored, because the database server version {version} does not support constant default values for type '{type}' and does not support default value expressions in general. + + The entity type '{entityType}' is mapped to the stored procedure '{sproc}', which is configured with result columns. MySQL stored procedures do not support result columns; use output parameters instead. + + + The entity type '{entityType}' is mapped to the stored procedure '{sproc}', which is configured with a return value. MySQL stored procedures do not support return values; use an output parameter instead. + diff --git a/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlBoolOptimizingExpressionVisitor.cs b/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlBoolOptimizingExpressionVisitor.cs index 79e4f8aca..ce6c72c2e 100644 --- a/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlBoolOptimizingExpressionVisitor.cs +++ b/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlBoolOptimizingExpressionVisitor.cs @@ -40,6 +40,17 @@ sqlExpression.TypeMapping is MySqlBoolTypeMapping && return sqlExpression; } + protected override Expression VisitAtTimeZone(AtTimeZoneExpression atTimeZoneExpression) + { + var parentOptimize = _optimize; + _optimize = false; + var operand = (SqlExpression)Visit(atTimeZoneExpression.Operand); + var timeZone = (SqlExpression)Visit(atTimeZoneExpression.TimeZone); + _optimize = parentOptimize; + + return atTimeZoneExpression.Update(operand, timeZone); + } + protected override Expression VisitCase(CaseExpression caseExpression) { Check.NotNull(caseExpression, nameof(caseExpression)); @@ -86,6 +97,9 @@ protected override Expression VisitColumn(ColumnExpression columnExpression) return ApplyConversion(columnExpression, condition: false); } + protected override Expression VisitDelete(DeleteExpression deleteExpression) + => deleteExpression.Update((SelectExpression)Visit(deleteExpression.SelectExpression)); + protected override Expression VisitDistinct(DistinctExpression distinctExpression) { Check.NotNull(distinctExpression, nameof(distinctExpression)); @@ -579,5 +593,38 @@ protected override Expression VisitUnion(UnionExpression unionExpression) return unionExpression.Update(source1, source2); } + + protected override Expression VisitUpdate(UpdateExpression updateExpression) + { + var selectExpression = (SelectExpression)Visit(updateExpression.SelectExpression); + var parentOptimize = _optimize; + _optimize = false; + List columnValueSetters = null; + for (var (i, n) = (0, updateExpression.ColumnValueSetters.Count); i < n; i++) + { + var columnValueSetter = updateExpression.ColumnValueSetters[i]; + var newValue = (SqlExpression)Visit(columnValueSetter.Value); + if (columnValueSetters != null) + { + columnValueSetters.Add(new ColumnValueSetter(columnValueSetter.Column, newValue)); + } + else if (!ReferenceEquals(newValue, columnValueSetter.Value)) + { + columnValueSetters = new List(); + for (var j = 0; j < i; j++) + { + columnValueSetters.Add(updateExpression.ColumnValueSetters[j]); + } + + columnValueSetters.Add(new ColumnValueSetter(columnValueSetter.Column, newValue)); + } + } + + _optimize = parentOptimize; + return updateExpression.Update(selectExpression, columnValueSetters ?? updateExpression.ColumnValueSetters); + } + + protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExpression) + => jsonScalarExpression; } } diff --git a/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQuerySqlGenerator.cs b/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQuerySqlGenerator.cs index 175fecc49..49a3dbdc4 100644 --- a/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQuerySqlGenerator.cs +++ b/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQuerySqlGenerator.cs @@ -7,6 +7,7 @@ using System.Linq.Expressions; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Storage; @@ -45,6 +46,8 @@ public class MySqlQuerySqlGenerator : QuerySqlGenerator private const ulong LimitUpperBound = 18446744073709551610; private readonly IMySqlOptions _options; + private string _removeTableAliasOld; + private string _removeTableAliasNew; /// /// This API supports the Entity Framework Core infrastructure and is not intended to be used @@ -153,6 +156,44 @@ protected virtual Expression VisitJsonPathTraversal(MySqlJsonTraversalExpression return expression; } + protected override Expression VisitColumn(ColumnExpression columnExpression) + { + if (_removeTableAliasOld is not null && + columnExpression.TableAlias == _removeTableAliasOld) + { + if (_removeTableAliasNew is not null) + { + Sql.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(_removeTableAliasNew)) + .Append("."); + } + + Sql.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(columnExpression.Name)); + + return columnExpression; + } + + return base.VisitColumn(columnExpression); + } + + protected override Expression VisitTable(TableExpression tableExpression) + { + if (_removeTableAliasOld is not null && + tableExpression.Alias == _removeTableAliasOld) + { + if (_removeTableAliasNew is not null) + { + Sql.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(_removeTableAliasNew)) + .Append(AliasSeparator); + } + + Sql.Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(tableExpression.Name)); + + return tableExpression; + } + + return base.VisitTable(tableExpression); + } + /// /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. @@ -281,6 +322,120 @@ sqlBinaryExpression.Right is SqlUnaryExpression sqlUnaryExpression && return sqlBinaryExpression; } + protected override Expression VisitDelete(DeleteExpression deleteExpression) + { + var selectExpression = deleteExpression.SelectExpression; + + if (selectExpression.Offset == null + && selectExpression.Having == null + && selectExpression.GroupBy.Count == 0 + && selectExpression.Projection.Count == 0 + && (selectExpression.Tables.Count == 1 || selectExpression.Orderings.Count == 0 && selectExpression.Limit is null)) + { + var removeSingleTableAlias = selectExpression.Tables.Count == 1 && + selectExpression.Orderings.Count > 0 || selectExpression.Limit is not null; + + Sql.Append($"DELETE"); + + if (!removeSingleTableAlias) + { + Sql.Append($" {Dependencies.SqlGenerationHelper.DelimitIdentifier(deleteExpression.Table.Alias)}"); + } + + Sql.AppendLine().Append("FROM "); + + if (removeSingleTableAlias) + { + _removeTableAliasOld = selectExpression.Tables[0].Alias; + _removeTableAliasNew = null; + } + + GenerateList(selectExpression.Tables, e => Visit(e), sql => sql.AppendLine()); + + if (selectExpression.Predicate != null) + { + Sql.AppendLine().Append("WHERE "); + + Visit(selectExpression.Predicate); + } + + GenerateOrderings(selectExpression); + GenerateLimitOffset(selectExpression); + + if (removeSingleTableAlias) + { + _removeTableAliasOld = null; + } + + return deleteExpression; + } + + throw new InvalidOperationException( + RelationalStrings.ExecuteOperationWithUnsupportedOperatorInSqlGeneration(nameof(RelationalQueryableExtensions.ExecuteDelete))); + } + + protected override Expression VisitUpdate(UpdateExpression updateExpression) + { + var selectExpression = updateExpression.SelectExpression; + + if (selectExpression.Offset == null + && selectExpression.Having == null + && selectExpression.Orderings.Count == 0 + && selectExpression.GroupBy.Count == 0 + && selectExpression.Projection.Count == 0) + { + Sql.Append("UPDATE "); + GenerateList(selectExpression.Tables, e => Visit(e), sql => sql.AppendLine()); + + Sql.AppendLine().Append("SET "); + Visit(updateExpression.ColumnValueSetters[0].Column); + Sql.Append(" = "); + Visit(updateExpression.ColumnValueSetters[0].Value); + + using (Sql.Indent()) + { + foreach (var columnValueSetter in updateExpression.ColumnValueSetters.Skip(1)) + { + Sql.AppendLine(","); + Visit(columnValueSetter.Column); + Sql.Append(" = "); + Visit(columnValueSetter.Value); + } + } + + if (selectExpression.Predicate != null) + { + Sql.AppendLine().Append("WHERE "); + Visit(selectExpression.Predicate); + } + + GenerateLimitOffset(selectExpression); + + return updateExpression; + } + + throw new InvalidOperationException( + RelationalStrings.ExecuteOperationWithUnsupportedOperatorInSqlGeneration(nameof(RelationalQueryableExtensions.ExecuteUpdate))); + } + + protected virtual void GenerateList( + IReadOnlyList items, + Action generationAction, + Action joinAction = null) + { + joinAction ??= (isb => isb.Append(", ")); + + for (var i = 0; i < items.Count; i++) + { + if (i > 0) + { + joinAction(Sql); + } + + generationAction(items[i]); + } + } + private static bool RequiresBrackets(SqlExpression expression) => expression is SqlBinaryExpression || expression is LikeExpression diff --git a/src/EFCore.MySql/Query/Internal/MySqlParameterBasedSqlProcessor.cs b/src/EFCore.MySql/Query/Internal/MySqlParameterBasedSqlProcessor.cs index afcae8e88..4c2235d48 100644 --- a/src/EFCore.MySql/Query/Internal/MySqlParameterBasedSqlProcessor.cs +++ b/src/EFCore.MySql/Query/Internal/MySqlParameterBasedSqlProcessor.cs @@ -4,9 +4,8 @@ #nullable enable using System.Collections.Generic; -using JetBrains.Annotations; +using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Utilities; using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; using Pomelo.EntityFrameworkCore.MySql.Query.ExpressionVisitors.Internal; @@ -19,7 +18,7 @@ public class MySqlParameterBasedSqlProcessor : RelationalParameterBasedSqlProces private readonly MySqlSqlExpressionFactory _sqlExpressionFactory; public MySqlParameterBasedSqlProcessor( - [NotNull] RelationalParameterBasedSqlProcessorDependencies dependencies, + RelationalParameterBasedSqlProcessorDependencies dependencies, bool useRelationalNulls, IMySqlOptions options) : base(dependencies, useRelationalNulls) @@ -28,44 +27,48 @@ public MySqlParameterBasedSqlProcessor( _options = options; } - public override SelectExpression Optimize(SelectExpression selectExpression, IReadOnlyDictionary parametersValues, out bool canCache) + public override Expression Optimize( + Expression queryExpression, + IReadOnlyDictionary parametersValues, + out bool canCache) { - Check.NotNull(selectExpression, nameof(selectExpression)); - Check.NotNull(parametersValues, nameof(parametersValues)); - - selectExpression = base.Optimize(selectExpression, parametersValues, out canCache); + queryExpression = base.Optimize(queryExpression, parametersValues, out canCache); if (_options.ServerVersion.Supports.MySqlBugLimit0Offset0ExistsWorkaround) { - selectExpression = new SkipTakeCollapsingExpressionVisitor(Dependencies.SqlExpressionFactory) - .Process(selectExpression, parametersValues, out var canCache2); + queryExpression = new SkipTakeCollapsingExpressionVisitor(Dependencies.SqlExpressionFactory) + .Process(queryExpression, parametersValues, out var canCache2); canCache &= canCache2; } if (_options.IndexOptimizedBooleanColumns) { - selectExpression = (SelectExpression)new MySqlBoolOptimizingExpressionVisitor(Dependencies.SqlExpressionFactory).Visit(selectExpression); + queryExpression = new MySqlBoolOptimizingExpressionVisitor(Dependencies.SqlExpressionFactory) + .Visit(queryExpression); } - selectExpression = (SelectExpression)new MySqlHavingExpressionVisitor(_sqlExpressionFactory).Visit(selectExpression); + queryExpression = new MySqlHavingExpressionVisitor(_sqlExpressionFactory).Visit(queryExpression); // Run the compatibility checks as late in the query pipeline (before the actual SQL translation happens) as reasonable. - selectExpression = (SelectExpression)new MySqlCompatibilityExpressionVisitor(_options).Visit(selectExpression); + queryExpression = new MySqlCompatibilityExpressionVisitor(_options).Visit(queryExpression); - return selectExpression; + return queryExpression; } /// - protected override SelectExpression ProcessSqlNullability( - SelectExpression selectExpression, IReadOnlyDictionary parametersValues, out bool canCache) + protected override Expression ProcessSqlNullability( + Expression queryExpression, + IReadOnlyDictionary parametersValues, + out bool canCache) { - Check.NotNull(selectExpression, nameof(selectExpression)); + Check.NotNull(queryExpression, nameof(queryExpression)); Check.NotNull(parametersValues, nameof(parametersValues)); - selectExpression = new MySqlSqlNullabilityProcessor(Dependencies, UseRelationalNulls).Process(selectExpression, parametersValues, out canCache); + queryExpression = new MySqlSqlNullabilityProcessor(Dependencies, UseRelationalNulls) + .Process(queryExpression, parametersValues, out canCache); - return selectExpression; + return queryExpression; } } } diff --git a/src/EFCore.MySql/Query/Internal/MySqlQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.MySql/Query/Internal/MySqlQueryableMethodTranslatingExpressionVisitor.cs new file mode 100644 index 000000000..261c69ec5 --- /dev/null +++ b/src/EFCore.MySql/Query/Internal/MySqlQueryableMethodTranslatingExpressionVisitor.cs @@ -0,0 +1,99 @@ +// Copyright (c) Pomelo Foundation. All rights reserved. +// Licensed under the MIT. See LICENSE in the project root for license information. + +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; + +namespace Pomelo.EntityFrameworkCore.MySql.Query.Internal; + +public class MySqlQueryableMethodTranslatingExpressionVisitor : RelationalQueryableMethodTranslatingExpressionVisitor +{ + public MySqlQueryableMethodTranslatingExpressionVisitor( + QueryableMethodTranslatingExpressionVisitorDependencies dependencies, + RelationalQueryableMethodTranslatingExpressionVisitorDependencies relationalDependencies, + QueryCompilationContext queryCompilationContext) + : base(dependencies, relationalDependencies, queryCompilationContext) + { + } + + protected override bool IsValidSelectExpressionForExecuteDelete( + SelectExpression selectExpression, + EntityShaperExpression entityShaperExpression, + [NotNullWhen(true)] out TableExpression tableExpression) + { + if (selectExpression.Offset == null + && (!selectExpression.IsDistinct || entityShaperExpression.EntityType.FindPrimaryKey() != null) + && selectExpression.GroupBy.Count == 0 + && selectExpression.Having == null + && (selectExpression.Tables.Count == 1 || selectExpression.Orderings.Count == 0)) + { + TableExpressionBase table; + if (selectExpression.Tables.Count == 1) + { + table = selectExpression.Tables[0]; + } + else + { + var projectionBindingExpression = (ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression; + var entityProjectionExpression = (EntityProjectionExpression)selectExpression.GetProjection(projectionBindingExpression); + var column = entityProjectionExpression.BindProperty(entityShaperExpression.EntityType.GetProperties().First()); + table = column.Table; + if (table is JoinExpressionBase joinExpressionBase) + { + table = joinExpressionBase.Table; + } + } + + if (table is TableExpression te) + { + tableExpression = te; + return true; + } + } + + tableExpression = null; + return false; + } + + protected override bool IsValidSelectExpressionForExecuteUpdate( + SelectExpression selectExpression, + EntityShaperExpression entityShaperExpression, + [NotNullWhen(true)] out TableExpression tableExpression) + { + if (selectExpression.Offset == null + // If entity type has primary key then Distinct is no-op + && (!selectExpression.IsDistinct || entityShaperExpression.EntityType.FindPrimaryKey() != null) + && selectExpression.GroupBy.Count == 0 + && selectExpression.Having == null + && selectExpression.Orderings.Count == 0) + { + TableExpressionBase table; + if (selectExpression.Tables.Count == 1) + { + table = selectExpression.Tables[0]; + } + else + { + var projectionBindingExpression = (ProjectionBindingExpression)entityShaperExpression.ValueBufferExpression; + var entityProjectionExpression = (EntityProjectionExpression)selectExpression.GetProjection(projectionBindingExpression); + var column = entityProjectionExpression.BindProperty(entityShaperExpression.EntityType.GetProperties().First()); + table = column.Table; + if (table is JoinExpressionBase joinExpressionBase) + { + table = joinExpressionBase.Table; + } + } + + if (table is TableExpression te) + { + tableExpression = te; + return true; + } + } + + tableExpression = null; + return false; + } +} diff --git a/src/EFCore.MySql/Query/Internal/MySqlQueryableMethodTranslatingExpressionVisitorFactory.cs b/src/EFCore.MySql/Query/Internal/MySqlQueryableMethodTranslatingExpressionVisitorFactory.cs new file mode 100644 index 000000000..498e7a33e --- /dev/null +++ b/src/EFCore.MySql/Query/Internal/MySqlQueryableMethodTranslatingExpressionVisitorFactory.cs @@ -0,0 +1,42 @@ +// Copyright (c) Pomelo Foundation. All rights reserved. +// Licensed under the MIT. See LICENSE in the project root for license information. + +using Microsoft.EntityFrameworkCore.Query; + +namespace Pomelo.EntityFrameworkCore.MySql.Query.Internal; + +public class MySqlQueryableMethodTranslatingExpressionVisitorFactory : IQueryableMethodTranslatingExpressionVisitorFactory +{ + /// + /// 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 MySqlQueryableMethodTranslatingExpressionVisitorFactory( + QueryableMethodTranslatingExpressionVisitorDependencies dependencies, + RelationalQueryableMethodTranslatingExpressionVisitorDependencies relationalDependencies) + { + Dependencies = dependencies; + RelationalDependencies = relationalDependencies; + } + + /// + /// Dependencies for this service. + /// + protected virtual QueryableMethodTranslatingExpressionVisitorDependencies Dependencies { get; } + + /// + /// Relational provider-specific dependencies for this service. + /// + protected virtual RelationalQueryableMethodTranslatingExpressionVisitorDependencies RelationalDependencies { get; } + + /// + /// 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 virtual QueryableMethodTranslatingExpressionVisitor Create(QueryCompilationContext queryCompilationContext) + => new MySqlQueryableMethodTranslatingExpressionVisitor(Dependencies, RelationalDependencies, queryCompilationContext); +} diff --git a/src/EFCore.MySql/Query/Internal/SkipTakeCollapsingExpressionVisitor.cs b/src/EFCore.MySql/Query/Internal/SkipTakeCollapsingExpressionVisitor.cs index 69f532aca..217c83d53 100644 --- a/src/EFCore.MySql/Query/Internal/SkipTakeCollapsingExpressionVisitor.cs +++ b/src/EFCore.MySql/Query/Internal/SkipTakeCollapsingExpressionVisitor.cs @@ -26,8 +26,8 @@ public SkipTakeCollapsingExpressionVisitor(ISqlExpressionFactory sqlExpressionFa _parameterValues = null!; } - public virtual SelectExpression Process( - SelectExpression selectExpression, + public virtual Expression Process( + Expression selectExpression, IReadOnlyDictionary parametersValues, out bool canCache) { @@ -37,7 +37,7 @@ public virtual SelectExpression Process( _parameterValues = parametersValues; _canCache = true; - var result = (SelectExpression)Visit(selectExpression); + var result = Visit(selectExpression); canCache = _canCache; diff --git a/src/EFCore.MySql/Scaffolding/Internal/MySqlDatabaseModelFactory.cs b/src/EFCore.MySql/Scaffolding/Internal/MySqlDatabaseModelFactory.cs index eb4e3dd53..dbcfe7883 100644 --- a/src/EFCore.MySql/Scaffolding/Internal/MySqlDatabaseModelFactory.cs +++ b/src/EFCore.MySql/Scaffolding/Internal/MySqlDatabaseModelFactory.cs @@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Scaffolding; using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; @@ -168,6 +169,15 @@ protected virtual DatabaseModel GetDatabase(DbConnection connection, DatabaseMod databaseModel.Tables.Add(table); } + if (_options.ServerVersion.Supports.Sequences) + { + foreach (var sequence in GetSequences(connection)) + { + sequence.Database = databaseModel; + databaseModel.Sequences.Add(sequence); + } + } + return databaseModel; } @@ -179,6 +189,16 @@ protected virtual Func GenerateTableFilter( IReadOnlyList schemas) => tables.Count > 0 ? (s, t) => tables.Contains(t) : (Func)null; + private static Func GenerateSchemaFilter(IReadOnlyList schemas) + => schemas.Any() + ? s => $"{s} IN ({string.Join(", ", schemas.Select(EscapeLiteral))})" + : null; + + /// + /// Wraps a string literal in single quotes. + /// + private static string EscapeLiteral(string s) => $"'{s}'"; + private const string GetTablesQuery = @"SELECT `t`.`TABLE_NAME`, `t`.`TABLE_TYPE`, @@ -251,7 +271,66 @@ protected virtual IEnumerable GetTables( } } - private const string GetColumnsQuery = @"SELECT + /// + /// Queries the database for defined sequences and registers them with the model. + /// + private static IEnumerable GetSequences(DbConnection connection) + { + var commandText = @"SELECT + `t`.`TABLE_NAME` +FROM + `INFORMATION_SCHEMA`.`TABLES` as `t` +WHERE + `TABLE_SCHEMA` = SCHEMA() +AND + `TABLE_TYPE` = 'SEQUENCE'"; + + var sequences = new List(); + + using var command = connection.CreateCommand(); + command.CommandText = commandText; + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + var name = reader.GetValueOrDefault("TABLE_NAME"); + + var sequence = new DatabaseSequence + { + Schema = null, + Name = name, + }; + + sequences.Add(sequence); + } + } + + foreach (var sequence in sequences) + { + command.CommandText = $"SELECT `START_VALUE`, `MINIMUM_VALUE`, `MAXIMUM_VALUE`, `INCREMENT`, `CYCLE_OPTION` FROM `{sequence.Name}`"; + + using var reader = command.ExecuteReader(); + while (reader.Read()) + { + var startValue = reader.GetValueOrDefault("START_VALUE"); + var minimumValue = reader.GetValueOrDefault("MINIMUM_VALUE"); + var maximumValue = reader.GetValueOrDefault("MAXIMUM_VALUE"); + var increment = reader.GetValueOrDefault("INCREMENT"); + var cycle = reader.GetValueOrDefault("CYCLE_OPTION"); + + sequence.StartValue = startValue; + sequence.MinValue = minimumValue; + sequence.MaxValue = maximumValue; + sequence.IncrementBy = increment; + sequence.IsCyclic = cycle; + } + } + + return sequences; + } + + private const string GetColumnsQuery = @"SELECT `COLUMN_NAME`, `ORDINAL_POSITION`, `COLUMN_DEFAULT`, @@ -635,6 +714,7 @@ protected virtual void GetPrimaryKeys( `NON_UNIQUE`, GROUP_CONCAT(`COLUMN_NAME` ORDER BY `SEQ_IN_INDEX` SEPARATOR ',') AS `COLUMNS`, GROUP_CONCAT(CAST(IFNULL(`SUB_PART`, 0) AS CHAR) ORDER BY `SEQ_IN_INDEX` SEPARATOR ',') AS `SUB_PARTS`, + GROUP_CONCAT(IFNULL(`COLLATION`, 'A') ORDER BY `SEQ_IN_INDEX` SEPARATOR ',') AS `COLLATION`, `INDEX_TYPE` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = '{0}' @@ -724,6 +804,11 @@ protected virtual void GetIndexes( index[MySqlAnnotationNames.IndexPrefixLength] = null; } + index.IsDescending = reader.GetValueOrDefault("COLLATION") + .Split(',') + .Select(c => c == "D") + .ToArray(); + var indexType = reader.GetValueOrDefault("INDEX_TYPE"); if (string.Equals(indexType, "spatial", StringComparison.OrdinalIgnoreCase)) diff --git a/src/EFCore.MySql/Storage/Internal/MySqlRelationalConnection.cs b/src/EFCore.MySql/Storage/Internal/MySqlRelationalConnection.cs index 1b5593180..12c5dc592 100644 --- a/src/EFCore.MySql/Storage/Internal/MySqlRelationalConnection.cs +++ b/src/EFCore.MySql/Storage/Internal/MySqlRelationalConnection.cs @@ -72,7 +72,7 @@ public virtual IMySqlRelationalConnection CreateMasterConnection() set => base.DbConnection = value; } - private MySqlConnectionStringBuilder AddConnectionStringOptions(MySqlConnectionStringBuilder builder) + protected virtual MySqlConnectionStringBuilder AddConnectionStringOptions(MySqlConnectionStringBuilder builder) { if (CommandTimeout != null) { diff --git a/src/EFCore.MySql/Update/Internal/IMySqlUpdateSqlGenerator.cs b/src/EFCore.MySql/Update/Internal/IMySqlUpdateSqlGenerator.cs index fdb5f69a6..b91daa822 100644 --- a/src/EFCore.MySql/Update/Internal/IMySqlUpdateSqlGenerator.cs +++ b/src/EFCore.MySql/Update/Internal/IMySqlUpdateSqlGenerator.cs @@ -13,6 +13,7 @@ public interface IMySqlUpdateSqlGenerator : IUpdateSqlGenerator ResultSetMapping AppendBulkInsertOperation( [NotNull] StringBuilder commandStringBuilder, [NotNull] IReadOnlyList modificationCommands, - int commandPosition); + int commandPosition, + out bool requiresTransaction); } } diff --git a/src/EFCore.MySql/Update/Internal/MySqlModificationCommand.cs b/src/EFCore.MySql/Update/Internal/MySqlModificationCommand.cs new file mode 100644 index 000000000..8c138c71b --- /dev/null +++ b/src/EFCore.MySql/Update/Internal/MySqlModificationCommand.cs @@ -0,0 +1,68 @@ +// Copyright (c) Pomelo Foundation. All rights reserved. +// Licensed under the MIT. See LICENSE in the project root for license information. + +using System; +using System.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Update; + +namespace Pomelo.EntityFrameworkCore.MySql.Update.Internal; + +public class MySqlModificationCommand : ModificationCommand +{ + private readonly bool _detailedErrorsEnabled; + + public MySqlModificationCommand(in ModificationCommandParameters modificationCommandParameters) + : base(in modificationCommandParameters) + => _detailedErrorsEnabled = modificationCommandParameters.DetailedErrorsEnabled; + + public MySqlModificationCommand(in NonTrackedModificationCommandParameters modificationCommandParameters) + : base(in modificationCommandParameters) + { + } + + public override void PropagateResults(RelationalDataReader relationalReader) + { + // The default implementation of PropagateResults skips (output) parameters, since for e.g. SQL Server these aren't yet populated + // when consuming the result set (propagating output columns is done later, after the reader is closed). + // However, in MySQL, output parameters actually get returned as the result set, so we override and take care of that here. + var columnCount = ColumnModifications.Count; + + var readerIndex = -1; + + for (var columnIndex = 0; columnIndex < columnCount; columnIndex++) + { + var columnModification = ColumnModifications[columnIndex]; + + switch (columnModification.Column) + { + case IColumn when columnModification.IsRead: + case IStoreStoredProcedureParameter { Direction: ParameterDirection.Output or ParameterDirection.InputOutput }: + readerIndex++; + break; + + case IColumn: + case IStoreStoredProcedureParameter: + case null when columnModification.JsonPath is not null: + continue; + + default: + throw new ArgumentOutOfRangeException(); + } + + // For regular result sets, results are always propagated back into entity properties. + // But with stored procedures, there may be a rows affected result column (generated by an output parameter definition). + // Skip these. + if (columnModification.Property is null || + !columnModification.IsRead) + { + continue; + } + + columnModification.Value = + columnModification.Property.GetReaderFieldValue(relationalReader, readerIndex, _detailedErrorsEnabled); + } + } +} diff --git a/src/EFCore.MySql/Update/Internal/MySqlModificationCommandBatch.cs b/src/EFCore.MySql/Update/Internal/MySqlModificationCommandBatch.cs index bda59c080..b191378d7 100644 --- a/src/EFCore.MySql/Update/Internal/MySqlModificationCommandBatch.cs +++ b/src/EFCore.MySql/Update/Internal/MySqlModificationCommandBatch.cs @@ -1,202 +1,396 @@ -// Copyright (c) Pomelo Foundation. All rights reserved. +// Copyright (c) Pomelo Foundation. All rights reserved. // Licensed under the MIT. See LICENSE in the project root for license information. using System; using System.Collections.Generic; +using System.Data; +using System.Diagnostics; using System.Linq; -using System.Text; -using JetBrains.Annotations; +using System.Threading; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.Internal; -using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Update; +using Microsoft.EntityFrameworkCore.Utilities; +using Microsoft.EntityFrameworkCore.Storage; -namespace Pomelo.EntityFrameworkCore.MySql.Update.Internal +namespace Pomelo.EntityFrameworkCore.MySql.Update.Internal; + +/// +/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to +/// the same compatibility standards as public APIs. It may be changed or removed without notice in +/// any release. You should only use it directly in your code with extreme caution and knowing that +/// doing so can result in application failures when updating to a new Entity Framework Core release. +/// +public class MySqlModificationCommandBatch : AffectedCountModificationCommandBatch { - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - public class MySqlModificationCommandBatch : AffectedCountModificationCommandBatch + private readonly List _pendingBulkInsertCommands = new(); + + public MySqlModificationCommandBatch( + ModificationCommandBatchFactoryDependencies dependencies, + int maxBatchSize) + : base(dependencies, maxBatchSize) { - private const int DefaultNetworkPacketSizeBytes = 4096; - private const int MaxScriptLength = 65536 * DefaultNetworkPacketSizeBytes / 2; - private const int MaxParameterCount = 2100; - private const int MaxRowCount = 1000; - private int _parameterCount = 1; // Implicit parameter for the command text - private readonly int _maxBatchSize; - private readonly List _bulkInsertCommands = new List(); - private int _commandsLeftToLengthCheck = 50; - - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - public MySqlModificationCommandBatch( - [NotNull] ModificationCommandBatchFactoryDependencies dependencies, - int? maxBatchSize) - : base(dependencies) - { - if (maxBatchSize is <= 0) - { - throw new ArgumentOutOfRangeException(nameof(maxBatchSize), RelationalStrings.InvalidMaxBatchSize(maxBatchSize.Value)); - } + } + + protected new virtual IMySqlUpdateSqlGenerator UpdateSqlGenerator + => (IMySqlUpdateSqlGenerator)base.UpdateSqlGenerator; - _maxBatchSize = Math.Min(maxBatchSize ?? int.MaxValue, MaxRowCount); + protected override void RollbackLastCommand(IReadOnlyModificationCommand modificationCommand) + { + if (_pendingBulkInsertCommands.Count > 0) + { + _pendingBulkInsertCommands.RemoveAt(_pendingBulkInsertCommands.Count - 1); } - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - protected new virtual IMySqlUpdateSqlGenerator UpdateSqlGenerator => (IMySqlUpdateSqlGenerator)base.UpdateSqlGenerator; + ////// + // Pulled up from the base implementation to support our _pendingParameters field: + + for (var i = 0; i < _pendingParameters; i++) + { + var parameterIndex = RelationalCommandBuilder.Parameters.Count - 1; + var parameter = RelationalCommandBuilder.Parameters[parameterIndex]; + + RelationalCommandBuilder.RemoveParameterAt(parameterIndex); + ParameterValues.Remove(parameter.InvariantName); + } + + // + ////// + + base.RollbackLastCommand(modificationCommand); + } + + private void ApplyPendingBulkInsertCommands() + { + if (_pendingBulkInsertCommands.Count == 0) + { + return; + } + + var commandPosition = ResultSetMappings.Count; + + var wasCachedCommandTextEmpty = IsCommandTextEmpty; + + var resultSetMapping = UpdateSqlGenerator.AppendBulkInsertOperation( + SqlBuilder, _pendingBulkInsertCommands, commandPosition, out var requiresTransaction); + + SetRequiresTransaction(!wasCachedCommandTextEmpty || requiresTransaction); + + for (var i = 0; i < _pendingBulkInsertCommands.Count; i++) + { + ResultSetMappings.Add(resultSetMapping); + } - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// + if (resultSetMapping != ResultSetMapping.NoResults) + { + ResultSetMappings[^1] = ResultSetMapping.LastInResultSet; + } + } - protected override bool CanAddCommand(IReadOnlyModificationCommand modificationCommand) + protected override void AddCommand(IReadOnlyModificationCommand modificationCommand) + { + if (modificationCommand.EntityState == EntityState.Added && modificationCommand.StoreStoredProcedure is null) { - if (ModificationCommands.Count >= _maxBatchSize) + if (_pendingBulkInsertCommands.Count > 0 + && !CanBeInsertedInSameStatement(_pendingBulkInsertCommands[0], modificationCommand)) { - return false; + // The new Add command cannot be added to the pending bulk insert commands (e.g. different table). + // Write out the pending commands before starting a new pending chain. + ApplyPendingBulkInsertCommands(); + _pendingBulkInsertCommands.Clear(); } - var additionalParameterCount = CountParameters(modificationCommand); - - if (_parameterCount + additionalParameterCount >= MaxParameterCount) + _pendingBulkInsertCommands.Add(modificationCommand); + AddParameters(modificationCommand); + } + else + { + // If we have any pending bulk insert commands, write them out before the next non-Add command + if (_pendingBulkInsertCommands.Count > 0) { - return false; + // Note that we don't care about the transactionality of the bulk insert SQL, since there's the additional non-Add + // command coming right afterwards, and so a transaction is required in any case. + ApplyPendingBulkInsertCommands(); + _pendingBulkInsertCommands.Clear(); } - _parameterCount += additionalParameterCount; - return true; + base.AddCommand(modificationCommand); } + } + + private static bool CanBeInsertedInSameStatement( + IReadOnlyModificationCommand firstCommand, + IReadOnlyModificationCommand secondCommand) + => firstCommand.TableName == secondCommand.TableName + && firstCommand.Schema == secondCommand.Schema + && firstCommand.ColumnModifications.Where(o => o.IsWrite).Select(o => o.ColumnName).SequenceEqual( + secondCommand.ColumnModifications.Where(o => o.IsWrite).Select(o => o.ColumnName)) + && firstCommand.ColumnModifications.Where(o => o.IsRead).Select(o => o.ColumnName).SequenceEqual( + secondCommand.ColumnModifications.Where(o => o.IsRead).Select(o => o.ColumnName)); + + public override void Complete(bool moreBatchesExpected) + { + ApplyPendingBulkInsertCommands(); - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - protected override bool IsCommandTextValid() + base.Complete(moreBatchesExpected); + } + + /// + /// Consumes the data reader created by , + /// propagating values back into the . + /// + /// The ordinal of the first command being consumed. + /// The data reader. + /// The ordinal of the next result set that must be consumed. + protected override int ConsumeResultSet(int startCommandIndex, RelationalDataReader reader) + { + var commandIndex = startCommandIndex; + var rowsAffected = 0; + do { - if (--_commandsLeftToLengthCheck < 0) + if (!reader.Read()) { - var commandTextLength = GetCommandText().Length; - if (commandTextLength >= MaxScriptLength) + var expectedRowsAffected = rowsAffected + 1; + while (++commandIndex < ResultSetMappings.Count + && ResultSetMappings[commandIndex - 1].HasFlag(ResultSetMapping.NotLastInResultSet)) { - return false; + expectedRowsAffected++; } - var avarageCommandLength = commandTextLength / ModificationCommands.Count; - var expectedAdditionalCommandCapacity = (MaxScriptLength - commandTextLength) / avarageCommandLength; - _commandsLeftToLengthCheck = Math.Max(1, expectedAdditionalCommandCapacity / 4); + ThrowAggregateUpdateConcurrencyException(reader, commandIndex, expectedRowsAffected, rowsAffected); + } + else + { + var resultSetMapping = ResultSetMappings[commandIndex]; + + var command = ModificationCommands[ + resultSetMapping.HasFlag(ResultSetMapping.IsPositionalResultMappingEnabled) + ? startCommandIndex + reader.DbDataReader.GetInt32(reader.DbDataReader.FieldCount - 1) + : commandIndex]; + + Check.DebugAssert( + !resultSetMapping.HasFlag(ResultSetMapping.ResultSetWithRowsAffectedOnly), + "!resultSetMapping.HasFlag(ResultSetMapping.ResultSetWithRowsAffectedOnly)"); + + ////// + // Addition to base method: + ConsumeRowsAffectedFromResultSet(command, reader, commandIndex); + // + ////// + + command.PropagateResults(reader); } - return true; + rowsAffected++; } + while (++commandIndex < ResultSetMappings.Count + && ResultSetMappings[commandIndex - 1].HasFlag(ResultSetMapping.NotLastInResultSet)); - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - protected override int GetParameterCount() - => _parameterCount; + return commandIndex - 1; + } - private static int CountParameters(IReadOnlyModificationCommand modificationCommand) + /// + /// Consumes the data reader created by , + /// propagating values back into the . + /// + /// The ordinal of the first result set being consumed. + /// The data reader. + /// A to observe while waiting for the task to complete. + /// + /// A task that represents the asynchronous operation. + /// The task contains the ordinal of the next command that must be consumed. + /// + /// If the is canceled. + protected override async Task ConsumeResultSetAsync(int startCommandIndex, RelationalDataReader reader, CancellationToken cancellationToken) + { + var commandIndex = startCommandIndex; + var rowsAffected = 0; + do { - var parameterCount = 0; - foreach (var columnModification in modificationCommand.ColumnModifications) + if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { - if (columnModification.UseCurrentValueParameter) + var expectedRowsAffected = rowsAffected + 1; + while (++commandIndex < ResultSetMappings.Count + && ResultSetMappings[commandIndex - 1].HasFlag(ResultSetMapping.NotLastInResultSet)) { - parameterCount++; + expectedRowsAffected++; } - if (columnModification.UseOriginalValueParameter) - { - parameterCount++; - } + await ThrowAggregateUpdateConcurrencyExceptionAsync( + reader, commandIndex, expectedRowsAffected, rowsAffected, cancellationToken).ConfigureAwait(false); } + else + { + var resultSetMapping = ResultSetMappings[commandIndex]; - return parameterCount; - } + var command = ModificationCommands[ + resultSetMapping.HasFlag(ResultSetMapping.IsPositionalResultMappingEnabled) + ? startCommandIndex + reader.DbDataReader.GetInt32(reader.DbDataReader.FieldCount - 1) + : commandIndex]; - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - protected override void ResetCommandText() - { - base.ResetCommandText(); - _bulkInsertCommands.Clear(); + Check.DebugAssert( + !resultSetMapping.HasFlag(ResultSetMapping.ResultSetWithRowsAffectedOnly), + "!resultSetMapping.HasFlag(ResultSetMapping.ResultSetWithRowsAffectedOnly)"); + + ////// + // Addition to base method: + ConsumeRowsAffectedFromResultSet(command, reader, commandIndex); + // + ////// + + command.PropagateResults(reader); + } + + rowsAffected++; } + while (++commandIndex < ResultSetMappings.Count + && ResultSetMappings[commandIndex - 1].HasFlag(ResultSetMapping.NotLastInResultSet)); - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - protected override string GetCommandText() - => base.GetCommandText() + GetBulkInsertCommandText(ModificationCommands.Count); + return commandIndex - 1; + } - private string GetBulkInsertCommandText(int lastIndex) + protected virtual void ConsumeRowsAffectedFromResultSet( + IReadOnlyModificationCommand command, + RelationalDataReader reader, + int commandIndex) + { + if (command.StoreStoredProcedure is not null && + command.RowsAffectedColumn is { } rowsAffectedColumn) { - if (_bulkInsertCommands.Count == 0) - { - return string.Empty; - } + var rowsAffectedParameter = (IStoreStoredProcedureParameter)rowsAffectedColumn; + + Debug.Assert(rowsAffectedParameter.Direction == ParameterDirection.Output); + + var readerIndex = -1; - var stringBuilder = new StringBuilder(); - var resultSetMapping = UpdateSqlGenerator.AppendBulkInsertOperation(stringBuilder, _bulkInsertCommands, lastIndex - _bulkInsertCommands.Count); - for (var i = lastIndex - _bulkInsertCommands.Count; i < lastIndex; i++) + for (var i = 0; i < command.ColumnModifications.Count; i++) { - CommandResultSet[i] = resultSetMapping; + var columnModification = command.ColumnModifications[i]; + if (columnModification.Column is IStoreStoredProcedureParameter + { + Direction: ParameterDirection.Output or ParameterDirection.InputOutput + }) + { + readerIndex++; + } + + if (columnModification.Column == rowsAffectedColumn) + { + break; + } } - if (resultSetMapping != ResultSetMapping.NoResultSet) + if (reader.DbDataReader.GetInt32(readerIndex) != 1) { - CommandResultSet[lastIndex - 1] = ResultSetMapping.LastInResultSet; + ThrowAggregateUpdateConcurrencyException(reader, commandIndex + 1, 1, 0); } - - return stringBuilder.ToString(); } + } - /// - /// This API supports the Entity Framework Core infrastructure and is not intended to be used - /// directly from your code. This API may change or be removed in future releases. - /// - protected override void UpdateCachedCommandText(int commandPosition) + protected override void AddParameter(IColumnModification columnModification) + { + var direction = columnModification.Column switch { - var newModificationCommand = ModificationCommands[commandPosition]; + IStoreStoredProcedureParameter storedProcedureParameter => storedProcedureParameter.Direction, + IStoreStoredProcedureReturnValue => ParameterDirection.Output, + _ => ParameterDirection.Input + }; + + ////// + // Start of injected code. - if (newModificationCommand.EntityState == EntityState.Added) + // MySQL stored procedures cannot return a regular result set, and output parameter values are simply sent back as the + // result set; this is very different from SQL Server, where output parameter values can be sent back in addition to result + // sets. So we avoid adding MySqlParameters for output parameters - we'll just retrieve and propagate the values below when + // consuming the result set. + // Because MySqlConnector throws if we use an INOUT or OUT parameter for CommandType.Text commands, we skip + // ParameterDirection.Output parameters entirely and change ParameterDirection.InputOutput to ParameterDirection.Input. + if (columnModification.Column is IStoreStoredProcedureParameter parameter) + { + if (parameter.Direction.HasFlag(ParameterDirection.Output)) { - if (_bulkInsertCommands.Count > 0 - && !CanBeInsertedInSameStatement(_bulkInsertCommands[0], newModificationCommand)) + if (!parameter.Direction.HasFlag(ParameterDirection.Input)) { - CachedCommandText.Append(GetBulkInsertCommandText(commandPosition)); - _bulkInsertCommands.Clear(); + return; } - _bulkInsertCommands.Add(newModificationCommand); - LastCachedCommandIndex = commandPosition; - } - else - { - CachedCommandText.Append(GetBulkInsertCommandText(commandPosition)); - _bulkInsertCommands.Clear(); + direction = ParameterDirection.Input; + + var value = columnModification.UseCurrentValueParameter + ? columnModification.Value + : columnModification.UseOriginalValueParameter + ? columnModification.OriginalValue + : null; - base.UpdateCachedCommandText(commandPosition); + if (value is null) + { + return; + } } } - private static bool CanBeInsertedInSameStatement(IReadOnlyModificationCommand firstCommand, IReadOnlyModificationCommand secondCommand) - => string.Equals(firstCommand.TableName, secondCommand.TableName, StringComparison.Ordinal) - && string.Equals(firstCommand.Schema, secondCommand.Schema, StringComparison.Ordinal) - && firstCommand.ColumnModifications.Where(o => o.IsWrite).Select(o => o.ColumnName).SequenceEqual( - secondCommand.ColumnModifications.Where(o => o.IsWrite).Select(o => o.ColumnName)) - && firstCommand.ColumnModifications.Where(o => o.IsRead).Select(o => o.ColumnName).SequenceEqual( - secondCommand.ColumnModifications.Where(o => o.IsRead).Select(o => o.ColumnName)); + // End of injected code. + ////// + + // For the case where the same modification has both current and original value parameters, and corresponds to an in/out parameter, + // we only want to add a single parameter. This will happen below. + if (columnModification.UseCurrentValueParameter + && !(columnModification.UseOriginalValueParameter && direction == ParameterDirection.InputOutput)) + { + AddParameterCore( + columnModification.ParameterName, columnModification.UseCurrentValue + ? columnModification.Value + : direction == ParameterDirection.InputOutput + ? DBNull.Value + : null); + } + + if (columnModification.UseOriginalValueParameter) + { + Check.DebugAssert(direction.HasFlag(ParameterDirection.Input), "direction.HasFlag(ParameterDirection.Input)"); + + AddParameterCore(columnModification.OriginalParameterName, columnModification.OriginalValue); + } + + void AddParameterCore(string name, object value) + { + RelationalCommandBuilder.AddParameter( + name, + Dependencies.SqlGenerationHelper.GenerateParameterName(name), + columnModification.TypeMapping!, + columnModification.IsNullable, + direction); + + ParameterValues.Add(name, value); + + _pendingParameters++; + } } + + /// + /// We override this method only to support our _pendingParameters field. + /// + public override bool TryAddCommand(IReadOnlyModificationCommand modificationCommand) + { + if (StoreCommand is not null) + { + throw new InvalidOperationException(RelationalStrings.ModificationCommandBatchAlreadyComplete); + } + + if (ModificationCommands.Count >= MaxBatchSize) + { + return false; + } + + _pendingParameters = 0; + + return base.TryAddCommand(modificationCommand); + } + + /// + /// We use _pendingParameters only to support our AddParameter implementation. + /// + private int _pendingParameters; } diff --git a/src/EFCore.MySql/Update/Internal/MySqlModificationCommandBatchFactory.cs b/src/EFCore.MySql/Update/Internal/MySqlModificationCommandBatchFactory.cs index 7c789bcbf..50fdb7b7c 100644 --- a/src/EFCore.MySql/Update/Internal/MySqlModificationCommandBatchFactory.cs +++ b/src/EFCore.MySql/Update/Internal/MySqlModificationCommandBatchFactory.cs @@ -1,43 +1,54 @@ // Copyright (c) Pomelo Foundation. All rights reserved. // Licensed under the MIT. See LICENSE in the project root for license information. +using System; using System.Linq; using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; -using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Update; -using Microsoft.EntityFrameworkCore.Utilities; -namespace Pomelo.EntityFrameworkCore.MySql.Update.Internal +namespace Pomelo.EntityFrameworkCore.MySql.Update.Internal; + +public class MySqlModificationCommandBatchFactory : IModificationCommandBatchFactory { - public class MySqlModificationCommandBatchFactory : IModificationCommandBatchFactory - { - private readonly ModificationCommandBatchFactoryDependencies _dependencies; - private readonly IDbContextOptions _options; + private const int DefaultMaxBatchSize = 42; + private const int MaxMaxBatchSize = 1000; + private readonly int _maxBatchSize; - public MySqlModificationCommandBatchFactory( - [NotNull] ModificationCommandBatchFactoryDependencies dependencies, - [NotNull] IDbContextOptions options) - { - Check.NotNull(dependencies, nameof(dependencies)); - Check.NotNull(options, nameof(options)); + /// + /// 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 MySqlModificationCommandBatchFactory(ModificationCommandBatchFactoryDependencies dependencies, + IDbContextOptions options) + { + Dependencies = dependencies; - _dependencies = dependencies; - _options = options; - } + _maxBatchSize = Math.Min( + options.Extensions.OfType().FirstOrDefault()?.MaxBatchSize ?? DefaultMaxBatchSize, + MaxMaxBatchSize); - /// - /// 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 virtual ModificationCommandBatch Create() + if (_maxBatchSize <= 0) { - var optionsExtension = _options.Extensions.OfType().FirstOrDefault(); - - return new MySqlModificationCommandBatch(_dependencies, optionsExtension?.MaxBatchSize); + throw new ArgumentOutOfRangeException( + nameof(RelationalOptionsExtension.MaxBatchSize), RelationalStrings.InvalidMaxBatchSize(_maxBatchSize)); } } + + /// + /// Relational provider-specific dependencies for this service. + /// + protected virtual ModificationCommandBatchFactoryDependencies Dependencies { get; } + + /// + /// 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 virtual ModificationCommandBatch Create() + => new MySqlModificationCommandBatch(Dependencies, _maxBatchSize); } diff --git a/src/EFCore.MySql/Update/Internal/MySqlModificationCommandFactory.cs b/src/EFCore.MySql/Update/Internal/MySqlModificationCommandFactory.cs new file mode 100644 index 000000000..275b62454 --- /dev/null +++ b/src/EFCore.MySql/Update/Internal/MySqlModificationCommandFactory.cs @@ -0,0 +1,17 @@ +// Copyright (c) Pomelo Foundation. All rights reserved. +// Licensed under the MIT. See LICENSE in the project root for license information. + +using Microsoft.EntityFrameworkCore.Update; + +namespace Pomelo.EntityFrameworkCore.MySql.Update.Internal; + +public class MySqlModificationCommandFactory : IModificationCommandFactory +{ + public virtual IModificationCommand CreateModificationCommand( + in ModificationCommandParameters modificationCommandParameters) + => new MySqlModificationCommand(modificationCommandParameters); + + public virtual INonTrackedModificationCommand CreateNonTrackedModificationCommand( + in NonTrackedModificationCommandParameters modificationCommandParameters) + => new MySqlModificationCommand(modificationCommandParameters); +} diff --git a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs index 1c8d31b0e..20fd1ec24 100644 --- a/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs +++ b/src/EFCore.MySql/Update/Internal/MySqlUpdateSqlGenerator.cs @@ -2,7 +2,7 @@ // Licensed under the MIT. See LICENSE in the project root for license information. using System.Collections.Generic; -using System.Diagnostics; +using System.Data; using System.Globalization; using System.Linq; using System.Text; @@ -11,96 +11,67 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Update; using Microsoft.EntityFrameworkCore.Utilities; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; namespace Pomelo.EntityFrameworkCore.MySql.Update.Internal { - // TODO: Revamp - public class MySqlUpdateSqlGenerator : UpdateSqlGenerator, IMySqlUpdateSqlGenerator + public class MySqlUpdateSqlGenerator : UpdateAndSelectSqlGenerator, IMySqlUpdateSqlGenerator { - /// - /// 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. - /// + [NotNull] private readonly IMySqlOptions _options; + public MySqlUpdateSqlGenerator( - [NotNull] UpdateSqlGeneratorDependencies dependencies) + [NotNull] UpdateSqlGeneratorDependencies dependencies, + [NotNull] IMySqlOptions options) : base(dependencies) { + _options = options; } - /// - /// 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 ResultSetMapping AppendInsertOperation( + StringBuilder commandStringBuilder, + IReadOnlyModificationCommand command, + int commandPosition, + out bool requiresTransaction) + => _options.ServerVersion.Supports.Returning || + command.ColumnModifications.All(o => !o.IsRead) + ? AppendInsertReturningOperation(commandStringBuilder, command, commandPosition, out requiresTransaction) + : base.AppendInsertOperation(commandStringBuilder, command, commandPosition, out requiresTransaction); + public virtual ResultSetMapping AppendBulkInsertOperation( StringBuilder commandStringBuilder, IReadOnlyList modificationCommands, - int commandPosition) + int commandPosition, + out bool requiresTransaction) { - var table = StoreObjectIdentifier.Table(modificationCommands[0].TableName, modificationCommands[0].Schema); - - if (modificationCommands.Count == 1 - && modificationCommands[0].ColumnModifications.All(o => - !o.IsKey - || !o.IsRead - || o.Property?.GetValueGenerationStrategy(table) == MySqlValueGenerationStrategy.IdentityColumn)) + if (modificationCommands.Count == 1) { - return AppendInsertOperation(commandStringBuilder, modificationCommands[0], commandPosition); + return AppendInsertOperation(commandStringBuilder, modificationCommands[0], commandPosition, out requiresTransaction); } var readOperations = modificationCommands[0].ColumnModifications.Where(o => o.IsRead).ToList(); var writeOperations = modificationCommands[0].ColumnModifications.Where(o => o.IsWrite).ToList(); - var keyOperations = modificationCommands[0].ColumnModifications.Where(o => o.IsKey).ToList(); - - var nonIdentityOperations = modificationCommands[0].ColumnModifications - .Where(o => o.Property?.GetValueGenerationStrategy(table) != MySqlValueGenerationStrategy.IdentityColumn) - .ToList(); - - var defaultValuesOnly = writeOperations.Count == 0; - if (defaultValuesOnly) - { - if (nonIdentityOperations.Count == 0 - || readOperations.Count == 0) - { - foreach (var modification in modificationCommands) - { - AppendInsertOperation(commandStringBuilder, modification, commandPosition); - } - - return readOperations.Count == 0 - ? ResultSetMapping.NoResultSet - : ResultSetMapping.LastInResultSet; - } - - if (nonIdentityOperations.Count > 1) - { - nonIdentityOperations = new List { nonIdentityOperations.First() }; - } - } if (readOperations.Count == 0) { - return AppendBulkInsertWithoutServerValues(commandStringBuilder, modificationCommands, writeOperations); + return AppendInsertMultipleRowsInSingleStatementOperation(commandStringBuilder, modificationCommands, writeOperations, out requiresTransaction); } + requiresTransaction = modificationCommands.Count > 1; foreach (var modification in modificationCommands) { - AppendInsertOperation(commandStringBuilder, modification, commandPosition); + AppendInsertOperation(commandStringBuilder, modification, commandPosition, out var localRequiresTransaction); + requiresTransaction = requiresTransaction || localRequiresTransaction; } return ResultSetMapping.LastInResultSet; } - private ResultSetMapping AppendBulkInsertWithoutServerValues( + private ResultSetMapping AppendInsertMultipleRowsInSingleStatementOperation( StringBuilder commandStringBuilder, IReadOnlyList modificationCommands, - List writeOperations) + List writeOperations, + out bool requiresTransaction) { - Debug.Assert(writeOperations.Count > 0); - var name = modificationCommands[0].TableName; var schema = modificationCommands[0].Schema; @@ -114,7 +85,10 @@ private ResultSetMapping AppendBulkInsertWithoutServerValues( } commandStringBuilder.Append(SqlGenerationHelper.StatementTerminator).AppendLine(); - return ResultSetMapping.NoResultSet; + // A single INSERT command should run atomically, regardless of how many value lists it contains. + requiresTransaction = false; + + return ResultSetMapping.NoResults; } protected override void AppendInsertCommandHeader( @@ -162,6 +136,14 @@ protected override void AppendValues( } } + public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStringBuilder, + IReadOnlyModificationCommand command, + int commandPosition, + out bool requiresTransaction) + => _options.ServerVersion.Supports.Returning + ? AppendDeleteReturningOperation(commandStringBuilder, command, commandPosition, out requiresTransaction) + : base.AppendDeleteOperation(commandStringBuilder, command, commandPosition, out requiresTransaction); + protected override ResultSetMapping AppendSelectAffectedCountCommand(StringBuilder commandStringBuilder, string name, string schema, int commandPosition) { commandStringBuilder @@ -169,36 +151,7 @@ protected override ResultSetMapping AppendSelectAffectedCountCommand(StringBuild .Append(SqlGenerationHelper.StatementTerminator).AppendLine() .AppendLine(); - return ResultSetMapping.LastInResultSet; - } - - protected override void AppendWhereAffectedClause( - StringBuilder commandStringBuilder, - IReadOnlyList operations) - { - Check.NotNull(commandStringBuilder, nameof(commandStringBuilder)); - Check.NotNull(operations, nameof(operations)); - - // If a compound key consists of an auto_increment column and a database generated column (e.g. a DEFAULT - // value), then we only want to filter by `LAST_INSERT_ID()`, because we can't know what the other generated - // values are. - // Therefore, we filter out the key columns that are marked as `read`, but are not an auto_increment column, - // so that `AppendIdentityWhereCondition()` can safely called for the remaining auto_increment column. - // Because we currently use `MySqlValueGenerationStrategy.IdentityColumn` for auto_increment columns as well - // as CURRENT_TIMESTAMP columns, we need to use `MySqlPropertyExtensions.IsCompatibleAutoIncrementColumn()` - // to ensure, that the column is actually an auto_increment column. - // See https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/1300 - var nonDefaultOperations = operations - .Where( - o => !o.IsKey || - !o.IsRead || - o.Property == null || - !o.Property.ValueGenerated.HasFlag(ValueGenerated.OnAdd) || - MySqlPropertyExtensions.IsCompatibleAutoIncrementColumn(o.Property)) - .ToList() - .AsReadOnly(); - - base.AppendWhereAffectedClause(commandStringBuilder, nonDefaultOperations); + return ResultSetMapping.LastInResultSet | ResultSetMapping.ResultSetWithRowsAffectedOnly; } protected override void AppendIdentityWhereCondition(StringBuilder commandStringBuilder, IColumnModification columnModification) @@ -212,5 +165,197 @@ protected override void AppendRowsAffectedWhereCondition(StringBuilder commandSt => commandStringBuilder .Append("ROW_COUNT() = ") .Append(expectedRowsAffected.ToString(CultureInfo.InvariantCulture)); + + public override ResultSetMapping AppendStoredProcedureCall( + StringBuilder commandStringBuilder, + IReadOnlyModificationCommand command, + int commandPosition, + out bool requiresTransaction) + { + Check.DebugAssert(command.StoreStoredProcedure is not null, "command.StoreStoredProcedure is not null"); + + var storedProcedure = command.StoreStoredProcedure; + + Check.DebugAssert(storedProcedure.Parameters.Any(), "Stored procedure call without parameters"); + + var resultSetMapping = ResultSetMapping.NoResults; + + // IN parameters will get injected directly into the argument list of the CALL statement. + // FOR INOUT or OUT parameters, we will declare variables. + // For OUT parameters, we initialize those variables to NUll. + // For IN parameters, we initialize those variables with their corresponding parameter of the command that executes the CALL + // statement. + for (var i = 0; i < command.ColumnModifications.Count; i++) + { + var columnModification = command.ColumnModifications[i]; + var parameter = (IStoreStoredProcedureParameter)columnModification.Column!; + + // MySQL stored procedures cannot return a regular result set, and output parameter values are simply sent back to us as the + // result set, if we append a SELECT query for them. This is very different from SQL Server, where output parameter values + // can be sent back in addition to result sets. + if (!parameter.Direction.HasFlag(ParameterDirection.Output)) + { + continue; + } + + // The distinction between having only a rows affected output parameter and having other non-rows affected parameters + // is important later on (i.e. whether we need to propagate or not). + resultSetMapping = parameter == command.RowsAffectedColumn && + resultSetMapping == ResultSetMapping.NoResults + ? ResultSetMapping.ResultSetWithRowsAffectedOnly | ResultSetMapping.LastInResultSet + : ResultSetMapping.LastInResultSet; + + commandStringBuilder.Append("SET "); + + var commandParameterName = columnModification.UseOriginalValueParameter + ? columnModification.OriginalParameterName! + : columnModification.ParameterName!; + + var procedureCallParameterName = GetProcedureCallOutParameterVariableName(commandParameterName); + + SqlGenerationHelper.GenerateParameterNamePlaceholder(commandStringBuilder, procedureCallParameterName); + + commandStringBuilder.Append(" = "); + + if (parameter.Direction.HasFlag(ParameterDirection.Input)) + { + SqlGenerationHelper.GenerateParameterNamePlaceholder(commandStringBuilder, commandParameterName); + } + else + { + commandStringBuilder.Append("NULL"); + } + + commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator); + } + + commandStringBuilder.Append("CALL "); + + // MySQL supports neither a return value nor a result set that gets returned from inside of a stored procedures. It only + // supports output parameters to propagate values back to the caller. + Check.DebugAssert(storedProcedure.ReturnValue is null, "storedProcedure.Return is null"); + Check.DebugAssert(!storedProcedure.ResultColumns.Any(), "!storedProcedure.ResultColumns.Any()"); + + SqlGenerationHelper.DelimitIdentifier(commandStringBuilder, storedProcedure.Name, storedProcedure.Schema); + + commandStringBuilder.Append('('); + + // Only positional parameter style supported for now, see https://github.com/dotnet/efcore/issues/28439 + + // Note: the column modifications are already ordered according to the sproc parameter ordering + // (see ModificationCommand.GenerateColumnModifications) + for (var i = 0; i < command.ColumnModifications.Count; i++) + { + var columnModification = command.ColumnModifications[i]; + var parameter = (IStoreStoredProcedureParameter)columnModification.Column!; + + if (i > 0) + { + commandStringBuilder.Append(", "); + } + + Check.DebugAssert(columnModification.UseParameter, "Column modification matched a parameter, but UseParameter is false"); + + var commandParameterName = columnModification.UseOriginalValueParameter + ? columnModification.OriginalParameterName! + : columnModification.ParameterName!; + + var procedureCallParameterName = GetProcedureCallOutParameterVariableName(commandParameterName); + + SqlGenerationHelper.GenerateParameterNamePlaceholder( + commandStringBuilder, + parameter.Direction.HasFlag(ParameterDirection.Output) + ? procedureCallParameterName + : commandParameterName); + } + + commandStringBuilder.Append(')'); + commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator); + + // The CALL has propagated any INOUT and OUT values back into our previously declared variables. + // To get those values back to the caller, we need to run a SELECT statement against those variables. + // We start by checking, whether there exist any INOUT or OUT parameters. + if (resultSetMapping != ResultSetMapping.NoResults) + { + commandStringBuilder.Append("SELECT "); + + var first = true; + + for (var i = 0; i < command.ColumnModifications.Count; i++) + { + var columnModification = command.ColumnModifications[i]; + var parameter = (IStoreStoredProcedureParameter)columnModification.Column!; + + if (!parameter.Direction.HasFlag(ParameterDirection.Output)) + { + continue; + } + + if (first) + { + first = false; + } + else + { + commandStringBuilder.Append(", "); + } + + var commandParameterName = columnModification.UseOriginalValueParameter + ? columnModification.OriginalParameterName! + : columnModification.ParameterName!; + + var procedureCallParameterName = GetProcedureCallOutParameterVariableName(commandParameterName); + + SqlGenerationHelper.GenerateParameterNamePlaceholder( + commandStringBuilder, + procedureCallParameterName); + } + + commandStringBuilder.AppendLine(SqlGenerationHelper.StatementTerminator); + } + + requiresTransaction = true; + + return resultSetMapping; + } + + /// + /// Returns the name (without the @ prefix) used for any temporary user variables, that need to be declared to get values out of a + /// stored procedure. + /// + /// The name of the parameter of the command that executes the CALL statement. + /// The variable name (without the @ prefix). + protected virtual string GetProcedureCallOutParameterVariableName(string commandParameterName) + => "_out_" + commandParameterName; + + protected override bool IsIdentityOperation(IColumnModification modification) + { + var isIdentityOperation = base.IsIdentityOperation(modification); + + if (isIdentityOperation && + modification.Property is { } property) + { + var (tableName, schema) = GetTableNameAndSchema(modification, property); + var storeObject = StoreObjectIdentifier.Table(tableName, schema); + + return property.GetValueGenerationStrategy(storeObject) is MySqlValueGenerationStrategy.IdentityColumn; + } + + return isIdentityOperation; + } + + private static (string tableName, string schema) GetTableNameAndSchema(IColumnModification modification, IProperty property) + { + if (modification.Column?.Table is { } table) + { + return (table.Name, table.Schema); + } + else + { + // CHECK: Is this branch ever hit and then returns something different than null, or can we just rely on + // `modification.Column?.Table`? + return (property.DeclaringEntityType.GetTableName(), property.DeclaringEntityType.GetSchema()); + } + } } } diff --git a/test/EFCore.MySql.FunctionalTests/BuiltInDataTypesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BuiltInDataTypesMySqlTest.cs index bc1b4d9a7..a37332407 100644 --- a/test/EFCore.MySql.FunctionalTests/BuiltInDataTypesMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/BuiltInDataTypesMySqlTest.cs @@ -723,7 +723,7 @@ private static void AssertMappedNullableDataTypes(MappedNullableDataTypes entity Assert.Equal(81.1m, entity.DecimalAsDecimal); Assert.Equal(82.2m, entity.DecimalAsFixed); Assert.Equal(83.3, entity.DoubleAsReal.Value, 1); - Assert.Equal(84.4f, entity.FloatAsFloat.Value, 1); + Assert.Equal(84.4f, entity.FloatAsFloat.Value, 0.1f); Assert.Equal(85.5, entity.DoubleAsDoublePrecision.Value, 1); Assert.Equal(new DateTime(2015, 1, 2), entity.DateTimeAsDate); Assert.Equal(new DateTimeOffset(new DateTime(2016, 1, 2, 11, 11, 12), TimeSpan.Zero), entity.DateTimeOffsetAsDatetime); @@ -873,6 +873,84 @@ public virtual void Can_insert_and_read_back_all_mapped_data_types_set_to_null() } } + // Overridden because of TestNullableDateTimeOffset, since MySQL does not offer a native data type to save a date/time with + // timezone. + public override void Can_insert_and_read_back_all_nullable_data_types_with_values_set_to_non_null() + { + using (var context = CreateContext()) + { + context.Set().Add( + new BuiltInNullableDataTypes + { + Id = 101, + PartitionId = 101, + TestString = "TestString", + TestByteArray = new byte[] { 10, 9, 8, 7, 6 }, + TestNullableInt16 = -1234, + TestNullableInt32 = -123456789, + TestNullableInt64 = -1234567890123456789L, + TestNullableDouble = -1.23456789, + TestNullableDecimal = -1234567890.01M, + TestNullableDateTime = DateTime.Parse("01/01/2000 12:34:56").ToUniversalTime(), + TestNullableDateTimeOffset = new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)), + TestNullableTimeSpan = new TimeSpan(0, 10, 9, 8, 7), + TestNullableSingle = -1.234F, + TestNullableBoolean = false, + TestNullableByte = 255, + TestNullableUnsignedInt16 = 1234, + TestNullableUnsignedInt32 = 1234565789U, + TestNullableUnsignedInt64 = 1234567890123456789UL, + TestNullableCharacter = 'a', + TestNullableSignedByte = -128, + Enum64 = Enum64.SomeValue, + Enum32 = Enum32.SomeValue, + Enum16 = Enum16.SomeValue, + Enum8 = Enum8.SomeValue, + EnumU64 = EnumU64.SomeValue, + EnumU32 = EnumU32.SomeValue, + EnumU16 = EnumU16.SomeValue, + EnumS8 = EnumS8.SomeValue + }); + + Assert.Equal(1, context.SaveChanges()); + } + + using (var context = CreateContext()) + { + var dt = context.Set().Where(ndt => ndt.Id == 101).ToList().Single(); + + var entityType = context.Model.FindEntityType(typeof(BuiltInNullableDataTypes)); + AssertEqualIfMapped(entityType, "TestString", () => dt.TestString); + AssertEqualIfMapped(entityType, new byte[] { 10, 9, 8, 7, 6 }, () => dt.TestByteArray); + AssertEqualIfMapped(entityType, (short)-1234, () => dt.TestNullableInt16); + AssertEqualIfMapped(entityType, -123456789, () => dt.TestNullableInt32); + AssertEqualIfMapped(entityType, -1234567890123456789L, () => dt.TestNullableInt64); + AssertEqualIfMapped(entityType, -1.23456789, () => dt.TestNullableDouble); + AssertEqualIfMapped(entityType, -1234567890.01M, () => dt.TestNullableDecimal); + AssertEqualIfMapped(entityType, DateTime.Parse("01/01/2000 12:34:56").ToUniversalTime(), () => dt.TestNullableDateTime); + AssertEqualIfMapped( + entityType, new DateTimeOffset(DateTime.Parse("01/01/2000 12:34:56"), TimeSpan.FromHours(-8.0)).ToUniversalTime(), // adjusted for Pomelo's translation + () => dt.TestNullableDateTimeOffset); + AssertEqualIfMapped(entityType, new TimeSpan(0, 10, 9, 8, 7), () => dt.TestNullableTimeSpan); + AssertEqualIfMapped(entityType, -1.234F, () => dt.TestNullableSingle); + AssertEqualIfMapped(entityType, false, () => dt.TestNullableBoolean); + AssertEqualIfMapped(entityType, (byte)255, () => dt.TestNullableByte); + AssertEqualIfMapped(entityType, Enum64.SomeValue, () => dt.Enum64); + AssertEqualIfMapped(entityType, Enum32.SomeValue, () => dt.Enum32); + AssertEqualIfMapped(entityType, Enum16.SomeValue, () => dt.Enum16); + AssertEqualIfMapped(entityType, Enum8.SomeValue, () => dt.Enum8); + AssertEqualIfMapped(entityType, (ushort)1234, () => dt.TestNullableUnsignedInt16); + AssertEqualIfMapped(entityType, 1234565789U, () => dt.TestNullableUnsignedInt32); + AssertEqualIfMapped(entityType, 1234567890123456789UL, () => dt.TestNullableUnsignedInt64); + AssertEqualIfMapped(entityType, 'a', () => dt.TestNullableCharacter); + AssertEqualIfMapped(entityType, (sbyte)-128, () => dt.TestNullableSignedByte); + AssertEqualIfMapped(entityType, EnumU64.SomeValue, () => dt.EnumU64); + AssertEqualIfMapped(entityType, EnumU32.SomeValue, () => dt.EnumU32); + AssertEqualIfMapped(entityType, EnumU16.SomeValue, () => dt.EnumU16); + AssertEqualIfMapped(entityType, EnumS8.SomeValue, () => dt.EnumS8); + } + } + private static void AssertNullMappedNullableDataTypes(MappedNullableDataTypes entity, int id) { Assert.Equal(id, entity.Int); diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/FiltersInheritanceBulkUpdatesMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/FiltersInheritanceBulkUpdatesMySqlFixture.cs new file mode 100644 index 000000000..aa5e22242 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/FiltersInheritanceBulkUpdatesMySqlFixture.cs @@ -0,0 +1,10 @@ +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class FiltersInheritanceBulkUpdatesMySqlFixture : InheritanceBulkUpdatesMySqlFixture +{ + protected override string StoreName + => "FiltersInheritanceBulkUpdatesTest"; + + protected override bool EnableFilters + => true; +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/FiltersInheritanceBulkUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/FiltersInheritanceBulkUpdatesMySqlTest.cs new file mode 100644 index 000000000..f08b7ef21 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/FiltersInheritanceBulkUpdatesMySqlTest.cs @@ -0,0 +1,222 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using MySqlConnector; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class FiltersInheritanceBulkUpdatesMySqlTest : FiltersInheritanceBulkUpdatesTestBase< + FiltersInheritanceBulkUpdatesMySqlFixture> +{ + public FiltersInheritanceBulkUpdatesMySqlTest(FiltersInheritanceBulkUpdatesMySqlFixture fixture) + : base(fixture) + { + ClearLog(); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Delete_where_hierarchy(bool async) + { + await base.Delete_where_hierarchy(async); + + AssertSql( +""" +DELETE `a` +FROM `Animals` AS `a` +WHERE (`a`.`CountryId` = 1) AND (`a`.`Name` = 'Great spotted kiwi') +"""); + } + + public override async Task Delete_where_hierarchy_derived(bool async) + { + await base.Delete_where_hierarchy_derived(async); + + AssertSql( +""" +DELETE `a` +FROM `Animals` AS `a` +WHERE ((`a`.`Discriminator` = 'Kiwi') AND (`a`.`CountryId` = 1)) AND (`a`.`Name` = 'Great spotted kiwi') +"""); + } + + public override async Task Delete_where_using_hierarchy(bool async) + { + await base.Delete_where_using_hierarchy(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + WHERE ((`a`.`CountryId` = 1) AND (`c`.`Id` = `a`.`CountryId`)) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_where_using_hierarchy_derived(bool async) + { + await base.Delete_where_using_hierarchy_derived(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + WHERE (((`a`.`CountryId` = 1) AND (`c`.`Id` = `a`.`CountryId`)) AND (`a`.`Discriminator` = 'Kiwi')) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_GroupBy_Where_Select_First(bool async) + { + await base.Delete_GroupBy_Where_Select_First(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_2(bool async) + { + await base.Delete_GroupBy_Where_Select_First_2(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_3(bool async) + { + // Not supported by MySQL: + // Error Code: 1093. You can't specify target table 'c' for update in FROM clause + await Assert.ThrowsAsync( + () => base.Delete_GroupBy_Where_Select_First_3(async)); + + AssertSql( +""" +DELETE `a` +FROM `Animals` AS `a` +WHERE (`a`.`CountryId` = 1) AND EXISTS ( + SELECT 1 + FROM `Animals` AS `a0` + WHERE `a0`.`CountryId` = 1 + GROUP BY `a0`.`CountryId` + HAVING (COUNT(*) < 3) AND (( + SELECT `a1`.`Id` + FROM `Animals` AS `a1` + WHERE (`a1`.`CountryId` = 1) AND (`a0`.`CountryId` = `a1`.`CountryId`) + LIMIT 1) = `a`.`Id`)) +""" +); + } + + public override async Task Delete_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Delete_where_keyless_entity_mapped_to_sql_query(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_subquery(bool async) + { + await base.Delete_where_hierarchy_subquery(async); + + AssertSql( +""" +@__p_1='3' +@__p_0='0' + +DELETE `a` +FROM `Animals` AS `a` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `a0`.`Id`, `a0`.`CountryId`, `a0`.`Discriminator`, `a0`.`Name`, `a0`.`Species`, `a0`.`EagleId`, `a0`.`IsFlightless`, `a0`.`Group`, `a0`.`FoundOn` + FROM `Animals` AS `a0` + WHERE (`a0`.`CountryId` = 1) AND (`a0`.`Name` = 'Great spotted kiwi') + ORDER BY `a0`.`Name` + LIMIT @__p_1 OFFSET @__p_0 + ) AS `t` + WHERE `t`.`Id` = `a`.`Id`) +"""); + } + + public override async Task Update_where_hierarchy(bool async) + { + await base.Update_where_hierarchy(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Animals` AS `a` +SET `a`.`Name` = 'Animal' +WHERE (`a`.`CountryId` = 1) AND (`a`.`Name` = 'Great spotted kiwi') +"""); + } + + public override async Task Update_where_hierarchy_subquery(bool async) + { + await base.Update_where_hierarchy_subquery(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_derived(bool async) + { + await base.Update_where_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Animals` AS `a` +SET `a`.`Name` = 'Kiwi' +WHERE ((`a`.`Discriminator` = 'Kiwi') AND (`a`.`CountryId` = 1)) AND (`a`.`Name` = 'Great spotted kiwi') +"""); + } + + public override async Task Update_where_using_hierarchy(bool async) + { + await base.Update_where_using_hierarchy(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + WHERE ((`a`.`CountryId` = 1) AND (`c`.`Id` = `a`.`CountryId`)) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_using_hierarchy_derived(bool async) + { + await base.Update_where_using_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + WHERE (((`a`.`CountryId` = 1) AND (`c`.`Id` = `a`.`CountryId`)) AND (`a`.`Discriminator` = 'Kiwi')) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Update_where_keyless_entity_mapped_to_sql_query(async); + + AssertExecuteUpdateSql(); + } + + protected override void ClearLog() + => Fixture.TestSqlLoggerFactory.Clear(); + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + private void AssertExecuteUpdateSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/InheritanceBulkUpdatesMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/InheritanceBulkUpdatesMySqlFixture.cs new file mode 100644 index 000000000..2b395c574 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/InheritanceBulkUpdatesMySqlFixture.cs @@ -0,0 +1,11 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class InheritanceBulkUpdatesMySqlFixture : InheritanceBulkUpdatesRelationalFixture +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/InheritanceBulkUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/InheritanceBulkUpdatesMySqlTest.cs new file mode 100644 index 000000000..dead015ea --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/InheritanceBulkUpdatesMySqlTest.cs @@ -0,0 +1,219 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using MySqlConnector; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class InheritanceBulkUpdatesMySqlTest : InheritanceBulkUpdatesTestBase +{ + public InheritanceBulkUpdatesMySqlTest(InheritanceBulkUpdatesMySqlFixture fixture) + : base(fixture) + { + ClearLog(); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Delete_where_hierarchy(bool async) + { + await base.Delete_where_hierarchy(async); + + AssertSql( +""" +DELETE `a` +FROM `Animals` AS `a` +WHERE `a`.`Name` = 'Great spotted kiwi' +"""); + } + + public override async Task Delete_where_hierarchy_derived(bool async) + { + await base.Delete_where_hierarchy_derived(async); + + AssertSql( +""" +DELETE `a` +FROM `Animals` AS `a` +WHERE (`a`.`Discriminator` = 'Kiwi') AND (`a`.`Name` = 'Great spotted kiwi') +"""); + } + + public override async Task Delete_where_using_hierarchy(bool async) + { + await base.Delete_where_using_hierarchy(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + WHERE (`c`.`Id` = `a`.`CountryId`) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_where_using_hierarchy_derived(bool async) + { + await base.Delete_where_using_hierarchy_derived(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + WHERE ((`c`.`Id` = `a`.`CountryId`) AND (`a`.`Discriminator` = 'Kiwi')) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_GroupBy_Where_Select_First(bool async) + { + await base.Delete_GroupBy_Where_Select_First(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_2(bool async) + { + await base.Delete_GroupBy_Where_Select_First_2(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_3(bool async) + { + // Not supported by MySQL: + // Error Code: 1093. You can't specify target table 'c' for update in FROM clause + await Assert.ThrowsAsync( + () => base.Delete_GroupBy_Where_Select_First_3(async)); + + AssertSql( +""" +DELETE `a` +FROM `Animals` AS `a` +WHERE EXISTS ( + SELECT 1 + FROM `Animals` AS `a0` + GROUP BY `a0`.`CountryId` + HAVING (COUNT(*) < 3) AND (( + SELECT `a1`.`Id` + FROM `Animals` AS `a1` + WHERE `a0`.`CountryId` = `a1`.`CountryId` + LIMIT 1) = `a`.`Id`)) +"""); + } + + public override async Task Delete_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Delete_where_keyless_entity_mapped_to_sql_query(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_subquery(bool async) + { + await base.Delete_where_hierarchy_subquery(async); + + AssertSql( +""" +@__p_1='3' +@__p_0='0' + +DELETE `a` +FROM `Animals` AS `a` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `a0`.`Id`, `a0`.`CountryId`, `a0`.`Discriminator`, `a0`.`Name`, `a0`.`Species`, `a0`.`EagleId`, `a0`.`IsFlightless`, `a0`.`Group`, `a0`.`FoundOn` + FROM `Animals` AS `a0` + WHERE `a0`.`Name` = 'Great spotted kiwi' + ORDER BY `a0`.`Name` + LIMIT @__p_1 OFFSET @__p_0 + ) AS `t` + WHERE `t`.`Id` = `a`.`Id`) +"""); + } + + public override async Task Update_where_hierarchy(bool async) + { + await base.Update_where_hierarchy(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Animals` AS `a` +SET `a`.`Name` = 'Animal' +WHERE `a`.`Name` = 'Great spotted kiwi' +"""); + } + + public override async Task Update_where_hierarchy_subquery(bool async) + { + await base.Update_where_hierarchy_subquery(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_derived(bool async) + { + await base.Update_where_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Animals` AS `a` +SET `a`.`Name` = 'Kiwi' +WHERE (`a`.`Discriminator` = 'Kiwi') AND (`a`.`Name` = 'Great spotted kiwi') +"""); + } + + public override async Task Update_where_using_hierarchy(bool async) + { + await base.Update_where_using_hierarchy(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + WHERE (`c`.`Id` = `a`.`CountryId`) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_using_hierarchy_derived(bool async) + { + await base.Update_where_using_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + WHERE ((`c`.`Id` = `a`.`CountryId`) AND (`a`.`Discriminator` = 'Kiwi')) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Update_where_keyless_entity_mapped_to_sql_query(async); + + AssertExecuteUpdateSql(); + } + + protected override void ClearLog() + => Fixture.TestSqlLoggerFactory.Clear(); + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + private void AssertExecuteUpdateSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesMySqlTest.cs new file mode 100644 index 000000000..df9c72c19 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/NonSharedModelBulkUpdatesMySqlTest.cs @@ -0,0 +1,65 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class NonSharedModelBulkUpdatesMySqlTest : NonSharedModelBulkUpdatesTestBase +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Delete_aggregate_root_when_eager_loaded_owned_collection(bool async) + { + await base.Delete_aggregate_root_when_eager_loaded_owned_collection(async); + + AssertSql( +""" +DELETE `o` +FROM `Owner` AS `o` +"""); + } + + public override async Task Delete_aggregate_root_when_table_sharing_with_owned(bool async) + { + await base.Delete_aggregate_root_when_table_sharing_with_owned(async); + + AssertSql( +""" +DELETE `o` +FROM `Owner` AS `o` +"""); + } + + public override async Task Delete_aggregate_root_when_table_sharing_with_non_owned_throws(bool async) + { + await base.Delete_aggregate_root_when_table_sharing_with_non_owned_throws(async); + + AssertSql(); + } + + public override async Task Delete_predicate_based_on_optional_navigation(bool async) + { + await base.Delete_predicate_based_on_optional_navigation(async); + + AssertSql( +""" +DELETE `p` +FROM `Posts` AS `p` +LEFT JOIN `Blogs` AS `b` ON `p`.`BlogId` = `b`.`Id` +WHERE `b`.`Title` IS NOT NULL AND (`b`.`Title` LIKE 'Arthur%') +"""); + } + + private void AssertSql(params string[] expected) + => TestSqlLoggerFactory.AssertBaseline(expected); + + private void AssertExecuteUpdateSql(params string[] expected) + => TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlFixture.cs new file mode 100644 index 000000000..6808823e4 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlFixture.cs @@ -0,0 +1,13 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class NorthwindBulkUpdatesMySqlFixture : NorthwindBulkUpdatesFixture + where TModelCustomizer : IModelCustomizer, new() +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlNorthwindTestStoreFactory.Instance; +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlTest.cs new file mode 100644 index 000000000..b386e4533 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/NorthwindBulkUpdatesMySqlTest.cs @@ -0,0 +1,1444 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestModels.Northwind; +using Microsoft.EntityFrameworkCore.TestUtilities; +using MySqlConnector; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure; +using Pomelo.EntityFrameworkCore.MySql.Tests; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class NorthwindBulkUpdatesMySqlTest : NorthwindBulkUpdatesTestBase> +{ + public NorthwindBulkUpdatesMySqlTest( + NorthwindBulkUpdatesMySqlFixture fixture, + ITestOutputHelper testOutputHelper) + : base(fixture) + { + ClearLog(); + // Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Delete_Where_TagWith(bool async) + { + await base.Delete_Where_TagWith(async); + + AssertSql( +""" +-- MyDelete + +DELETE `o` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` < 10300 +"""); + } + + public override async Task Delete_Where(bool async) + { + await base.Delete_Where(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` < 10300 +"""); + } + + public override async Task Delete_Where_parameter(bool async) + { + await base.Delete_Where_parameter(async); + + AssertSql( +""" +@__quantity_0='1' (Nullable = true) (DbType = Int16) + +DELETE `o` +FROM `Order Details` AS `o` +WHERE `o`.`Quantity` = @__quantity_0 +""", + // + """ +DELETE `o` +FROM `Order Details` AS `o` +WHERE FALSE +"""); + } + + public override async Task Delete_Where_OrderBy(bool async) + { + await base.Delete_Where_OrderBy(async); + + AssertSql( +""" +DELETE +FROM `Order Details` +WHERE `OrderID` < 10300 +ORDER BY `OrderID` +"""); + } + + public override async Task Delete_Where_OrderBy_Skip(bool async) + { + await base.Delete_Where_OrderBy_Skip(async); + + AssertSql( +""" +@__p_0='100' + +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10300 + ORDER BY `o0`.`OrderID` + LIMIT 18446744073709551610 OFFSET @__p_0 + ) AS `t` + WHERE (`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Where_OrderBy_Take(bool async) + { + await base.Delete_Where_OrderBy_Take(async); + + AssertSql( +""" +@__p_0='100' + +DELETE +FROM `Order Details` +WHERE `OrderID` < 10300 +ORDER BY `OrderID` +LIMIT @__p_0 +"""); + } + + public override async Task Delete_Where_OrderBy_Skip_Take(bool async) + { + await base.Delete_Where_OrderBy_Skip_Take(async); + + AssertSql( +""" +@__p_0='100' + +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10300 + ORDER BY `o0`.`OrderID` + LIMIT @__p_0 OFFSET @__p_0 + ) AS `t` + WHERE (`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Where_Skip(bool async) + { + await base.Delete_Where_Skip(async); + + AssertSql( +""" +@__p_0='100' + +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10300 + LIMIT 18446744073709551610 OFFSET @__p_0 + ) AS `t` + WHERE (`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Where_Take(bool async) + { + await base.Delete_Where_Take(async); + + AssertSql( +""" +@__p_0='100' + +DELETE +FROM `Order Details` +WHERE `OrderID` < 10300 +LIMIT @__p_0 +"""); + } + + public override async Task Delete_Where_Skip_Take(bool async) + { + await base.Delete_Where_Skip_Take(async); + + AssertSql( +""" +@__p_0='100' + +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10300 + LIMIT @__p_0 OFFSET @__p_0 + ) AS `t` + WHERE (`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Where_predicate_with_GroupBy_aggregate(bool async) + { + await base.Delete_Where_predicate_with_GroupBy_aggregate(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` < ( + SELECT ( + SELECT `o1`.`OrderID` + FROM `Orders` AS `o1` + WHERE (`o0`.`CustomerID` = `o1`.`CustomerID`) OR (`o0`.`CustomerID` IS NULL AND (`o1`.`CustomerID` IS NULL)) + LIMIT 1) + FROM `Orders` AS `o0` + GROUP BY `o0`.`CustomerID` + HAVING COUNT(*) > 11 + LIMIT 1) +"""); + } + + public override async Task Delete_Where_predicate_with_GroupBy_aggregate_2(bool async) + { + await base.Delete_Where_predicate_with_GroupBy_aggregate_2(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE EXISTS ( + SELECT 1 + FROM `Orders` AS `o1` + GROUP BY `o1`.`CustomerID` + HAVING (COUNT(*) > 9) AND (( + SELECT `o2`.`OrderID` + FROM `Orders` AS `o2` + WHERE (`o1`.`CustomerID` = `o2`.`CustomerID`) OR (`o1`.`CustomerID` IS NULL AND (`o2`.`CustomerID` IS NULL)) + LIMIT 1) = `o0`.`OrderID`)) +"""); + } + + public override async Task Delete_GroupBy_Where_Select(bool async) + { + await base.Delete_GroupBy_Where_Select(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_2(bool async) + { + await base.Delete_GroupBy_Where_Select_2(async); + + AssertSql(); + } + + public override async Task Delete_Where_Skip_Take_Skip_Take_causing_subquery(bool async) + { + await base.Delete_Where_Skip_Take_Skip_Take_causing_subquery(async); + + AssertSql( +""" +@__p_0='100' +@__p_2='5' +@__p_1='20' + +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `t`.`OrderID`, `t`.`ProductID`, `t`.`Discount`, `t`.`Quantity`, `t`.`UnitPrice` + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10300 + LIMIT @__p_0 OFFSET @__p_0 + ) AS `t` + LIMIT @__p_2 OFFSET @__p_1 + ) AS `t0` + WHERE (`t0`.`OrderID` = `o`.`OrderID`) AND (`t0`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Where_Distinct(bool async) + { + await base.Delete_Where_Distinct(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE `o`.`OrderID` < 10300 +"""); + } + + public override async Task Delete_SelectMany(bool async) + { + await base.Delete_SelectMany(async); + + AssertSql( +""" +DELETE `o0` +FROM `Orders` AS `o` +INNER JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE `o`.`OrderID` < 10250 +"""); + } + + public override async Task Delete_SelectMany_subquery(bool async) + { + await base.Delete_SelectMany_subquery(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM `Orders` AS `o0` + INNER JOIN ( + SELECT `o1`.`OrderID`, `o1`.`ProductID`, `o1`.`Discount`, `o1`.`Quantity`, `o1`.`UnitPrice` + FROM `Order Details` AS `o1` + WHERE `o1`.`ProductID` > 0 + ) AS `t` ON `o0`.`OrderID` = `t`.`OrderID` + WHERE (`o0`.`OrderID` < 10250) AND ((`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`))) +"""); + } + + public override async Task Delete_Where_using_navigation(bool async) + { + await base.Delete_Where_using_navigation(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE EXTRACT(year FROM `o0`.`OrderDate`) = 2000 +"""); + } + + public override async Task Delete_Where_using_navigation_2(bool async) + { + await base.Delete_Where_using_navigation_2(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +WHERE `c`.`CustomerID` IS NOT NULL AND (`c`.`CustomerID` LIKE 'F%') +"""); + } + + public override async Task Delete_Union(bool async) + { + await base.Delete_Union(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10250 + UNION + SELECT `o1`.`OrderID`, `o1`.`ProductID`, `o1`.`Discount`, `o1`.`Quantity`, `o1`.`UnitPrice` + FROM `Order Details` AS `o1` + WHERE `o1`.`OrderID` > 11250 + ) AS `t` + WHERE (`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Concat(bool async) + { + await base.Delete_Concat(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10250 + UNION ALL + SELECT `o1`.`OrderID`, `o1`.`ProductID`, `o1`.`Discount`, `o1`.`Quantity`, `o1`.`UnitPrice` + FROM `Order Details` AS `o1` + WHERE `o1`.`OrderID` > 11250 + ) AS `t` + WHERE (`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Intersect(bool async) + { + await base.Delete_Intersect(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10250 + INTERSECT + SELECT `o1`.`OrderID`, `o1`.`ProductID`, `o1`.`Discount`, `o1`.`Quantity`, `o1`.`UnitPrice` + FROM `Order Details` AS `o1` + WHERE `o1`.`OrderID` > 11250 + ) AS `t` + WHERE (`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Except(bool async) + { + await base.Delete_Except(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Order Details` AS `o0` + WHERE `o0`.`OrderID` < 10250 + EXCEPT + SELECT `o1`.`OrderID`, `o1`.`ProductID`, `o1`.`Discount`, `o1`.`Quantity`, `o1`.`UnitPrice` + FROM `Order Details` AS `o1` + WHERE `o1`.`OrderID` > 11250 + ) AS `t` + WHERE (`t`.`OrderID` = `o`.`OrderID`) AND (`t`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_non_entity_projection(bool async) + { + await base.Delete_non_entity_projection(async); + + AssertSql(); + } + + public override async Task Delete_non_entity_projection_2(bool async) + { + await base.Delete_non_entity_projection_2(async); + + AssertSql(); + } + + public override async Task Delete_non_entity_projection_3(bool async) + { + await base.Delete_non_entity_projection_3(async); + + AssertSql(); + } + + public override async Task Delete_FromSql_converted_to_subquery(bool async) + { + await base.Delete_FromSql_converted_to_subquery(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `OrderID`, `ProductID`, `UnitPrice`, `Quantity`, `Discount` + FROM `Order Details` + WHERE `OrderID` < 10300 + ) AS `m` + WHERE (`m`.`OrderID` = `o`.`OrderID`) AND (`m`.`ProductID` = `o`.`ProductID`)) +"""); + } + + public override async Task Delete_Where_optional_navigation_predicate(bool async) + { + await base.Delete_Where_optional_navigation_predicate(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +WHERE `c`.`City` IS NOT NULL AND (`c`.`City` LIKE 'Se%') +"""); + } + + public override async Task Delete_with_join(bool async) + { + await base.Delete_with_join(async); + + AssertSql( +""" +@__p_1='100' +@__p_0='0' + +DELETE `o` +FROM `Order Details` AS `o` +INNER JOIN ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + WHERE `o0`.`OrderID` < 10300 + ORDER BY `o0`.`OrderID` + LIMIT @__p_1 OFFSET @__p_0 +) AS `t` ON `o`.`OrderID` = `t`.`OrderID` +"""); + } + + public override async Task Delete_with_left_join(bool async) + { + await base.Delete_with_left_join(async); + + AssertSql( +""" +@__p_1='100' +@__p_0='0' + +DELETE `o` +FROM `Order Details` AS `o` +LEFT JOIN ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + WHERE `o0`.`OrderID` < 10300 + ORDER BY `o0`.`OrderID` + LIMIT @__p_1 OFFSET @__p_0 +) AS `t` ON `o`.`OrderID` = `t`.`OrderID` +WHERE `o`.`OrderID` < 10276 +"""); + } + + public override async Task Delete_with_cross_join(bool async) + { + await base.Delete_with_cross_join(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +CROSS JOIN ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + WHERE `o0`.`OrderID` < 10300 + ORDER BY `o0`.`OrderID` + LIMIT 100 OFFSET 0 +) AS `t` +WHERE `o`.`OrderID` < 10276 +"""); + } + + public override async Task Delete_with_cross_apply(bool async) + { + await base.Delete_with_cross_apply(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +JOIN LATERAL ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + WHERE `o0`.`OrderID` < `o`.`OrderID` + ORDER BY `o0`.`OrderID` + LIMIT 100 OFFSET 0 +) AS `t` ON TRUE +WHERE `o`.`OrderID` < 10276 +"""); + } + + public override async Task Delete_with_outer_apply(bool async) + { + await base.Delete_with_outer_apply(async); + + AssertSql( +""" +DELETE `o` +FROM `Order Details` AS `o` +LEFT JOIN LATERAL ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + WHERE `o0`.`OrderID` < `o`.`OrderID` + ORDER BY `o0`.`OrderID` + LIMIT 100 OFFSET 0 +) AS `t` ON TRUE +WHERE `o`.`OrderID` < 10276 +"""); + } + + public override async Task Update_Where_set_constant_TagWith(bool async) + { + await base.Update_Where_set_constant_TagWith(async); + + AssertExecuteUpdateSql( +""" +-- MyUpdate + +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_constant(bool async) + { + await base.Update_Where_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_parameter_set_constant(bool async) + { + await base.Update_Where_parameter_set_constant(async); + + AssertExecuteUpdateSql( + """ +@__customer_0='ALFKI' (Size = 255) + +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` = @__customer_0 +""", + // + """ +@__customer_0='ALFKI' (Size = 255) + +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Customers` AS `c` +WHERE `c`.`CustomerID` = @__customer_0 +""", + // + """ +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Customers` AS `c` +WHERE FALSE +""", + // + """ +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE FALSE +"""); + } + + public override async Task Update_Where_set_parameter(bool async) + { + await base.Update_Where_set_parameter(async); + + AssertExecuteUpdateSql( +""" +@__value_0='Abc' (Size = 4000) + +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = @__value_0 +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_parameter_from_closure_array(bool async) + { + await base.Update_Where_set_parameter_from_closure_array(async); + + AssertExecuteUpdateSql( +""" +@__p_0='Abc' (Size = 4000) + +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = @__p_0 +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_parameter_from_inline_list(bool async) + { + await base.Update_Where_set_parameter_from_inline_list(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Abc' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_parameter_from_multilevel_property_access(bool async) + { + await base.Update_Where_set_parameter_from_multilevel_property_access(async); + + AssertExecuteUpdateSql( +""" +@__container_Containee_Property_0='Abc' (Size = 4000) + +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = @__container_Containee_Property_0 +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_Skip_set_constant(bool async) + { + await base.Update_Where_Skip_set_constant(async); + + AssertExecuteUpdateSql( +""" +@__p_0='4' + +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + LIMIT 18446744073709551610 OFFSET @__p_0 +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Where_Take_set_constant(bool async) + { + await AssertUpdate( + async, + ss => ss.Set().Where(c => c.CustomerID.StartsWith("F")).Take(4), + e => e, + s => s.SetProperty(c => c.ContactName, "Updated"), + rowsAffectedCount: 4, + (b, a) => Assert.All(a, c => Assert.Equal("Updated", c.ContactName))); + + AssertExecuteUpdateSql( +""" +@__p_0='4' + +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +LIMIT @__p_0 +"""); + } + + public override async Task Update_Where_Skip_Take_set_constant(bool async) + { + await base.Update_Where_Skip_Take_set_constant(async); + + AssertExecuteUpdateSql( +""" +@__p_1='4' +@__p_0='2' + +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + LIMIT @__p_1 OFFSET @__p_0 +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Where_OrderBy_set_constant(bool async) + { + await base.Update_Where_OrderBy_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Where_OrderBy_Skip_set_constant(bool async) + { + await base.Update_Where_OrderBy_Skip_set_constant(async); + + AssertExecuteUpdateSql( +""" +@__p_0='4' + +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + ORDER BY `c0`.`City` + LIMIT 18446744073709551610 OFFSET @__p_0 +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Where_OrderBy_Take_set_constant(bool async) + { + await base.Update_Where_OrderBy_Take_set_constant(async); + + AssertExecuteUpdateSql( +""" +@__p_0='4' + +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + ORDER BY `c0`.`City` + LIMIT @__p_0 +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Where_OrderBy_Skip_Take_set_constant(bool async) + { + await base.Update_Where_OrderBy_Skip_Take_set_constant(async); + + AssertExecuteUpdateSql( +""" +@__p_1='4' +@__p_0='2' + +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + ORDER BY `c0`.`City` + LIMIT @__p_1 OFFSET @__p_0 +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Where_OrderBy_Skip_Take_Skip_Take_set_constant(bool async) + { + await base.Update_Where_OrderBy_Skip_Take_Skip_Take_set_constant(async); + + AssertExecuteUpdateSql( +""" +@__p_1='6' +@__p_0='2' + +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region` + FROM ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + ORDER BY `c0`.`City` + LIMIT @__p_1 OFFSET @__p_0 + ) AS `t` + ORDER BY `t`.`City` + LIMIT @__p_0 OFFSET @__p_0 +) AS `t0` ON `c`.`CustomerID` = `t0`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Where_GroupBy_aggregate_set_constant(bool async) + { + await base.Update_Where_GroupBy_aggregate_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` = ( + SELECT `o`.`CustomerID` + FROM `Orders` AS `o` + GROUP BY `o`.`CustomerID` + HAVING COUNT(*) > 11 + LIMIT 1) +"""); + } + + public override async Task Update_Where_GroupBy_First_set_constant(bool async) + { + await base.Update_Where_GroupBy_First_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` = ( + SELECT ( + SELECT `o0`.`CustomerID` + FROM `Orders` AS `o0` + WHERE (`o`.`CustomerID` = `o0`.`CustomerID`) OR (`o`.`CustomerID` IS NULL AND (`o0`.`CustomerID` IS NULL)) + LIMIT 1) + FROM `Orders` AS `o` + GROUP BY `o`.`CustomerID` + HAVING COUNT(*) > 11 + LIMIT 1) +"""); + } + + public override async Task Update_Where_GroupBy_First_set_constant_2(bool async) + { + await base.Update_Where_GroupBy_First_set_constant_2(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_Where_GroupBy_First_set_constant_3(bool async) + { + if (AppConfig.ServerVersion.Type == ServerType.MySql) + { + // Not supported by MySQL: + // Error Code: 1093. You can't specify target table 'c' for update in FROM clause + await Assert.ThrowsAsync( + () => base.Update_Where_GroupBy_First_set_constant_3(async)); + } + else + { + // Works as expected in MariaDB. + await base.Update_Where_GroupBy_First_set_constant_3(async); + } + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE EXISTS ( + SELECT 1 + FROM `Orders` AS `o` + GROUP BY `o`.`CustomerID` + HAVING (COUNT(*) > 11) AND (( + SELECT `c0`.`CustomerID` + FROM `Orders` AS `o0` + LEFT JOIN `Customers` AS `c0` ON `o0`.`CustomerID` = `c0`.`CustomerID` + WHERE (`o`.`CustomerID` = `o0`.`CustomerID`) OR (`o`.`CustomerID` IS NULL AND (`o0`.`CustomerID` IS NULL)) + LIMIT 1) = `c`.`CustomerID`)) +"""); + } + + public override async Task Update_Where_Distinct_set_constant(bool async) + { + await base.Update_Where_Distinct_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_using_navigation_set_null(bool async) + { + await base.Update_Where_using_navigation_set_null(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +SET `o`.`OrderDate` = NULL +WHERE `c`.`City` = 'Seattle' +"""); + } + + public override async Task Update_Where_using_navigation_2_set_constant(bool async) + { + await base.Update_Where_using_navigation_2_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +SET `o`.`Quantity` = CAST(1 AS signed) +WHERE `c`.`City` = 'Seattle' +"""); + } + + public override async Task Update_Where_SelectMany_set_null(bool async) + { + await base.Update_Where_SelectMany_set_null(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +INNER JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +SET `o`.`OrderDate` = NULL +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_property_plus_constant(bool async) + { + await base.Update_Where_set_property_plus_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = CONCAT(COALESCE(`c`.`ContactName`, ''), 'Abc') +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_property_plus_parameter(bool async) + { + await base.Update_Where_set_property_plus_parameter(async); + + AssertExecuteUpdateSql( +""" +@__value_0='Abc' (Size = 4000) + +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = CONCAT(COALESCE(`c`.`ContactName`, ''), @__value_0) +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_property_plus_property(bool async) + { + await base.Update_Where_set_property_plus_property(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = CONCAT(COALESCE(`c`.`ContactName`, ''), `c`.`CustomerID`) +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_constant_using_ef_property(bool async) + { + await base.Update_Where_set_constant_using_ef_property(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_set_null(bool async) + { + await base.Update_Where_set_null(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`ContactName` = NULL +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_without_property_to_set_throws(bool async) + { + await base.Update_without_property_to_set_throws(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_with_invalid_lambda_throws(bool async) + { + await base.Update_with_invalid_lambda_throws(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_Where_multiple_set(bool async) + { + await base.Update_Where_multiple_set(async); + + AssertExecuteUpdateSql( +""" +@__value_0='Abc' (Size = 4000) + +UPDATE `Customers` AS `c` +SET `c`.`City` = 'Seattle', + `c`.`ContactName` = @__value_0 +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_with_invalid_lambda_in_set_property_throws(bool async) + { + await base.Update_with_invalid_lambda_in_set_property_throws(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_multiple_entity_throws(bool async) + { + await base.Update_multiple_entity_throws(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_unmapped_property_throws(bool async) + { + await base.Update_unmapped_property_throws(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_Union_set_constant(bool async) + { + await base.Update_Union_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + UNION + SELECT `c1`.`CustomerID`, `c1`.`Address`, `c1`.`City`, `c1`.`CompanyName`, `c1`.`ContactName`, `c1`.`ContactTitle`, `c1`.`Country`, `c1`.`Fax`, `c1`.`Phone`, `c1`.`PostalCode`, `c1`.`Region` + FROM `Customers` AS `c1` + WHERE `c1`.`CustomerID` LIKE 'A%' +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Concat_set_constant(bool async) + { + await base.Update_Concat_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + UNION ALL + SELECT `c1`.`CustomerID`, `c1`.`Address`, `c1`.`City`, `c1`.`CompanyName`, `c1`.`ContactName`, `c1`.`ContactTitle`, `c1`.`Country`, `c1`.`Fax`, `c1`.`Phone`, `c1`.`PostalCode`, `c1`.`Region` + FROM `Customers` AS `c1` + WHERE `c1`.`CustomerID` LIKE 'A%' +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Except_set_constant(bool async) + { + await base.Update_Except_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + EXCEPT + SELECT `c1`.`CustomerID`, `c1`.`Address`, `c1`.`City`, `c1`.`CompanyName`, `c1`.`ContactName`, `c1`.`ContactTitle`, `c1`.`Country`, `c1`.`Fax`, `c1`.`Phone`, `c1`.`PostalCode`, `c1`.`Region` + FROM `Customers` AS `c1` + WHERE `c1`.`CustomerID` LIKE 'A%' +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_Intersect_set_constant(bool async) + { + await base.Update_Intersect_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' + INTERSECT + SELECT `c1`.`CustomerID`, `c1`.`Address`, `c1`.`City`, `c1`.`CompanyName`, `c1`.`ContactName`, `c1`.`ContactTitle`, `c1`.`Country`, `c1`.`Fax`, `c1`.`Phone`, `c1`.`PostalCode`, `c1`.`Region` + FROM `Customers` AS `c1` + WHERE `c1`.`CustomerID` LIKE 'A%' +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +"""); + } + + public override async Task Update_with_join_set_constant(bool async) + { + await base.Update_with_join_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +INNER JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` < 10300 +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_with_left_join_set_constant(bool async) + { + await base.Update_with_left_join_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` < 10300 +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_with_cross_join_set_constant(bool async) + { + await base.Update_with_cross_join_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +CROSS JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` < 10300 +) AS `t` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_with_cross_apply_set_constant(bool async) + { + await base.Update_with_cross_apply_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +JOIN LATERAL ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE (`o`.`OrderID` < 10300) AND (EXTRACT(year FROM `o`.`OrderDate`) < CHAR_LENGTH(`c`.`ContactName`)) +) AS `t` ON TRUE +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_with_outer_apply_set_constant(bool async) + { + await base.Update_with_outer_apply_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +LEFT JOIN LATERAL ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE (`o`.`OrderID` < 10300) AND (EXTRACT(year FROM `o`.`OrderDate`) < CHAR_LENGTH(`c`.`ContactName`)) +) AS `t` ON TRUE +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_with_cross_join_left_join_set_constant(bool async) + { + await base.Update_with_cross_join_left_join_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`City` IS NOT NULL AND (`c0`.`City` LIKE 'S%') +) AS `t` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` < 10300 +) AS `t0` ON `c`.`CustomerID` = `t0`.`CustomerID` +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_with_cross_join_cross_apply_set_constant(bool async) + { + await base.Update_with_cross_join_cross_apply_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`City` IS NOT NULL AND (`c0`.`City` LIKE 'S%') +) AS `t` +JOIN LATERAL ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE (`o`.`OrderID` < 10300) AND (EXTRACT(year FROM `o`.`OrderDate`) < CHAR_LENGTH(`c`.`ContactName`)) +) AS `t0` ON TRUE +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_with_cross_join_outer_apply_set_constant(bool async) + { + await base.Update_with_cross_join_outer_apply_set_constant(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`City` IS NOT NULL AND (`c0`.`City` LIKE 'S%') +) AS `t` +LEFT JOIN LATERAL ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE (`o`.`OrderID` < 10300) AND (EXTRACT(year FROM `o`.`OrderDate`) < CHAR_LENGTH(`c`.`ContactName`)) +) AS `t0` ON TRUE +SET `c`.`ContactName` = 'Updated' +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_FromSql_set_constant(bool async) + { + await base.Update_FromSql_set_constant(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_Where_SelectMany_subquery_set_null(bool async) + { + await base.Update_Where_SelectMany_subquery_set_null(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Orders` AS `o` +INNER JOIN ( + SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0` + FROM `Customers` AS `c` + INNER JOIN ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + WHERE EXTRACT(year FROM `o0`.`OrderDate`) = 1997 + ) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` + WHERE `c`.`CustomerID` LIKE 'F%' +) AS `t0` ON `o`.`OrderID` = `t0`.`OrderID` +SET `o`.`OrderDate` = NULL +"""); + } + + public override async Task Update_Where_Join_set_property_from_joined_single_result_table(bool async) + { + await base.Update_Where_Join_set_property_from_joined_single_result_table(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`City` = CAST(EXTRACT(year FROM ( + SELECT `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`OrderDate` DESC + LIMIT 1)) AS char) +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_Join_set_property_from_joined_table(bool async) + { + await base.Update_Where_Join_set_property_from_joined_table(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` = 'ALFKI' +) AS `t` +SET `c`.`City` = `t`.`City` +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + public override async Task Update_Where_Join_set_property_from_joined_single_result_scalar(bool async) + { + await base.Update_Where_Join_set_property_from_joined_single_result_scalar(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Customers` AS `c` +SET `c`.`City` = CAST(EXTRACT(year FROM ( + SELECT `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`OrderDate` DESC + LIMIT 1)) AS char) +WHERE `c`.`CustomerID` LIKE 'F%' +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + private void AssertExecuteUpdateSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesMySqlFixture.cs new file mode 100644 index 000000000..cd766f84c --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesMySqlFixture.cs @@ -0,0 +1,10 @@ +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class TPCFiltersInheritanceBulkUpdatesMySqlFixture : TPCInheritanceBulkUpdatesMySqlFixture +{ + protected override string StoreName + => "TPCFiltersInheritanceBulkUpdatesTest"; + + protected override bool EnableFilters + => true; +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesMySqlTest.cs new file mode 100644 index 000000000..fe57a90ef --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCFiltersInheritanceBulkUpdatesMySqlTest.cs @@ -0,0 +1,194 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class TPCFiltersInheritanceBulkUpdatesMySqlTest : TPCFiltersInheritanceBulkUpdatesTestBase< + TPCFiltersInheritanceBulkUpdatesMySqlFixture> +{ + public TPCFiltersInheritanceBulkUpdatesMySqlTest(TPCFiltersInheritanceBulkUpdatesMySqlFixture fixture) + : base(fixture) + { + ClearLog(); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Delete_where_hierarchy(bool async) + { + await base.Delete_where_hierarchy(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_derived(bool async) + { + await base.Delete_where_hierarchy_derived(async); + + AssertSql( +""" +DELETE `k` +FROM `Kiwi` AS `k` +WHERE (`k`.`CountryId` = 1) AND (`k`.`Name` = 'Great spotted kiwi') +"""); + } + + public override async Task Delete_where_using_hierarchy(bool async) + { + await base.Delete_where_using_hierarchy(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` + ) AS `t` + WHERE ((`t`.`CountryId` = 1) AND (`c`.`Id` = `t`.`CountryId`)) AND (`t`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_where_using_hierarchy_derived(bool async) + { + await base.Delete_where_using_hierarchy_derived(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` + ) AS `t` + WHERE ((`t`.`CountryId` = 1) AND (`c`.`Id` = `t`.`CountryId`)) AND (`t`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Delete_where_keyless_entity_mapped_to_sql_query(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_subquery(bool async) + { + await base.Delete_where_hierarchy_subquery(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First(bool async) + { + await base.Delete_GroupBy_Where_Select_First(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_2(bool async) + { + await base.Delete_GroupBy_Where_Select_First_2(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_3(bool async) + { + await base.Delete_GroupBy_Where_Select_First_3(async); + + AssertSql(); + } + + public override async Task Update_where_hierarchy(bool async) + { + await base.Update_where_hierarchy(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_subquery(bool async) + { + await base.Update_where_hierarchy_subquery(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_derived(bool async) + { + await base.Update_where_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Kiwi` AS `k` +SET `k`.`Name` = 'Kiwi' +WHERE (`k`.`CountryId` = 1) AND (`k`.`Name` = 'Great spotted kiwi') +"""); + } + + public override async Task Update_where_using_hierarchy(bool async) + { + await base.Update_where_using_hierarchy(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` + ) AS `t` + WHERE ((`t`.`CountryId` = 1) AND (`c`.`Id` = `t`.`CountryId`)) AND (`t`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_using_hierarchy_derived(bool async) + { + await base.Update_where_using_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` + ) AS `t` + WHERE ((`t`.`CountryId` = 1) AND (`c`.`Id` = `t`.`CountryId`)) AND (`t`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Update_where_keyless_entity_mapped_to_sql_query(async); + + AssertExecuteUpdateSql(); + } + + protected override void ClearLog() + => Fixture.TestSqlLoggerFactory.Clear(); + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + private void AssertExecuteUpdateSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesMySqlFixture.cs new file mode 100644 index 000000000..07d9729be --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesMySqlFixture.cs @@ -0,0 +1,33 @@ +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class TPCInheritanceBulkUpdatesMySqlFixture : TPCInheritanceBulkUpdatesFixture +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + protected override bool UseGeneratedKeys + => false; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + // We currently do not support an official way to set a seed and auto_increment value for auto_increment columns, which is needed + // for TPC if the database implementation does not support sequences (which MariaDB does, but we have not fully implemented yet). + // We therefore just remove the auto_increment flag from the appropriate entities here, so we do not trigger the related TPC + // warning by EF Core. + foreach (var tpcPrimaryKey in modelBuilder.Model.GetEntityTypes() + .Where(e => e.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) + .Select(e => e.FindPrimaryKey())) + { + tpcPrimaryKey.Properties.Single().ValueGenerated = ValueGenerated.Never; + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesMySqlTest.cs new file mode 100644 index 000000000..92481a93c --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPCInheritanceBulkUpdatesMySqlTest.cs @@ -0,0 +1,193 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class TPCInheritanceBulkUpdatesMySqlTest : TPCInheritanceBulkUpdatesTestBase +{ + public TPCInheritanceBulkUpdatesMySqlTest(TPCInheritanceBulkUpdatesMySqlFixture fixture) + : base(fixture) + { + ClearLog(); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Delete_where_hierarchy(bool async) + { + await base.Delete_where_hierarchy(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_derived(bool async) + { + await base.Delete_where_hierarchy_derived(async); + + AssertSql( +""" +DELETE `k` +FROM `Kiwi` AS `k` +WHERE `k`.`Name` = 'Great spotted kiwi' +"""); + } + + public override async Task Delete_where_using_hierarchy(bool async) + { + await base.Delete_where_using_hierarchy(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` + ) AS `t` + WHERE (`c`.`Id` = `t`.`CountryId`) AND (`t`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_where_using_hierarchy_derived(bool async) + { + await base.Delete_where_using_hierarchy_derived(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` + ) AS `t` + WHERE (`c`.`Id` = `t`.`CountryId`) AND (`t`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Delete_where_keyless_entity_mapped_to_sql_query(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_subquery(bool async) + { + await base.Delete_where_hierarchy_subquery(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First(bool async) + { + await base.Delete_GroupBy_Where_Select_First(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_2(bool async) + { + await base.Delete_GroupBy_Where_Select_First_2(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_3(bool async) + { + await base.Delete_GroupBy_Where_Select_First_3(async); + + AssertSql(); + } + + public override async Task Update_where_hierarchy(bool async) + { + await base.Update_where_hierarchy(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_subquery(bool async) + { + await base.Update_where_hierarchy_subquery(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_derived(bool async) + { + await base.Update_where_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Kiwi` AS `k` +SET `k`.`Name` = 'Kiwi' +WHERE `k`.`Name` = 'Great spotted kiwi' +"""); + } + + public override async Task Update_where_using_hierarchy(bool async) + { + await base.Update_where_using_hierarchy(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` + ) AS `t` + WHERE (`c`.`Id` = `t`.`CountryId`) AND (`t`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_using_hierarchy_derived(bool async) + { + await base.Update_where_using_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM ( + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` + ) AS `t` + WHERE (`c`.`Id` = `t`.`CountryId`) AND (`t`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Update_where_keyless_entity_mapped_to_sql_query(async); + + AssertExecuteUpdateSql(); + } + + protected override void ClearLog() + => Fixture.TestSqlLoggerFactory.Clear(); + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + private void AssertExecuteUpdateSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesMySqlFixture.cs new file mode 100644 index 000000000..dddec9d11 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesMySqlFixture.cs @@ -0,0 +1,10 @@ +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class TPTFiltersInheritanceBulkUpdatesMySqlFixture : TPTInheritanceBulkUpdatesMySqlFixture +{ + protected override string StoreName + => "TPTFiltersInheritanceBulkUpdatesTest"; + + protected override bool EnableFilters + => true; +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesMySqlTest.cs new file mode 100644 index 000000000..b63b29e42 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTFiltersInheritanceBulkUpdatesMySqlTest.cs @@ -0,0 +1,178 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class TPTFiltersInheritanceBulkUpdatesMySqlTest : TPTFiltersInheritanceBulkUpdatesTestBase< + TPTFiltersInheritanceBulkUpdatesMySqlFixture> +{ + public TPTFiltersInheritanceBulkUpdatesMySqlTest(TPTFiltersInheritanceBulkUpdatesMySqlFixture fixture) + : base(fixture) + { + ClearLog(); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Delete_where_hierarchy(bool async) + { + await base.Delete_where_hierarchy(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_derived(bool async) + { + await base.Delete_where_hierarchy_derived(async); + + AssertSql(); + } + + public override async Task Delete_where_using_hierarchy(bool async) + { + await base.Delete_where_using_hierarchy(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + LEFT JOIN `Birds` AS `b` ON `a`.`Id` = `b`.`Id` + LEFT JOIN `Eagle` AS `e` ON `a`.`Id` = `e`.`Id` + LEFT JOIN `Kiwi` AS `k` ON `a`.`Id` = `k`.`Id` + WHERE ((`a`.`CountryId` = 1) AND (`c`.`Id` = `a`.`CountryId`)) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_where_using_hierarchy_derived(bool async) + { + await base.Delete_where_using_hierarchy_derived(async); + + AssertSql( +""" +DELETE `c` +FROM `Countries` AS `c` +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + LEFT JOIN `Birds` AS `b` ON `a`.`Id` = `b`.`Id` + LEFT JOIN `Eagle` AS `e` ON `a`.`Id` = `e`.`Id` + LEFT JOIN `Kiwi` AS `k` ON `a`.`Id` = `k`.`Id` + WHERE (((`a`.`CountryId` = 1) AND (`c`.`Id` = `a`.`CountryId`)) AND `k`.`Id` IS NOT NULL) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Delete_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Delete_where_keyless_entity_mapped_to_sql_query(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_subquery(bool async) + { + await base.Delete_where_hierarchy_subquery(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First(bool async) + { + await base.Delete_GroupBy_Where_Select_First(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_2(bool async) + { + await base.Delete_GroupBy_Where_Select_First_2(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_3(bool async) + { + await base.Delete_GroupBy_Where_Select_First_3(async); + + AssertSql(); + } + + public override async Task Update_where_hierarchy(bool async) + { + await base.Update_where_hierarchy(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_subquery(bool async) + { + await base.Update_where_hierarchy_subquery(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_derived(bool async) + { + await base.Update_where_hierarchy_derived(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_using_hierarchy(bool async) + { + await base.Update_where_using_hierarchy(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + LEFT JOIN `Birds` AS `b` ON `a`.`Id` = `b`.`Id` + LEFT JOIN `Eagle` AS `e` ON `a`.`Id` = `e`.`Id` + LEFT JOIN `Kiwi` AS `k` ON `a`.`Id` = `k`.`Id` + WHERE ((`a`.`CountryId` = 1) AND (`c`.`Id` = `a`.`CountryId`)) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_using_hierarchy_derived(bool async) + { + await base.Update_where_using_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + LEFT JOIN `Birds` AS `b` ON `a`.`Id` = `b`.`Id` + LEFT JOIN `Eagle` AS `e` ON `a`.`Id` = `e`.`Id` + LEFT JOIN `Kiwi` AS `k` ON `a`.`Id` = `k`.`Id` + WHERE (((`a`.`CountryId` = 1) AND (`c`.`Id` = `a`.`CountryId`)) AND `k`.`Id` IS NOT NULL) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Update_where_keyless_entity_mapped_to_sql_query(async); + + AssertExecuteUpdateSql(); + } + + protected override void ClearLog() + => Fixture.TestSqlLoggerFactory.Clear(); + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + private void AssertExecuteUpdateSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesMySqlFixture.cs new file mode 100644 index 000000000..d7cea5a28 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesMySqlFixture.cs @@ -0,0 +1,11 @@ +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class TPTInheritanceBulkUpdatesMySqlFixture : TPTInheritanceBulkUpdatesFixture +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesMySqlTest.cs new file mode 100644 index 000000000..d9669a957 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/BulkUpdates/TPTInheritanceBulkUpdatesMySqlTest.cs @@ -0,0 +1,155 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.BulkUpdates; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.BulkUpdates; + +public class TPTInheritanceBulkUpdatesMySqlTest : TPTInheritanceBulkUpdatesTestBase +{ + public TPTInheritanceBulkUpdatesMySqlTest(TPTInheritanceBulkUpdatesMySqlFixture fixture) + : base(fixture) + { + ClearLog(); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Delete_where_hierarchy(bool async) + { + await base.Delete_where_hierarchy(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_derived(bool async) + { + await base.Delete_where_hierarchy_derived(async); + + AssertSql(); + } + + public override async Task Delete_where_using_hierarchy(bool async) + { + await base.Delete_where_using_hierarchy(async); + + AssertSql(); + } + + public override async Task Delete_where_using_hierarchy_derived(bool async) + { + await base.Delete_where_using_hierarchy_derived(async); + + AssertSql(); + } + + public override async Task Delete_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Delete_where_keyless_entity_mapped_to_sql_query(async); + + AssertSql(); + } + + public override async Task Delete_where_hierarchy_subquery(bool async) + { + await base.Delete_where_hierarchy_subquery(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First(bool async) + { + await base.Delete_GroupBy_Where_Select_First(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_2(bool async) + { + await base.Delete_GroupBy_Where_Select_First_2(async); + + AssertSql(); + } + + public override async Task Delete_GroupBy_Where_Select_First_3(bool async) + { + await base.Delete_GroupBy_Where_Select_First_3(async); + + AssertSql(); + } + + public override async Task Update_where_hierarchy(bool async) + { + await base.Update_where_hierarchy(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_subquery(bool async) + { + await base.Update_where_hierarchy_subquery(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_hierarchy_derived(bool async) + { + await base.Update_where_hierarchy_derived(async); + + AssertExecuteUpdateSql(); + } + + public override async Task Update_where_using_hierarchy(bool async) + { + await base.Update_where_using_hierarchy(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + LEFT JOIN `Birds` AS `b` ON `a`.`Id` = `b`.`Id` + LEFT JOIN `Eagle` AS `e` ON `a`.`Id` = `e`.`Id` + LEFT JOIN `Kiwi` AS `k` ON `a`.`Id` = `k`.`Id` + WHERE (`c`.`Id` = `a`.`CountryId`) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_using_hierarchy_derived(bool async) + { + await base.Update_where_using_hierarchy_derived(async); + + AssertExecuteUpdateSql( +""" +UPDATE `Countries` AS `c` +SET `c`.`Name` = 'Monovia' +WHERE ( + SELECT COUNT(*) + FROM `Animals` AS `a` + LEFT JOIN `Birds` AS `b` ON `a`.`Id` = `b`.`Id` + LEFT JOIN `Eagle` AS `e` ON `a`.`Id` = `e`.`Id` + LEFT JOIN `Kiwi` AS `k` ON `a`.`Id` = `k`.`Id` + WHERE ((`c`.`Id` = `a`.`CountryId`) AND `k`.`Id` IS NOT NULL) AND (`a`.`CountryId` > 0)) > 0 +"""); + } + + public override async Task Update_where_keyless_entity_mapped_to_sql_query(bool async) + { + await base.Update_where_keyless_entity_mapped_to_sql_query(async); + + AssertExecuteUpdateSql(); + } + + protected override void ClearLog() + => Fixture.TestSqlLoggerFactory.Clear(); + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + private void AssertExecuteUpdateSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true); +} diff --git a/test/EFCore.MySql.FunctionalTests/ConnectionInterceptionMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/ConnectionInterceptionMySqlTest.cs index ba49ee619..143a8a8a4 100644 --- a/test/EFCore.MySql.FunctionalTests/ConnectionInterceptionMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/ConnectionInterceptionMySqlTest.cs @@ -30,6 +30,9 @@ protected override IServiceCollection InjectInterceptors( => base.InjectInterceptors(serviceCollection.AddEntityFrameworkMySql(), injectedInterceptors); } + protected override DbContextOptionsBuilder ConfigureProvider(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseMySql(AppConfig.ServerVersion); + protected override BadUniverseContext CreateBadUniverse(DbContextOptionsBuilder optionsBuilder) => new BadUniverseContext(optionsBuilder.UseMySql(new FakeDbConnection(), AppConfig.ServerVersion).Options); diff --git a/test/EFCore.MySql.FunctionalTests/DataAnnotationMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/DataAnnotationMySqlTest.cs index 4be87cde4..569058bee 100644 --- a/test/EFCore.MySql.FunctionalTests/DataAnnotationMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/DataAnnotationMySqlTest.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Pomelo.EntityFrameworkCore.MySql.Tests; using Xunit; using Xunit.Abstractions; @@ -24,6 +25,9 @@ public DataAnnotationMySqlTest(DataAnnotationMySqlFixture fixture, ITestOutputHe protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) => facade.UseTransaction(transaction.GetDbTransaction()); + protected override TestHelpers TestHelpers + => MySqlTestHelpers.Instance; + public override IModel Non_public_annotations_are_enabled() { var modelBuilder = CreateModelBuilder(); @@ -143,8 +147,27 @@ public override void DatabaseGeneratedAttribute_autogenerates_values_when_set_to { base.DatabaseGeneratedAttribute_autogenerates_values_when_set_to_identity(); - AssertSql( - @"@p0=NULL (Size = 10) + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +@p0=NULL (Size = 10) +@p1='Third' (Nullable = false) (Size = 4000) +@p2='00000000-0000-0000-0000-000000000003' +@p3='Third Additional Name' (Size = 4000) +@p4='0' (Nullable = true) +@p5='Third Name' (Size = 4000) +@p6='0' (Nullable = true) + +INSERT INTO `Sample` (`MaxLengthProperty`, `Name`, `RowVersion`, `AdditionalDetails_Name`, `AdditionalDetails_Value`, `Details_Name`, `Details_Value`) +VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6) +RETURNING `Unique_No`; +"""); + } + else + { + AssertSql( + @"@p0=NULL (Size = 10) @p1='Third' (Nullable = false) (Size = 4000) @p2='00000000-0000-0000-0000-000000000003' @p3='Third Additional Name' (Size = 4000) @@ -157,6 +180,7 @@ public override void DatabaseGeneratedAttribute_autogenerates_values_when_set_to SELECT `Unique_No` FROM `Sample` WHERE ROW_COUNT() = 1 AND `Unique_No` = LAST_INSERT_ID();"); + } } [ConditionalFact] diff --git a/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj b/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj index 72bb835ee..5c1bb1e68 100644 --- a/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj +++ b/test/EFCore.MySql.FunctionalTests/EFCore.MySql.FunctionalTests.csproj @@ -1,9 +1,10 @@  - $(DefaultNetCoreTargetFramework) + $(PomeloTestTargetFramework) Pomelo.EntityFrameworkCore.MySql.FunctionalTests Pomelo.EntityFrameworkCore.MySql.FunctionalTests + true $(DefaultItemExcludes);*.trx @@ -35,28 +36,28 @@ - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Proxies.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Proxies.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.Specification.Tests.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Relational.Specification.Tests.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Specification.Tests.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Specification.Tests.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Design.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Design.dll diff --git a/test/EFCore.MySql.FunctionalTests/EntitySplittingMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/EntitySplittingMySqlTest.cs new file mode 100644 index 000000000..0a499690a --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/EntitySplittingMySqlTest.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests; + +public class EntitySplittingMySqlTest : EntitySplittingTestBase +{ + public EntitySplittingMySqlTest(ITestOutputHelper testOutputHelper) + : base(testOutputHelper) + { + } + + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.MySql.FunctionalTests/FindMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/FindMySqlTest.cs index 4ffaab5a7..a776c1f6e 100644 --- a/test/EFCore.MySql.FunctionalTests/FindMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/FindMySqlTest.cs @@ -1,26 +1,52 @@ -using System.Threading.Tasks; -using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests; -namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests +public abstract class FindMySqlTest : FindTestBase { - public class FindMySqlTest : FindTestBase + protected FindMySqlTest(FindMySqlFixture fixture) + : base(fixture) + { + fixture.TestSqlLoggerFactory.Clear(); + } + + public class FindMySqlTestSet : FindMySqlTest { - public FindMySqlTest(FindMySqlFixture fixture) + public FindMySqlTestSet(FindMySqlFixture fixture) : base(fixture) { } - protected override TEntity Find(DbContext context, params object[] keyValues) - => context.Set().Find(keyValues); + protected override TestFinder Finder { get; } = new FindViaSetFinder(); + } - protected override ValueTask FindAsync(DbContext context, params object[] keyValues) - => context.Set().FindAsync(keyValues); + public class FindMySqlTestContext : FindMySqlTest + { + public FindMySqlTestContext(FindMySqlFixture fixture) + : base(fixture) + { + } + + protected override TestFinder Finder { get; } = new FindViaContextFinder(); + } - public class FindMySqlFixture : FindFixtureBase + public class FindMySqlTestNonGeneric : FindMySqlTest + { + public FindMySqlTestNonGeneric(FindMySqlFixture fixture) + : base(fixture) { - protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; } + + protected override TestFinder Finder { get; } = new FindViaNonGenericContextFinder(); + } + + public class FindMySqlFixture : FindFixtureBase + { + public TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ServiceProvider.GetRequiredService(); + protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; } } diff --git a/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlClientCascadeTest.cs b/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlClientCascadeTest.cs new file mode 100644 index 000000000..cc94f60dc --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlClientCascadeTest.cs @@ -0,0 +1,38 @@ +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests; + +public class GraphUpdatesMySqlClientCascadeTest : GraphUpdatesMySqlTestBase +{ + public GraphUpdatesMySqlClientCascadeTest(MySqlFixture fixture) + : base(fixture) + { + } + + protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) + => facade.UseTransaction(transaction.GetDbTransaction()); + + public class MySqlFixture : GraphUpdatesMySqlFixtureBase + { + public override bool NoStoreCascades + => true; + + protected override string StoreName { get; } = "GraphClientCascadeUpdatesTest"; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + foreach (var foreignKey in modelBuilder.Model + .GetEntityTypes() + .SelectMany(e => e.GetDeclaredForeignKeys()) + .Where(e => e.DeleteBehavior == DeleteBehavior.Cascade)) + { + foreignKey.DeleteBehavior = DeleteBehavior.ClientCascade; + } + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlClientNoActionTest.cs b/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlClientNoActionTest.cs new file mode 100644 index 000000000..21801edd2 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlClientNoActionTest.cs @@ -0,0 +1,38 @@ +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests +{ + public class GraphUpdatesMySqlClientNoActionTest : GraphUpdatesMySqlTestBase + { + public GraphUpdatesMySqlClientNoActionTest(MySqlFixture fixture) + : base(fixture) + { + } + + protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) + => facade.UseTransaction(transaction.GetDbTransaction()); + + public class MySqlFixture : GraphUpdatesMySqlFixtureBase + { + public override bool ForceClientNoAction + => true; + + protected override string StoreName { get; } = "GraphClientNoActionUpdatesTest"; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + foreach (var foreignKey in modelBuilder.Model + .GetEntityTypes() + .SelectMany(e => e.GetDeclaredForeignKeys())) + { + foreignKey.DeleteBehavior = DeleteBehavior.ClientNoAction; + } + } + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlTest.cs deleted file mode 100644 index 2475e859c..000000000 --- a/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlTest.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System.Linq; -using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.TestUtilities; - -namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests -{ - public class GraphUpdatesMySqlTest - { - public class ClientCascade : GraphUpdatesMySqlTestBase - { - public ClientCascade(MySqlFixture fixture) - : base(fixture) - { - } - - protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) - => facade.UseTransaction(transaction.GetDbTransaction()); - - public class MySqlFixture : GraphUpdatesMySqlFixtureBase - { - public override bool NoStoreCascades - => true; - - protected override string StoreName { get; } = "GraphClientCascadeUpdatesTest"; - - protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) - { - base.OnModelCreating(modelBuilder, context); - - foreach (var foreignKey in modelBuilder.Model - .GetEntityTypes() - .SelectMany(e => e.GetDeclaredForeignKeys()) - .Where(e => e.DeleteBehavior == DeleteBehavior.Cascade)) - { - foreignKey.DeleteBehavior = DeleteBehavior.ClientCascade; - } - } - } - } - - public class ClientNoAction : GraphUpdatesMySqlTestBase - { - public ClientNoAction(MySqlFixture fixture) - : base(fixture) - { - } - - protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) - => facade.UseTransaction(transaction.GetDbTransaction()); - - public class MySqlFixture : GraphUpdatesMySqlFixtureBase - { - public override bool ForceClientNoAction - => true; - - protected override string StoreName { get; } = "GraphClientNoActionUpdatesTest"; - - protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) - { - base.OnModelCreating(modelBuilder, context); - - foreach (var foreignKey in modelBuilder.Model - .GetEntityTypes() - .SelectMany(e => e.GetDeclaredForeignKeys())) - { - foreignKey.DeleteBehavior = DeleteBehavior.ClientNoAction; - } - } - } - } - - // TODO: UseIdentityColumns() - // public class Identity : GraphUpdatesMySqlTestBase - // { - // public Identity(MySqlFixture fixture) - // : base(fixture) - // { - // } - // - // protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) - // => facade.UseTransaction(transaction.GetDbTransaction()); - // - // public class MySqlFixture : GraphUpdatesMySqlFixtureBase - // { - // protected override string StoreName { get; } = "GraphIdentityUpdatesTest"; - // - // protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) - // { - // modelBuilder.UseIdentityColumns(); - // - // base.OnModelCreating(modelBuilder, context); - // } - // } - // } - - public abstract class GraphUpdatesMySqlTestBase : GraphUpdatesTestBase - where TFixture : GraphUpdatesMySqlTestBase.GraphUpdatesMySqlFixtureBase, new() - { - protected GraphUpdatesMySqlTestBase(TFixture fixture) - : base(fixture) - { - } - - protected override IQueryable ModifyQueryRoot(IQueryable query) - => query.AsSplitQuery(); - - protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) - => facade.UseTransaction(transaction.GetDbTransaction()); - - public abstract class GraphUpdatesMySqlFixtureBase : GraphUpdatesFixtureBase - { - public TestSqlLoggerFactory TestSqlLoggerFactory - => (TestSqlLoggerFactory)ListLoggerFactory; - - protected override ITestStoreFactory TestStoreFactory - => MySqlTestStoreFactory.Instance; - - protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) - { - base.OnModelCreating(modelBuilder, context); - - modelBuilder.Entity( - b => - { - b.Property(e => e.AccessStateId).ValueGeneratedNever(); - b.HasData(new AccessState {AccessStateId = 1}); - }); - - modelBuilder.Entity( - b => - { - b.Property(e => e.IdUserState).HasDefaultValue(1); - b.HasOne(e => e.UserState).WithMany(e => e.Users).HasForeignKey(e => e.IdUserState); - }); - } - } - } - } -} diff --git a/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlTestBase.cs b/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlTestBase.cs new file mode 100644 index 000000000..cc1d34baa --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/GraphUpdatesMySqlTestBase.cs @@ -0,0 +1,54 @@ +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests; + +public abstract class GraphUpdatesMySqlTestBase : GraphUpdatesTestBase + where TFixture : GraphUpdatesMySqlTestBase.GraphUpdatesMySqlFixtureBase, new() +{ + protected GraphUpdatesMySqlTestBase(TFixture fixture) + : base(fixture) + { + } + + protected override IQueryable ModifyQueryRoot(IQueryable query) + => query.AsSplitQuery(); + + protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) + => facade.UseTransaction(transaction.GetDbTransaction()); + + public abstract class GraphUpdatesMySqlFixtureBase : GraphUpdatesFixtureBase + { + public TestSqlLoggerFactory TestSqlLoggerFactory + => (TestSqlLoggerFactory)ListLoggerFactory; + + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity( + b => + { + b.Property(e => e.AccessStateId).ValueGeneratedNever(); + b.HasData(new AccessState {AccessStateId = 1}); + }); + + modelBuilder.Entity( + b => + { + b.Property(e => e.IdUserState).HasDefaultValue(1); + b.HasOne(e => e.UserState).WithMany(e => e.Users).HasForeignKey(e => e.IdUserState); + }); + + modelBuilder.Entity().Property("CategoryId").HasDefaultValue(1); + modelBuilder.Entity().Property(e => e.CategoryId).HasDefaultValue(2); + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/LoggingMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/LoggingMySqlTest.cs index 2871468cc..e504a1d3b 100644 --- a/test/EFCore.MySql.FunctionalTests/LoggingMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/LoggingMySqlTest.cs @@ -3,7 +3,9 @@ using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.Extensions.DependencyInjection; +using Pomelo.EntityFrameworkCore.MySql.Diagnostics.Internal; using Pomelo.EntityFrameworkCore.MySql.Tests; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests @@ -22,6 +24,9 @@ protected override DbContextOptionsBuilder CreateOptionsBuilder( .UseInternalServiceProvider(services.AddEntityFrameworkMySql().BuildServiceProvider(validateScopes: true)) .UseMySql("Database=DummyDatabase", AppConfig.ServerVersion, relationalAction); + protected override TestLogger CreateTestLogger() + => new TestLogger(); + protected override string ProviderName => "Pomelo.EntityFrameworkCore.MySql"; protected override string ProviderVersion => typeof(MySqlOptionsExtension).Assembly diff --git a/test/EFCore.MySql.FunctionalTests/ManyToManyTrackingMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/ManyToManyTrackingMySqlTest.cs index 9c3a4dd38..117c9f617 100644 --- a/test/EFCore.MySql.FunctionalTests/ManyToManyTrackingMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/ManyToManyTrackingMySqlTest.cs @@ -10,6 +10,8 @@ public ManyToManyTrackingMySqlTest(ManyToManyTrackingMySqlFixture fixture) public class ManyToManyTrackingMySqlFixture : ManyToManyTrackingMySqlFixtureBase { + protected override string StoreName + => "ManyToManyTrackingMySqlTest"; } } } diff --git a/test/EFCore.MySql.FunctionalTests/ManyToManyTrackingMySqlTestBase.cs b/test/EFCore.MySql.FunctionalTests/ManyToManyTrackingMySqlTestBase.cs index 299c2c36c..82fd8de7f 100644 --- a/test/EFCore.MySql.FunctionalTests/ManyToManyTrackingMySqlTestBase.cs +++ b/test/EFCore.MySql.FunctionalTests/ManyToManyTrackingMySqlTestBase.cs @@ -1,15 +1,22 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Threading; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata.Builders; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; using Microsoft.EntityFrameworkCore.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Tests; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests { - public abstract class ManyToManyTrackingMySqlTestBase : ManyToManyTrackingTestBase - where TFixture : ManyToManyTrackingTestBase.ManyToManyTrackingFixtureBase + public abstract class ManyToManyTrackingMySqlTestBase : ManyToManyTrackingRelationalTestBase + where TFixture : ManyToManyTrackingMySqlTestBase.ManyToManyTrackingMySqlFixtureBase { protected ManyToManyTrackingMySqlTestBase(TFixture fixture) : base(fixture) @@ -19,7 +26,7 @@ protected ManyToManyTrackingMySqlTestBase(TFixture fixture) protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) => facade.UseTransaction(transaction.GetDbTransaction()); - public class ManyToManyTrackingMySqlFixtureBase : ManyToManyTrackingFixtureBase + public class ManyToManyTrackingMySqlFixtureBase : ManyToManyTrackingRelationalFixture { protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; @@ -27,10 +34,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con { base.OnModelCreating(modelBuilder, context); - modelBuilder + var propertyBuilder = modelBuilder .Entity() - .Property(e => e.Payload) - .ValueGeneratedOnAdd(); // uses UTC in the original SQL Server implementation + .Property(e => e.Payload); + + SetupUtcDefaultValue(propertyBuilder); modelBuilder .SharedTypeEntity>("JoinOneToThreePayloadFullShared") @@ -43,6 +51,82 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con .Property(e => e.Payload) .HasMaxLength(255) // longtext does not support default values .HasDefaultValue("Generated"); + + propertyBuilder = modelBuilder + .Entity() + .Property(e => e.Payload); + + SetupUtcDefaultValue(propertyBuilder); + + modelBuilder + .SharedTypeEntity>("UnidirectionalJoinOneToThreePayloadFullShared") + .IndexerProperty("Payload") + .HasMaxLength(255) // longtext does not support default values + .HasDefaultValue("Generated"); + + modelBuilder + .Entity() + .Property(e => e.Payload) + .HasMaxLength(255) // longtext does not support default values + .HasDefaultValue("Generated"); + } + + private void SetupUtcDefaultValue(PropertyBuilder propertyBuilder) + { + // The original SQL Server implementation uses GETUTCDATE(). + if (SupportsDefaultExpressions) + { + propertyBuilder + .HasDefaultValueSql("(UTC_TIMESTAMP())"); + } + else + { + // This is the same as using .HasDefaultValueSql("CURRENT_TIMESTAMP()"); + propertyBuilder + .ValueGeneratedOnAdd(); + } + } + + protected virtual bool SupportsDefaultExpressions + => AppConfig.ServerVersion.Supports.DefaultExpression || + AppConfig.ServerVersion.Supports.AlternativeDefaultExpression; + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + { + var optionsBuilder = base.AddOptions(builder); + + // To support the Can_insert_many_to_many_self_with_payload_unidirectional test, a UTC_TIMESTAMP would need to be set as the + // column default value. Since this depends on default value expression support, we explicitly check for that. + // As a workaround for server versions that do not support default value expressions, we will set the default session + // timezone to UTC and just use a regular CURRENT_TIMESTAMP for the column default value in question. + if (!SupportsDefaultExpressions) + { + optionsBuilder + .AddInterceptors(new SessionInitializingConnectionInterceptor()); + } + + return optionsBuilder; + } + + private class SessionInitializingConnectionInterceptor : DbConnectionInterceptor + { + public override void ConnectionOpened(DbConnection connection, ConnectionEndEventData eventData) + => InitializeSession(connection); + + public override Task ConnectionOpenedAsync(DbConnection connection, + ConnectionEndEventData eventData, + CancellationToken cancellationToken = new CancellationToken()) + { + InitializeSession(connection); + return Task.CompletedTask; + } + + private static void InitializeSession(DbConnection connection) + { + using var command = connection.CreateCommand(); + command.CommandText = "SET @@session.time_zone = '+00:00'"; + command.ExecuteNonQuery(); + } } } } diff --git a/test/EFCore.MySql.FunctionalTests/MaterializationInterceptionMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/MaterializationInterceptionMySqlTest.cs new file mode 100644 index 000000000..8861ef23a --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/MaterializationInterceptionMySqlTest.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.Extensions.DependencyInjection; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Storage.Internal; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests; + +public class MaterializationInterceptionMySqlTest : MaterializationInterceptionTestBase, + IClassFixture +{ + public MaterializationInterceptionMySqlTest(MaterializationInterceptionMySqlFixture fixture) + : base(fixture) + { + } + + public class MaterializationInterceptionMySqlFixture : SingletonInterceptorsFixtureBase + { + protected override string StoreName + => "MaterializationInterception"; + + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + protected override IServiceCollection InjectInterceptors( + IServiceCollection serviceCollection, + IEnumerable injectedInterceptors) + => base.InjectInterceptors(serviceCollection.AddEntityFrameworkMySql(), injectedInterceptors); + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + { + new MySqlDbContextOptionsBuilder(base.AddOptions(builder)) + .ExecutionStrategy(d => new MySqlExecutionStrategy(d)); + return builder; + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/MigrationsMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/MigrationsMySqlTest.cs index 7f4b5a01f..0dfe9f338 100644 --- a/test/EFCore.MySql.FunctionalTests/MigrationsMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/MigrationsMySqlTest.cs @@ -4,7 +4,10 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Conventions; using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Design; using Microsoft.EntityFrameworkCore.Scaffolding; using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; using Microsoft.EntityFrameworkCore.TestUtilities; @@ -267,9 +270,15 @@ await Test( } [ConditionalTheory(Skip = "TODO")] - public override Task Add_primary_key() + public override Task Add_primary_key_int() { - return base.Add_primary_key(); + return base.Add_primary_key_int(); + } + + [ConditionalTheory(Skip = "TODO")] + public override async Task Add_primary_key_string() + { + await base.Add_primary_key_string(); } [ConditionalTheory(Skip = "TODO")] @@ -314,13 +323,42 @@ public override Task Alter_column_set_collation() return base.Alter_column_set_collation(); } - [ConditionalTheory(Skip = "TODO")] - public override Task Alter_sequence_all_settings() + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] + public override async Task Alter_sequence_all_settings() { - return base.Alter_sequence_all_settings(); + await Test( + builder => builder.HasSequence("foo"), + builder => { }, + builder => builder.HasSequence("foo") + .StartsAt(-3) + .IncrementsBy(2) + .HasMin(-5) + .HasMax(10) + .IsCyclic(), + model => + { + var sequence = Assert.Single(model.Sequences); + + // Assert.Equal(-3, sequence.StartValue); + Assert.Equal(1, sequence.StartValue); // Restarting doesn't change the scaffolded start value + + Assert.Equal(2, sequence.IncrementBy); + Assert.Equal(-5, sequence.MinValue); + Assert.Equal(10, sequence.MaxValue); + Assert.True(sequence.IsCyclic); + }); + + AssertSql( + """ +ALTER SEQUENCE `foo` INCREMENT BY 2 MINVALUE -5 MAXVALUE 10 CYCLE; +""", + // + """ +ALTER SEQUENCE `foo` RESTART WITH -3; +"""); } - [ConditionalTheory(Skip = "TODO")] + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] public override Task Alter_sequence_increment_by() { return base.Alter_sequence_increment_by(); @@ -346,16 +384,54 @@ public override Task Create_schema() return base.Create_schema(); } - [ConditionalTheory(Skip = "TODO")] + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] public override Task Create_sequence() { return base.Create_sequence(); } - [ConditionalTheory(Skip = "TODO")] - public override Task Create_sequence_all_settings() + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] + public override Task Create_sequence_long() { - return base.Create_sequence_all_settings(); + return base.Create_sequence_long(); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] + public override Task Create_sequence_short() + { + return base.Create_sequence_short(); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] + public override async Task Create_sequence_all_settings() + { + await Test( + builder => { }, + builder => builder.HasSequence("TestSequence", "dbo2") + .StartsAt(3) + .IncrementsBy(2) + .HasMin(2) + .HasMax(916) + .IsCyclic(), + model => + { + var sequence = Assert.Single(model.Sequences); + + // Assert.Equal("TestSequence", sequence.Name); + // Assert.Equal("dbo2", sequence.Schema); + Assert.Equal("dbo2_TestSequence", sequence.Name); + + Assert.Equal(3, sequence.StartValue); + Assert.Equal(2, sequence.IncrementBy); + Assert.Equal(2, sequence.MinValue); + Assert.Equal(916, sequence.MaxValue); + Assert.True(sequence.IsCyclic); + }); + + AssertSql( +""" +CREATE SEQUENCE `dbo2_TestSequence` START WITH 3 INCREMENT BY 2 MINVALUE 2 MAXVALUE 916 CYCLE; +"""); } [ConditionalTheory(Skip = "TODO")] @@ -370,11 +446,12 @@ public override async Task Create_table_with_multiline_comments() AssertSql( @"CREATE TABLE `People` ( - `Id` int NOT NULL, + `Id` int NOT NULL AUTO_INCREMENT, `Name` longtext CHARACTER SET utf8mb4 NULL COMMENT 'This is a multi-line column comment. More information can -be found in the docs.' +be found in the docs.', + CONSTRAINT `PK_People` PRIMARY KEY (`Id`) ) CHARACTER SET=utf8mb4 COMMENT='This is a multi-line table comment. More information can @@ -387,6 +464,35 @@ public override Task Create_unique_index_with_filter() return base.Create_unique_index_with_filter(); } + [SupportedServerVersionCondition(nameof(ServerVersionSupport.DescendingIndexes))] + public override async Task Create_index_descending() + { + await base.Create_index_descending(); + + AssertSql( + @"CREATE INDEX `IX_People_X` ON `People` (`X` DESC);"); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.DescendingIndexes))] + public override async Task Create_index_descending_mixed() + { + await base.Create_index_descending_mixed(); + + AssertSql( + @"CREATE INDEX `IX_People_X_Y_Z` ON `People` (`X`, `Y` DESC, `Z`);"); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.DescendingIndexes))] + public override async Task Alter_index_change_sort_order() + { + await base.Alter_index_change_sort_order(); + + AssertSql( + @"ALTER TABLE `People` DROP INDEX `IX_People_X_Y_Z`;", + // + @"CREATE INDEX `IX_People_X_Y_Z` ON `People` (`X`, `Y` DESC, `Z`);"); + } + [ConditionalTheory(Skip = "TODO: Syntax issue in MySQL 7 only.")] public override Task Drop_check_constraint() { @@ -400,21 +506,41 @@ public override Task Drop_column_primary_key() } [ConditionalTheory(Skip = "TODO")] - public override Task Drop_primary_key() + public override Task Drop_primary_key_int() { - return base.Drop_primary_key(); + return base.Drop_primary_key_int(); } [ConditionalTheory(Skip = "TODO")] + public override async Task Drop_primary_key_string() + { + await base.Drop_primary_key_string(); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] public override Task Drop_sequence() { return base.Drop_sequence(); } - [ConditionalTheory(Skip = "TODO")] - public override Task Move_sequence() + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] + public override async Task Move_sequence() { - return base.Move_sequence(); + await Test( + builder => builder.HasSequence("TestSequenceMove"), + builder => builder.HasSequence("TestSequenceMove", "TestSequenceSchema"), + model => + { + var sequence = Assert.Single(model.Sequences); + // Assert.Equal("TestSequenceSchema", sequence.Schema); + // Assert.Equal("TestSequence", sequence.Name); + Assert.Equal("TestSequenceSchema_TestSequenceMove", sequence.Name); + }); + + AssertSql( +""" +ALTER TABLE `TestSequenceMove` RENAME `TestSequenceSchema_TestSequenceMove`; +"""); } [ConditionalTheory(Skip = "TODO")] @@ -423,10 +549,15 @@ public override Task Move_table() return base.Move_table(); } - [ConditionalTheory(Skip = "TODO")] - public override Task Rename_sequence() + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Sequences))] + public override async Task Rename_sequence() { - return base.Rename_sequence(); + await base.Rename_sequence(); + + AssertSql( +""" +ALTER TABLE `TestSequence` RENAME `testsequence`; +"""); } [ConditionalTheory(Skip = "TODO")] @@ -535,9 +666,10 @@ await Test( }); AssertSql( - $@"CREATE TABLE `IceCream` ( - `IceCreamId` int NOT NULL, - `Name` NVARCHAR(45) NULL + @"CREATE TABLE `IceCream` ( + `IceCreamId` int NOT NULL AUTO_INCREMENT, + `Name` NVARCHAR(45) NULL, + CONSTRAINT `PK_IceCream` PRIMARY KEY (`IceCreamId`) ) CHARACTER SET=utf8mb4;"); } @@ -564,7 +696,8 @@ await Test( $@"ALTER DATABASE COLLATE {DefaultCollation};", // $@"CREATE TABLE `IceCream` ( - `IceCreamId` char(36) COLLATE ascii_general_ci NOT NULL + `IceCreamId` char(36) COLLATE ascii_general_ci NOT NULL, + CONSTRAINT `PK_IceCream` PRIMARY KEY (`IceCreamId`) ) COLLATE={DefaultCollation};"); } @@ -592,7 +725,8 @@ await Test( $@"ALTER DATABASE COLLATE {DefaultCollation};", // $@"CREATE TABLE `IceCream` ( - `IceCreamId` char(36) COLLATE {NonDefaultCollation} NOT NULL + `IceCreamId` char(36) COLLATE {NonDefaultCollation} NOT NULL, + CONSTRAINT `PK_IceCream` PRIMARY KEY (`IceCreamId`) ) COLLATE={DefaultCollation};"); } @@ -620,7 +754,8 @@ await Test( $@"ALTER DATABASE COLLATE {DefaultCollation};", // $@"CREATE TABLE `IceCream` ( - `IceCreamId` char(36) COLLATE {NonDefaultCollation} NOT NULL + `IceCreamId` char(36) COLLATE {NonDefaultCollation} NOT NULL, + CONSTRAINT `PK_IceCream` PRIMARY KEY (`IceCreamId`) ) COLLATE={DefaultCollation};"); } @@ -648,7 +783,8 @@ await Test( $@"ALTER DATABASE COLLATE {DefaultCollation};", // $@"CREATE TABLE `IceCream` ( - `IceCreamId` char(36) NOT NULL + `IceCreamId` char(36) NOT NULL, + CONSTRAINT `PK_IceCream` PRIMARY KEY (`IceCreamId`) ) COLLATE={DefaultCollation};"); } @@ -771,6 +907,17 @@ await Test( result => { }); AssertSql( + @"set @__pomelo_TableCharset = ( + SELECT `ccsa`.`CHARACTER_SET_NAME` as `TABLE_CHARACTER_SET` + FROM `INFORMATION_SCHEMA`.`TABLES` as `t` + LEFT JOIN `INFORMATION_SCHEMA`.`COLLATION_CHARACTER_SET_APPLICABILITY` as `ccsa` ON `ccsa`.`COLLATION_NAME` = `t`.`TABLE_COLLATION` + WHERE `TABLE_SCHEMA` = SCHEMA() AND `TABLE_NAME` = 'IceCream' AND `TABLE_TYPE` IN ('BASE TABLE', 'VIEW')); + +SET @__pomelo_SqlExpr = CONCAT('ALTER TABLE `IceCream` CHARACTER SET = ', @__pomelo_TableCharset, ';'); +PREPARE __pomelo_SqlExprExecute FROM @__pomelo_SqlExpr; +EXECUTE __pomelo_SqlExprExecute; +DEALLOCATE PREPARE __pomelo_SqlExprExecute;", + // $@"ALTER TABLE `IceCream` MODIFY COLUMN `Name` longtext COLLATE {NonDefaultCollation} NULL;", // $@"ALTER TABLE `IceCream` MODIFY COLUMN `Brand` longtext COLLATE {NonDefaultCollation2} NULL;"); @@ -811,8 +958,6 @@ await Test( result => { }); AssertSql( - $@"ALTER TABLE `IceCream` COLLATE={DefaultCollation};", - // $@"ALTER TABLE `IceCream` MODIFY COLUMN `Name` longtext COLLATE {NonDefaultCollation} NULL;", // $@"ALTER TABLE `IceCream` MODIFY COLUMN `Brand` longtext COLLATE {NonDefaultCollation2} NULL;"); @@ -907,9 +1052,10 @@ await Test( $@"ALTER DATABASE COLLATE {DefaultCollation};", // $@"CREATE TABLE `IceCream` ( + `IceCreamId` int NOT NULL AUTO_INCREMENT, `Brand` longtext CHARACTER SET {NonDefaultCharSet} NULL, - `IceCreamId` int NOT NULL, - `Name` longtext COLLATE {DefaultCollation} NULL + `Name` longtext COLLATE {DefaultCollation} NULL, + CONSTRAINT `PK_IceCream` PRIMARY KEY (`IceCreamId`) ) COLLATE={DefaultCollation};"); } @@ -946,9 +1092,10 @@ await Test( $@"ALTER DATABASE CHARACTER SET {NonDefaultCharSet};", // $@"CREATE TABLE `IceCream` ( + `IceCreamId` int NOT NULL AUTO_INCREMENT, `Brand` longtext COLLATE {NonDefaultCollation2} NULL, - `IceCreamId` int NOT NULL, - `Name` longtext CHARACTER SET {NonDefaultCharSet} NULL + `Name` longtext CHARACTER SET {NonDefaultCharSet} NULL, + CONSTRAINT `PK_IceCream` PRIMARY KEY (`IceCreamId`) ) CHARACTER SET={NonDefaultCharSet};"); } @@ -979,8 +1126,9 @@ await Test( AssertSql( $@"CREATE TABLE `IceCream` ( - `IceCreamId` int NOT NULL, - `Name` longtext CHARACTER SET {NonDefaultCharSet} NULL + `IceCreamId` int NOT NULL AUTO_INCREMENT, + `Name` longtext CHARACTER SET {NonDefaultCharSet} NULL, + CONSTRAINT `PK_IceCream` PRIMARY KEY (`IceCreamId`) ) CHARACTER SET=utf8mb4;"); } @@ -1125,7 +1273,7 @@ await Test( // @"ALTER TABLE `Foo` DROP KEY `AK_Foo_FooAK`;", // - @"ALTER TABLE `Foo` ADD CONSTRAINT `FK_Foo_Bar_BarFK` FOREIGN KEY (`BarFK`) REFERENCES `Bar` (`BarPK`);"); + @"ALTER TABLE `Foo` ADD CONSTRAINT `FK_Foo_Bar_BarFK` FOREIGN KEY (`BarFK`) REFERENCES `Bar` (`BarPK`) ON DELETE CASCADE;"); } public override async Task Add_foreign_key() @@ -1133,9 +1281,22 @@ public override async Task Add_foreign_key() await base.Add_foreign_key(); AssertSql( - @"ALTER TABLE `Orders` ADD CONSTRAINT `FK_Orders_Customers_CustomerId` FOREIGN KEY (`CustomerId`) REFERENCES `Customers` (`Id`);"); + @"CREATE INDEX `IX_Orders_CustomerId` ON `Orders` (`CustomerId`);", + // + @"ALTER TABLE `Orders` ADD CONSTRAINT `FK_Orders_Customers_CustomerId` FOREIGN KEY (`CustomerId`) REFERENCES `Customers` (`Id`) ON DELETE CASCADE;"); } + public override Task Rename_table() + => Test( + builder => builder.Entity("People").Property("Id"), + builder => builder.Entity("People").ToTable("Persons").Property("Id"), + model => + { + var table = Assert.Single(model.Tables); + Assert.Equal("Persons", table.Name); + }, + withConventions: false); + protected virtual string DefaultCollation => ((MySqlTestStore)Fixture.TestStore).DatabaseCollation; protected override string NonDefaultCollation @@ -1157,22 +1318,32 @@ protected virtual Task Test( Action buildSourceAction, Action buildTargetAction, Action migrationBuilderAction, - Action asserter) + Action asserter, + bool withConventions = true) { var services = TestHelpers.CreateContextServices(); + var modelRuntimeInitializer = services.GetRequiredService(); - // Build the source and target models. Add current/latest product version if one wasn't set. - var sourceModelBuilder = CreateConventionlessModelBuilder(); + // Build the source model, possibly with conventions + var sourceModelBuilder = CreateModelBuilder(withConventions); buildCommonAction(sourceModelBuilder); buildSourceAction(sourceModelBuilder); - var sourceModel = services.GetRequiredService() - .Initialize(sourceModelBuilder.FinalizeModel(), designTime: true, validationLogger: null); - - var targetModelBuilder = CreateConventionlessModelBuilder(); + var preSnapshotSourceModel = modelRuntimeInitializer.Initialize( + (IModel)sourceModelBuilder.Model, designTime: true, validationLogger: null); + + // Round-trip the source model through a snapshot, compiling it and then extracting it back again. + // This simulates the real-world migration flow and can expose errors in snapshot generation + var migrationsCodeGenerator = Fixture.TestHelpers.CreateDesignServiceProvider().GetRequiredService(); + var sourceModelSnapshot = migrationsCodeGenerator.GenerateSnapshot( + modelSnapshotNamespace: null, typeof(DbContext), "MigrationsTestSnapshot", preSnapshotSourceModel); + var sourceModel = BuildModelFromSnapshotSource(sourceModelSnapshot); + + // Build the target model, possibly with conventions + var targetModelBuilder = CreateModelBuilder(withConventions); buildCommonAction(targetModelBuilder); buildTargetAction(targetModelBuilder); - var targetModel = services.GetRequiredService() - .Initialize(targetModelBuilder.FinalizeModel(), designTime: true, validationLogger: null); + var targetModel = modelRuntimeInitializer.Initialize( + (IModel)targetModelBuilder.Model, designTime: true, validationLogger: null); var migrationBuilder = new MigrationBuilder(null); migrationBuilderAction(migrationBuilder); @@ -1180,13 +1351,16 @@ protected virtual Task Test( return Test(sourceModel, targetModel, migrationBuilder.Operations, asserter); } + private ModelBuilder CreateModelBuilder(bool withConventions) + => withConventions ? Fixture.TestHelpers.CreateConventionBuilder() : new ModelBuilder(new ConventionSet()); + public class MigrationsMySqlFixture : MigrationsFixtureBase { protected override string StoreName => nameof(MigrationsMySqlTest); protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; - public override TestHelpers TestHelpers => MySqlTestHelpers.Instance; + public override RelationalTestHelpers TestHelpers => MySqlTestHelpers.Instance; public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) { diff --git a/test/EFCore.MySql.FunctionalTests/MySqlComplianceTest.cs b/test/EFCore.MySql.FunctionalTests/MySqlComplianceTest.cs index 8f6e3e696..8d29abdc8 100644 --- a/test/EFCore.MySql.FunctionalTests/MySqlComplianceTest.cs +++ b/test/EFCore.MySql.FunctionalTests/MySqlComplianceTest.cs @@ -3,6 +3,7 @@ using System.Reflection; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Update; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests { @@ -18,7 +19,12 @@ public class MySqlComplianceTest : RelationalComplianceTestBase // TODO: Reenable LoggingMySqlTest once its issue has been fixed in EF Core upstream. typeof(LoggingTestBase), - typeof(LoggingRelationalTestBase<,>) + typeof(LoggingRelationalTestBase<,>), + + // We have our own JSON support for now + typeof(JsonUpdateTestBase<>), + typeof(JsonQueryTestBase<>), + typeof(JsonQueryAdHocTestBase), }; protected override Assembly TargetAssembly { get; } = typeof(MySqlComplianceTest).Assembly; diff --git a/test/EFCore.MySql.FunctionalTests/MySqlMigrationsSqlGeneratorTest.cs b/test/EFCore.MySql.FunctionalTests/MySqlMigrationsSqlGeneratorTest.cs index d8af3638d..eb91eced8 100644 --- a/test/EFCore.MySql.FunctionalTests/MySqlMigrationsSqlGeneratorTest.cs +++ b/test/EFCore.MySql.FunctionalTests/MySqlMigrationsSqlGeneratorTest.cs @@ -123,21 +123,14 @@ public override void InsertDataOperation_all_args_spatial() AssertSql( @"INSERT INTO `People` (`Id`, `Full Name`, `Geometry`) -VALUES (0, NULL, NULL); -INSERT INTO `People` (`Id`, `Full Name`, `Geometry`) -VALUES (1, 'Daenerys Targaryen', NULL); -INSERT INTO `People` (`Id`, `Full Name`, `Geometry`) -VALUES (2, 'John Snow', NULL); -INSERT INTO `People` (`Id`, `Full Name`, `Geometry`) -VALUES (3, 'Arya Stark', NULL); -INSERT INTO `People` (`Id`, `Full Name`, `Geometry`) -VALUES (4, 'Harry Strickland', NULL); -INSERT INTO `People` (`Id`, `Full Name`, `Geometry`) -VALUES (5, 'The Imp', NULL); -INSERT INTO `People` (`Id`, `Full Name`, `Geometry`) -VALUES (6, 'The Kingslayer', NULL); -INSERT INTO `People` (`Id`, `Full Name`, `Geometry`) -VALUES (7, 'Aemon Targaryen', X'E61000000107000000080000000102000000040000009A9999999999F13F9A999999999901409A999999999901409A999999999901409A999999999901409A9999999999F13F6666666666661C40CDCCCCCCCCCC1C400102000000040000006666666666661C40CDCCCCCCCCCC1C403333333333333440333333333333344033333333333334409A9999999999F13F6666666666865140CDCCCCCCCC8C514001040000000300000001010000009A9999999999F13F9A9999999999014001010000009A999999999901409A9999999999014001010000009A999999999901409A9999999999F13F010300000001000000040000009A9999999999F13F9A999999999901409A999999999901409A999999999901409A999999999901409A9999999999F13F9A9999999999F13F9A99999999990140010300000001000000040000003333333333332440333333333333344033333333333334403333333333333440333333333333344033333333333324403333333333332440333333333333344001010000009A9999999999F13F9A999999999901400105000000020000000102000000040000009A9999999999F13F9A999999999901409A999999999901409A999999999901409A999999999901409A9999999999F13F6666666666661C40CDCCCCCCCCCC1C400102000000040000006666666666661C40CDCCCCCCCCCC1C403333333333333440333333333333344033333333333334409A9999999999F13F6666666666865140CDCCCCCCCC8C51400106000000020000000103000000010000000400000033333333333324403333333333333440333333333333344033333333333334403333333333333440333333333333244033333333333324403333333333333440010300000001000000040000009A9999999999F13F9A999999999901409A999999999901409A999999999901409A999999999901409A9999999999F13F9A9999999999F13F9A99999999990140');"); +VALUES (0, NULL, NULL), +(1, 'Daenerys Targaryen', NULL), +(2, 'John Snow', NULL), +(3, 'Arya Stark', NULL), +(4, 'Harry Strickland', NULL), +(5, 'The Imp', NULL), +(6, 'The Kingslayer', NULL), +(7, 'Aemon Targaryen', X'E61000000107000000080000000102000000040000009A9999999999F13F9A999999999901409A999999999901409A999999999901409A999999999901409A9999999999F13F6666666666661C40CDCCCCCCCCCC1C400102000000040000006666666666661C40CDCCCCCCCCCC1C403333333333333440333333333333344033333333333334409A9999999999F13F6666666666865140CDCCCCCCCC8C514001040000000300000001010000009A9999999999F13F9A9999999999014001010000009A999999999901409A9999999999014001010000009A999999999901409A9999999999F13F010300000001000000040000009A9999999999F13F9A999999999901409A999999999901409A999999999901409A999999999901409A9999999999F13F9A9999999999F13F9A99999999990140010300000001000000040000003333333333332440333333333333344033333333333334403333333333333440333333333333344033333333333324403333333333332440333333333333344001010000009A9999999999F13F9A999999999901400105000000020000000102000000040000009A9999999999F13F9A999999999901409A999999999901409A999999999901409A999999999901409A9999999999F13F6666666666661C40CDCCCCCCCCCC1C400102000000040000006666666666661C40CDCCCCCCCCCC1C403333333333333440333333333333344033333333333334409A9999999999F13F6666666666865140CDCCCCCCCC8C51400106000000020000000103000000010000000400000033333333333324403333333333333440333333333333344033333333333334403333333333333440333333333333244033333333333324403333333333333440010300000001000000040000009A9999999999F13F9A999999999901409A999999999901409A999999999901409A999999999901409A9999999999F13F9A9999999999F13F9A99999999990140');"); } public override void InsertDataOperation_required_args() @@ -164,9 +157,8 @@ public override void InsertDataOperation_required_args_multiple_rows() AssertSql( @"INSERT INTO `People` (`First Name`) -VALUES ('John'); -INSERT INTO `People` (`First Name`) -VALUES ('Daenerys');"); +VALUES ('John'), +('Daenerys');"); } public override void InsertDataOperation_throws_for_unsupported_column_types() @@ -178,8 +170,31 @@ public override void DeleteDataOperation_all_args() { base.DeleteDataOperation_all_args(); - AssertSql( - @"DELETE FROM `People` + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +DELETE FROM `People` +WHERE `First Name` = 'Hodor' +RETURNING 1; +DELETE FROM `People` +WHERE `First Name` = 'Daenerys' +RETURNING 1; +DELETE FROM `People` +WHERE `First Name` = 'John' +RETURNING 1; +DELETE FROM `People` +WHERE `First Name` = 'Arya' +RETURNING 1; +DELETE FROM `People` +WHERE `First Name` = 'Harry' +RETURNING 1; +"""); + } + else + { + AssertSql( + @"DELETE FROM `People` WHERE `First Name` = 'Hodor'; SELECT ROW_COUNT(); @@ -198,14 +213,38 @@ DELETE FROM `People` DELETE FROM `People` WHERE `First Name` = 'Harry'; SELECT ROW_COUNT();"); + } } public override void DeleteDataOperation_all_args_composite() { base.DeleteDataOperation_all_args_composite(); - AssertSql( - @"DELETE FROM `People` + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +DELETE FROM `People` +WHERE `First Name` = 'Hodor' AND `Last Name` IS NULL +RETURNING 1; +DELETE FROM `People` +WHERE `First Name` = 'Daenerys' AND `Last Name` = 'Targaryen' +RETURNING 1; +DELETE FROM `People` +WHERE `First Name` = 'John' AND `Last Name` = 'Snow' +RETURNING 1; +DELETE FROM `People` +WHERE `First Name` = 'Arya' AND `Last Name` = 'Stark' +RETURNING 1; +DELETE FROM `People` +WHERE `First Name` = 'Harry' AND `Last Name` = 'Strickland' +RETURNING 1; +"""); + } + else + { + AssertSql( + @"DELETE FROM `People` WHERE `First Name` = 'Hodor' AND `Last Name` IS NULL; SELECT ROW_COUNT(); @@ -224,26 +263,52 @@ DELETE FROM `People` DELETE FROM `People` WHERE `First Name` = 'Harry' AND `Last Name` = 'Strickland'; SELECT ROW_COUNT();"); + } } public override void DeleteDataOperation_required_args() { base.DeleteDataOperation_required_args(); - AssertSql( - @"DELETE FROM `People` + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +DELETE FROM `People` +WHERE `Last Name` = 'Snow' +RETURNING 1; +"""); + } + else + { + AssertSql( + @"DELETE FROM `People` WHERE `Last Name` = 'Snow'; SELECT ROW_COUNT();"); + } } public override void DeleteDataOperation_required_args_composite() { base.DeleteDataOperation_required_args_composite(); - AssertSql( - @"DELETE FROM `People` + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +DELETE FROM `People` +WHERE `First Name` = 'John' AND `Last Name` = 'Snow' +RETURNING 1; +"""); + } + else + { + AssertSql( + @"DELETE FROM `People` WHERE `First Name` = 'John' AND `Last Name` = 'Snow'; SELECT ROW_COUNT();"); + } + } public override void UpdateDataOperation_all_args() @@ -363,6 +428,17 @@ public override void DefaultValue_with_line_breaks(bool isUnicode) );"); } + [SupportedServerVersionCondition(nameof(ServerVersionSupport.DefaultExpression), nameof(ServerVersionSupport.AlternativeDefaultExpression))] + public override void DefaultValue_with_line_breaks_2(bool isUnicode) + { + base.DefaultValue_with_line_breaks_2(isUnicode); + + AssertSql( + @"CREATE TABLE `TestLineBreaks` ( + `TestDefaultValue` longtext NOT NULL DEFAULT (CONCAT('0', CHAR(13, 10), '1', CHAR(13, 10), '2', CHAR(13, 10), '3', CHAR(13, 10), '4', CHAR(13, 10), '5', CHAR(13, 10), '6', CHAR(13, 10), '7', CHAR(13, 10), '8', CHAR(13, 10), '9', CHAR(13, 10), '10', CHAR(13, 10), '11', CHAR(13, 10), '12', CHAR(13, 10), '13', CHAR(13, 10), '14', CHAR(13, 10), '15', CHAR(13, 10), '16', CHAR(13, 10), '17', CHAR(13, 10), '18', CHAR(13, 10), '19', CHAR(13, 10), '20', CHAR(13, 10), '21', CHAR(13, 10), '22', CHAR(13, 10), '23', CHAR(13, 10), '24', CHAR(13, 10), '25', CHAR(13, 10), '26', CHAR(13, 10), '27', CHAR(13, 10), '28', CHAR(13, 10), '29', CHAR(13, 10), '30', CHAR(13, 10), '31', CHAR(13, 10), '32', CHAR(13, 10), '33', CHAR(13, 10), '34', CHAR(13, 10), '35', CHAR(13, 10), '36', CHAR(13, 10), '37', CHAR(13, 10), '38', CHAR(13, 10), '39', CHAR(13, 10), '40', CHAR(13, 10), '41', CHAR(13, 10), '42', CHAR(13, 10), '43', CHAR(13, 10), '44', CHAR(13, 10), '45', CHAR(13, 10), '46', CHAR(13, 10), '47', CHAR(13, 10), '48', CHAR(13, 10), '49', CHAR(13, 10), '50', CHAR(13, 10), '51', CHAR(13, 10), '52', CHAR(13, 10), '53', CHAR(13, 10), '54', CHAR(13, 10), '55', CHAR(13, 10), '56', CHAR(13, 10), '57', CHAR(13, 10), '58', CHAR(13, 10), '59', CHAR(13, 10), '60', CHAR(13, 10), '61', CHAR(13, 10), '62', CHAR(13, 10), '63', CHAR(13, 10), '64', CHAR(13, 10), '65', CHAR(13, 10), '66', CHAR(13, 10), '67', CHAR(13, 10), '68', CHAR(13, 10), '69', CHAR(13, 10), '70', CHAR(13, 10), '71', CHAR(13, 10), '72', CHAR(13, 10), '73', CHAR(13, 10), '74', CHAR(13, 10), '75', CHAR(13, 10), '76', CHAR(13, 10), '77', CHAR(13, 10), '78', CHAR(13, 10), '79', CHAR(13, 10), '80', CHAR(13, 10), '81', CHAR(13, 10), '82', CHAR(13, 10), '83', CHAR(13, 10), '84', CHAR(13, 10), '85', CHAR(13, 10), '86', CHAR(13, 10), '87', CHAR(13, 10), '88', CHAR(13, 10), '89', CHAR(13, 10), '90', CHAR(13, 10), '91', CHAR(13, 10), '92', CHAR(13, 10), '93', CHAR(13, 10), '94', CHAR(13, 10), '95', CHAR(13, 10), '96', CHAR(13, 10), '97', CHAR(13, 10), '98', CHAR(13, 10), '99', CHAR(13, 10), '100', CHAR(13, 10), '101', CHAR(13, 10), '102', CHAR(13, 10), '103', CHAR(13, 10), '104', CHAR(13, 10), '105', CHAR(13, 10), '106', CHAR(13, 10), '107', CHAR(13, 10), '108', CHAR(13, 10), '109', CHAR(13, 10), '110', CHAR(13, 10), '111', CHAR(13, 10), '112', CHAR(13, 10), '113', CHAR(13, 10), '114', CHAR(13, 10), '115', CHAR(13, 10), '116', CHAR(13, 10), '117', CHAR(13, 10), '118', CHAR(13, 10), '119', CHAR(13, 10), '120', CHAR(13, 10), '121', CHAR(13, 10), '122', CHAR(13, 10), '123', CHAR(13, 10), '124', CHAR(13, 10), '125', CHAR(13, 10), '126', CHAR(13, 10), '127', CHAR(13, 10), '128', CHAR(13, 10), '129', CHAR(13, 10), '130', CHAR(13, 10), '131', CHAR(13, 10), '132', CHAR(13, 10), '133', CHAR(13, 10), '134', CHAR(13, 10), '135', CHAR(13, 10), '136', CHAR(13, 10), '137', CHAR(13, 10), '138', CHAR(13, 10), '139', CHAR(13, 10), '140', CHAR(13, 10), '141', CHAR(13, 10), '142', CHAR(13, 10), '143', CHAR(13, 10), '144', CHAR(13, 10), '145', CHAR(13, 10), '146', CHAR(13, 10), '147', CHAR(13, 10), '148', CHAR(13, 10), '149', CHAR(13, 10), '150', CHAR(13, 10), '151', CHAR(13, 10), '152', CHAR(13, 10), '153', CHAR(13, 10), '154', CHAR(13, 10), '155', CHAR(13, 10), '156', CHAR(13, 10), '157', CHAR(13, 10), '158', CHAR(13, 10), '159', CHAR(13, 10), '160', CHAR(13, 10), '161', CHAR(13, 10), '162', CHAR(13, 10), '163', CHAR(13, 10), '164', CHAR(13, 10), '165', CHAR(13, 10), '166', CHAR(13, 10), '167', CHAR(13, 10), '168', CHAR(13, 10), '169', CHAR(13, 10), '170', CHAR(13, 10), '171', CHAR(13, 10), '172', CHAR(13, 10), '173', CHAR(13, 10), '174', CHAR(13, 10), '175', CHAR(13, 10), '176', CHAR(13, 10), '177', CHAR(13, 10), '178', CHAR(13, 10), '179', CHAR(13, 10), '180', CHAR(13, 10), '181', CHAR(13, 10), '182', CHAR(13, 10), '183', CHAR(13, 10), '184', CHAR(13, 10), '185', CHAR(13, 10), '186', CHAR(13, 10), '187', CHAR(13, 10), '188', CHAR(13, 10), '189', CHAR(13, 10), '190', CHAR(13, 10), '191', CHAR(13, 10), '192', CHAR(13, 10), '193', CHAR(13, 10), '194', CHAR(13, 10), '195', CHAR(13, 10), '196', CHAR(13, 10), '197', CHAR(13, 10), '198', CHAR(13, 10), '199', CHAR(13, 10), '200', CHAR(13, 10), '201', CHAR(13, 10), '202', CHAR(13, 10), '203', CHAR(13, 10), '204', CHAR(13, 10), '205', CHAR(13, 10), '206', CHAR(13, 10), '207', CHAR(13, 10), '208', CHAR(13, 10), '209', CHAR(13, 10), '210', CHAR(13, 10), '211', CHAR(13, 10), '212', CHAR(13, 10), '213', CHAR(13, 10), '214', CHAR(13, 10), '215', CHAR(13, 10), '216', CHAR(13, 10), '217', CHAR(13, 10), '218', CHAR(13, 10), '219', CHAR(13, 10), '220', CHAR(13, 10), '221', CHAR(13, 10), '222', CHAR(13, 10), '223', CHAR(13, 10), '224', CHAR(13, 10), '225', CHAR(13, 10), '226', CHAR(13, 10), '227', CHAR(13, 10), '228', CHAR(13, 10), '229', CHAR(13, 10), '230', CHAR(13, 10), '231', CHAR(13, 10), '232', CHAR(13, 10), '233', CHAR(13, 10), '234', CHAR(13, 10), '235', CHAR(13, 10), '236', CHAR(13, 10), '237', CHAR(13, 10), '238', CHAR(13, 10), '239', CHAR(13, 10), '240', CHAR(13, 10), '241', CHAR(13, 10), '242', CHAR(13, 10), '243', CHAR(13, 10), '244', CHAR(13, 10), '245', CHAR(13, 10), '246', CHAR(13, 10), '247', CHAR(13, 10), '248', CHAR(13, 10), '249', CHAR(13, 10), '250', CHAR(13, 10), '251', CHAR(13, 10), '252', CHAR(13, 10), '253', CHAR(13, 10), '254', CHAR(13, 10), '255', CHAR(13, 10), '256', CHAR(13, 10), '257', CHAR(13, 10), '258', CHAR(13, 10), '259', CHAR(13, 10), '260', CHAR(13, 10), '261', CHAR(13, 10), '262', CHAR(13, 10), '263', CHAR(13, 10), '264', CHAR(13, 10), '265', CHAR(13, 10), '266', CHAR(13, 10), '267', CHAR(13, 10), '268', CHAR(13, 10), '269', CHAR(13, 10), '270', CHAR(13, 10), '271', CHAR(13, 10), '272', CHAR(13, 10), '273', CHAR(13, 10), '274', CHAR(13, 10), '275', CHAR(13, 10), '276', CHAR(13, 10), '277', CHAR(13, 10), '278', CHAR(13, 10), '279', CHAR(13, 10), '280', CHAR(13, 10), '281', CHAR(13, 10), '282', CHAR(13, 10), '283', CHAR(13, 10), '284', CHAR(13, 10), '285', CHAR(13, 10), '286', CHAR(13, 10), '287', CHAR(13, 10), '288', CHAR(13, 10), '289', CHAR(13, 10), '290', CHAR(13, 10), '291', CHAR(13, 10), '292', CHAR(13, 10), '293', CHAR(13, 10), '294', CHAR(13, 10), '295', CHAR(13, 10), '296', CHAR(13, 10), '297', CHAR(13, 10), '298', CHAR(13, 10), '299', CHAR(13, 10), '')) +);"); + } + [ConditionalFact] [SupportedServerVersionLessThanCondition(nameof(ServerVersionSupport.DefaultExpression), nameof(ServerVersionSupport.AlternativeDefaultExpression))] public virtual void DefaultValue_not_generated_for_unlimited_text_column_missing_default_expression_support() diff --git a/test/EFCore.MySql.FunctionalTests/ProxyGraphUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/ProxyGraphUpdatesMySqlTest.cs index 7a27b7ac3..31c13a57e 100644 --- a/test/EFCore.MySql.FunctionalTests/ProxyGraphUpdatesMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/ProxyGraphUpdatesMySqlTest.cs @@ -17,11 +17,6 @@ protected ProxyGraphUpdatesMySqlTestBase(TFixture fixture) { } - // Needs lazy-loading - public override void Attempting_to_save_two_entity_cycle_with_lazy_loading_throws() - { - } - protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) => facade.UseTransaction(transaction.GetDbTransaction()); @@ -67,6 +62,11 @@ public ChangeTracking(ProxyGraphUpdatesWithChangeTrackingMySqlFixture fixture) { } + // Needs lazy loading + public override void Save_two_entity_cycle_with_lazy_loading() + { + } + protected override bool DoesLazyLoading => false; diff --git a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsQueryMySqlTest.cs index 7329370cf..74ebe3106 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsQueryMySqlTest.cs @@ -835,7 +835,7 @@ 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`, `t1`.`Id`, `t0`.`c` + @"SELECT `l`.`Id`, `t0`.`Id`, `l1`.`Id`, `t0`.`c` FROM `LevelOne` AS `l` LEFT JOIN ( SELECT `t`.`c`, `t`.`Id`, `t`.`OneToMany_Optional_Inverse2Id` @@ -845,11 +845,8 @@ LEFT JOIN ( ) AS `t` WHERE `t`.`row` <= 1 ) AS `t0` ON `l`.`Id` = `t0`.`OneToMany_Optional_Inverse2Id` -LEFT JOIN ( - SELECT `l1`.`Id`, `l1`.`OneToMany_Optional_Inverse3Id` - FROM `LevelThree` AS `l1` -) AS `t1` ON `t0`.`Id` = `t1`.`OneToMany_Optional_Inverse3Id` -ORDER BY `l`.`Id`, `t0`.`Id`, `t1`.`Id`"); +LEFT JOIN `LevelThree` AS `l1` ON `t0`.`Id` = `l1`.`OneToMany_Optional_Inverse3Id` +ORDER BY `l`.`Id`, `t0`.`Id`, `l1`.`Id`"); } public override async Task Select_subquery_single_nested_subquery2(bool async) @@ -857,25 +854,22 @@ public override async Task Select_subquery_single_nested_subquery2(bool async) await base.Select_subquery_single_nested_subquery2(async); AssertSql( - $@"SELECT `l`.`Id`, `t2`.`Id`, `t2`.`Id0`, `t2`.`Id1`, `t2`.`c` + $@"SELECT `l`.`Id`, `t1`.`Id`, `t1`.`Id0`, `t1`.`Id1`, `t1`.`c` FROM `LevelOne` AS `l` LEFT JOIN ( - SELECT `l0`.`Id`, `t0`.`Id` AS `Id0`, `t1`.`Id` AS `Id1`, `t0`.`c`, `l0`.`OneToMany_Optional_Inverse2Id` + SELECT `l0`.`Id`, `t0`.`Id` AS `Id0`, `l1`.`Id` AS `Id1`, `t0`.`c`, `l0`.`OneToMany_Optional_Inverse2Id` FROM `LevelTwo` AS `l0` LEFT JOIN ( SELECT `t`.`c`, `t`.`Id`, `t`.`OneToMany_Optional_Inverse3Id` FROM ( - SELECT {(AppConfig.ServerVersion.Supports.MySqlBug96947Workaround ? "CAST(1 AS signed)" : "1")} AS `c`, `l1`.`Id`, `l1`.`OneToMany_Optional_Inverse3Id`, ROW_NUMBER() OVER(PARTITION BY `l1`.`OneToMany_Optional_Inverse3Id` ORDER BY `l1`.`Id`) AS `row` - FROM `LevelThree` AS `l1` + SELECT {(AppConfig.ServerVersion.Supports.MySqlBug96947Workaround ? "CAST(1 AS signed)" : "1")} AS `c`, `l2`.`Id`, `l2`.`OneToMany_Optional_Inverse3Id`, ROW_NUMBER() OVER(PARTITION BY `l2`.`OneToMany_Optional_Inverse3Id` ORDER BY `l2`.`Id`) AS `row` + FROM `LevelThree` AS `l2` ) AS `t` WHERE `t`.`row` <= 1 ) AS `t0` ON `l0`.`Id` = `t0`.`OneToMany_Optional_Inverse3Id` - LEFT JOIN ( - SELECT `l2`.`Id`, `l2`.`OneToMany_Optional_Inverse4Id` - FROM `LevelFour` AS `l2` - ) AS `t1` ON `t0`.`Id` = `t1`.`OneToMany_Optional_Inverse4Id` -) AS `t2` ON `l`.`Id` = `t2`.`OneToMany_Optional_Inverse2Id` -ORDER BY `l`.`Id`, `t2`.`Id`, `t2`.`Id0`, `t2`.`Id1`"); + LEFT JOIN `LevelFour` AS `l1` ON `t0`.`Id` = `l1`.`OneToMany_Optional_Inverse4Id` +) AS `t1` ON `l`.`Id` = `t1`.`OneToMany_Optional_Inverse2Id` +ORDER BY `l`.`Id`, `t1`.`Id`, `t1`.`Id0`, `t1`.`Id1`"); } public override async Task Filtered_include_basic_Where(bool async) @@ -898,13 +892,10 @@ public override async Task Filtered_include_OrderBy(bool async) await base.Filtered_include_OrderBy(async); AssertSql( - @"SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `l`.`OneToMany_Optional_Self_Inverse1Id`, `l`.`OneToMany_Required_Self_Inverse1Id`, `l`.`OneToOne_Optional_Self1Id`, `t`.`Id`, `t`.`Date`, `t`.`Level1_Optional_Id`, `t`.`Level1_Required_Id`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id`, `t`.`OneToMany_Optional_Self_Inverse2Id`, `t`.`OneToMany_Required_Inverse2Id`, `t`.`OneToMany_Required_Self_Inverse2Id`, `t`.`OneToOne_Optional_PK_Inverse2Id`, `t`.`OneToOne_Optional_Self2Id` + @"SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `l`.`OneToMany_Optional_Self_Inverse1Id`, `l`.`OneToMany_Required_Self_Inverse1Id`, `l`.`OneToOne_Optional_Self1Id`, `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id` FROM `LevelOne` AS `l` -LEFT JOIN ( - SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id` - FROM `LevelTwo` AS `l0` -) AS `t` ON `l`.`Id` = `t`.`OneToMany_Optional_Inverse2Id` -ORDER BY `l`.`Id`, `t`.`Name`"); +LEFT JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` +ORDER BY `l`.`Id`, `l0`.`Name`"); } public override async Task Filtered_ThenInclude_OrderBy(bool async) @@ -912,17 +903,14 @@ public override async Task Filtered_ThenInclude_OrderBy(bool async) await base.Filtered_ThenInclude_OrderBy(async); AssertSql( - @"SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `l`.`OneToMany_Optional_Self_Inverse1Id`, `l`.`OneToMany_Required_Self_Inverse1Id`, `l`.`OneToOne_Optional_Self1Id`, `t0`.`Id`, `t0`.`Date`, `t0`.`Level1_Optional_Id`, `t0`.`Level1_Required_Id`, `t0`.`Name`, `t0`.`OneToMany_Optional_Inverse2Id`, `t0`.`OneToMany_Optional_Self_Inverse2Id`, `t0`.`OneToMany_Required_Inverse2Id`, `t0`.`OneToMany_Required_Self_Inverse2Id`, `t0`.`OneToOne_Optional_PK_Inverse2Id`, `t0`.`OneToOne_Optional_Self2Id`, `t0`.`Id0`, `t0`.`Level2_Optional_Id`, `t0`.`Level2_Required_Id`, `t0`.`Name0`, `t0`.`OneToMany_Optional_Inverse3Id`, `t0`.`OneToMany_Optional_Self_Inverse3Id`, `t0`.`OneToMany_Required_Inverse3Id`, `t0`.`OneToMany_Required_Self_Inverse3Id`, `t0`.`OneToOne_Optional_PK_Inverse3Id`, `t0`.`OneToOne_Optional_Self3Id` + @"SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `l`.`OneToMany_Optional_Self_Inverse1Id`, `l`.`OneToMany_Required_Self_Inverse1Id`, `l`.`OneToOne_Optional_Self1Id`, `t`.`Id`, `t`.`Date`, `t`.`Level1_Optional_Id`, `t`.`Level1_Required_Id`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id`, `t`.`OneToMany_Optional_Self_Inverse2Id`, `t`.`OneToMany_Required_Inverse2Id`, `t`.`OneToMany_Required_Self_Inverse2Id`, `t`.`OneToOne_Optional_PK_Inverse2Id`, `t`.`OneToOne_Optional_Self2Id`, `t`.`Id0`, `t`.`Level2_Optional_Id`, `t`.`Level2_Required_Id`, `t`.`Name0`, `t`.`OneToMany_Optional_Inverse3Id`, `t`.`OneToMany_Optional_Self_Inverse3Id`, `t`.`OneToMany_Required_Inverse3Id`, `t`.`OneToMany_Required_Self_Inverse3Id`, `t`.`OneToOne_Optional_PK_Inverse3Id`, `t`.`OneToOne_Optional_Self3Id` FROM `LevelOne` AS `l` LEFT JOIN ( - SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id`, `t`.`Id` AS `Id0`, `t`.`Level2_Optional_Id`, `t`.`Level2_Required_Id`, `t`.`Name` AS `Name0`, `t`.`OneToMany_Optional_Inverse3Id`, `t`.`OneToMany_Optional_Self_Inverse3Id`, `t`.`OneToMany_Required_Inverse3Id`, `t`.`OneToMany_Required_Self_Inverse3Id`, `t`.`OneToOne_Optional_PK_Inverse3Id`, `t`.`OneToOne_Optional_Self3Id` + SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id`, `l1`.`Id` AS `Id0`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name` AS `Name0`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id` FROM `LevelTwo` AS `l0` - LEFT JOIN ( - SELECT `l1`.`Id`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id` - FROM `LevelThree` AS `l1` - ) AS `t` ON `l0`.`Id` = `t`.`OneToMany_Optional_Inverse3Id` -) AS `t0` ON `l`.`Id` = `t0`.`OneToMany_Optional_Inverse2Id` -ORDER BY `l`.`Id`, `t0`.`Id`, `t0`.`Name0`"); + LEFT JOIN `LevelThree` AS `l1` ON `l0`.`Id` = `l1`.`OneToMany_Optional_Inverse3Id` +) AS `t` ON `l`.`Id` = `t`.`OneToMany_Optional_Inverse2Id` +ORDER BY `l`.`Id`, `t`.`Id`, `t`.`Name0`"); } public override async Task Filtered_include_ThenInclude_OrderBy(bool async) @@ -930,17 +918,14 @@ 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`.`OneToMany_Optional_Self_Inverse1Id`, `l`.`OneToMany_Required_Self_Inverse1Id`, `l`.`OneToOne_Optional_Self1Id`, `t0`.`Id`, `t0`.`Date`, `t0`.`Level1_Optional_Id`, `t0`.`Level1_Required_Id`, `t0`.`Name`, `t0`.`OneToMany_Optional_Inverse2Id`, `t0`.`OneToMany_Optional_Self_Inverse2Id`, `t0`.`OneToMany_Required_Inverse2Id`, `t0`.`OneToMany_Required_Self_Inverse2Id`, `t0`.`OneToOne_Optional_PK_Inverse2Id`, `t0`.`OneToOne_Optional_Self2Id`, `t0`.`Id0`, `t0`.`Level2_Optional_Id`, `t0`.`Level2_Required_Id`, `t0`.`Name0`, `t0`.`OneToMany_Optional_Inverse3Id`, `t0`.`OneToMany_Optional_Self_Inverse3Id`, `t0`.`OneToMany_Required_Inverse3Id`, `t0`.`OneToMany_Required_Self_Inverse3Id`, `t0`.`OneToOne_Optional_PK_Inverse3Id`, `t0`.`OneToOne_Optional_Self3Id` + @"SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `l`.`OneToMany_Optional_Self_Inverse1Id`, `l`.`OneToMany_Required_Self_Inverse1Id`, `l`.`OneToOne_Optional_Self1Id`, `t`.`Id`, `t`.`Date`, `t`.`Level1_Optional_Id`, `t`.`Level1_Required_Id`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id`, `t`.`OneToMany_Optional_Self_Inverse2Id`, `t`.`OneToMany_Required_Inverse2Id`, `t`.`OneToMany_Required_Self_Inverse2Id`, `t`.`OneToOne_Optional_PK_Inverse2Id`, `t`.`OneToOne_Optional_Self2Id`, `t`.`Id0`, `t`.`Level2_Optional_Id`, `t`.`Level2_Required_Id`, `t`.`Name0`, `t`.`OneToMany_Optional_Inverse3Id`, `t`.`OneToMany_Optional_Self_Inverse3Id`, `t`.`OneToMany_Required_Inverse3Id`, `t`.`OneToMany_Required_Self_Inverse3Id`, `t`.`OneToOne_Optional_PK_Inverse3Id`, `t`.`OneToOne_Optional_Self3Id` FROM `LevelOne` AS `l` LEFT JOIN ( - SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id`, `t`.`Id` AS `Id0`, `t`.`Level2_Optional_Id`, `t`.`Level2_Required_Id`, `t`.`Name` AS `Name0`, `t`.`OneToMany_Optional_Inverse3Id`, `t`.`OneToMany_Optional_Self_Inverse3Id`, `t`.`OneToMany_Required_Inverse3Id`, `t`.`OneToMany_Required_Self_Inverse3Id`, `t`.`OneToOne_Optional_PK_Inverse3Id`, `t`.`OneToOne_Optional_Self3Id` + SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id`, `l1`.`Id` AS `Id0`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name` AS `Name0`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id` FROM `LevelTwo` AS `l0` - LEFT JOIN ( - SELECT `l1`.`Id`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id` - FROM `LevelThree` AS `l1` - ) AS `t` ON `l0`.`Id` = `t`.`OneToMany_Optional_Inverse3Id` -) AS `t0` ON `l`.`Id` = `t0`.`OneToMany_Optional_Inverse2Id` -ORDER BY `l`.`Id`, `t0`.`Name`, `t0`.`Id`, `t0`.`Name0` DESC"); + LEFT JOIN `LevelThree` AS `l1` ON `l0`.`Id` = `l1`.`OneToMany_Optional_Inverse3Id` +) AS `t` ON `l`.`Id` = `t`.`OneToMany_Optional_Inverse2Id` +ORDER BY `l`.`Id`, `t`.`Name`, `t`.`Id`, `t`.`Name0` DESC"); } public override async Task Filtered_include_basic_OrderBy_Take(bool async) @@ -1012,7 +997,7 @@ LEFT JOIN ( ) 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`"); +ORDER BY `l`.`Id`"); } public override async Task Filtered_include_Take_without_OrderBy(bool async) @@ -1030,7 +1015,7 @@ LEFT JOIN ( ) 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`"); +ORDER BY `l`.`Id`"); } public override async Task Filtered_include_on_ThenInclude(bool async) diff --git a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQueryMySqlTest.cs index afb4e56b6..f149fa8c7 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQueryMySqlTest.cs @@ -21,28 +21,21 @@ public override async Task SelectMany_with_Include1(bool async) await base.SelectMany_with_Include1(async); AssertSql( - @"SELECT `t`.`Id`, `t`.`OneToOne_Required_PK_Date`, `t`.`Level1_Optional_Id`, `t`.`Level1_Required_Id`, `t`.`Level2_Name`, `t`.`OneToMany_Optional_Inverse2Id`, `t`.`OneToMany_Required_Inverse2Id`, `t`.`OneToOne_Optional_PK_Inverse2Id`, `l`.`Id`, `t`.`Id0`, `t0`.`Id`, `t0`.`Level2_Optional_Id`, `t0`.`Level2_Required_Id`, `t0`.`Level3_Name`, `t0`.`OneToMany_Optional_Inverse3Id`, `t0`.`OneToMany_Required_Inverse3Id`, `t0`.`OneToOne_Optional_PK_Inverse3Id`, `t0`.`Id0`, `t0`.`Id00` + @"SELECT `t`.`Id`, `t`.`OneToOne_Required_PK_Date`, `t`.`Level1_Optional_Id`, `t`.`Level1_Required_Id`, `t`.`Level2_Name`, `t`.`OneToMany_Optional_Inverse2Id`, `t`.`OneToMany_Required_Inverse2Id`, `t`.`OneToOne_Optional_PK_Inverse2Id`, `l`.`Id`, `t0`.`Id`, `t0`.`Level2_Optional_Id`, `t0`.`Level2_Required_Id`, `t0`.`Level3_Name`, `t0`.`OneToMany_Optional_Inverse3Id`, `t0`.`OneToMany_Required_Inverse3Id`, `t0`.`OneToOne_Optional_PK_Inverse3Id` FROM `Level1` AS `l` INNER JOIN ( - SELECT `l0`.`Id`, `l0`.`OneToOne_Required_PK_Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Level2_Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l1`.`Id` AS `Id0` + 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` FROM `Level1` AS `l0` - INNER JOIN `Level1` 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`, `t1`.`Id` AS `Id0`, `t1`.`Id0` AS `Id00` - FROM `Level1` AS `l2` - INNER JOIN ( - SELECT `l3`.`Id`, `l4`.`Id` AS `Id0` - FROM `Level1` AS `l3` - INNER JOIN `Level1` AS `l4` ON `l3`.`Id` = `l4`.`Id` - WHERE (`l3`.`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) + SELECT `l1`.`Id`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Level3_Name`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id` + FROM `Level1` AS `l1` + WHERE `l1`.`Level2_Required_Id` IS NOT NULL AND (`l1`.`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`"); +ORDER BY `l`.`Id`, `t`.`Id`"); } public override async Task SelectMany_with_navigation_and_Distinct(bool async) @@ -50,22 +43,20 @@ public override async Task SelectMany_with_navigation_and_Distinct(bool async) await base.SelectMany_with_navigation_and_Distinct(async); AssertSql( - @"SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `t`.`Id`, `t0`.`Id`, `t0`.`OneToOne_Required_PK_Date`, `t0`.`Level1_Optional_Id`, `t0`.`Level1_Required_Id`, `t0`.`Level2_Name`, `t0`.`OneToMany_Optional_Inverse2Id`, `t0`.`OneToMany_Required_Inverse2Id`, `t0`.`OneToOne_Optional_PK_Inverse2Id`, `t0`.`Id0` + @"SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `t`.`Id`, `t0`.`Id`, `t0`.`OneToOne_Required_PK_Date`, `t0`.`Level1_Optional_Id`, `t0`.`Level1_Required_Id`, `t0`.`Level2_Name`, `t0`.`OneToMany_Optional_Inverse2Id`, `t0`.`OneToMany_Required_Inverse2Id`, `t0`.`OneToOne_Optional_PK_Inverse2Id` FROM `Level1` AS `l` INNER JOIN ( SELECT DISTINCT `l0`.`Id`, `l0`.`OneToOne_Required_PK_Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Level2_Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id` FROM `Level1` AS `l0` - INNER JOIN `Level1` 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`, `l3`.`Id` AS `Id0` - FROM `Level1` AS `l2` - INNER JOIN `Level1` 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 + 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` + FROM `Level1` AS `l1` + 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 `t0` ON `l`.`Id` = `t0`.`OneToMany_Optional_Inverse2Id` WHERE (`t`.`OneToOne_Required_PK_Date` IS NOT NULL AND (`t`.`Level1_Required_Id` IS NOT NULL)) AND `t`.`OneToMany_Required_Inverse2Id` IS NOT NULL -ORDER BY `l`.`Id`, `t`.`Id`, `t0`.`Id`"); +ORDER BY `l`.`Id`, `t`.`Id`"); } public override async Task Take_Select_collection_Take(bool async) @@ -75,7 +66,7 @@ public override async Task Take_Select_collection_Take(bool 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`.`Id1`, `t0`.`Id00` +SELECT `t`.`Id`, `t`.`Name`, `t0`.`Id`, `t0`.`Name`, `t0`.`Level1Id`, `t0`.`Level2Id`, `t0`.`Id0`, `t0`.`Date`, `t0`.`Name0`, `t0`.`Id1` FROM ( SELECT `l`.`Id`, `l`.`Name` FROM `Level1` AS `l` @@ -85,22 +76,21 @@ LIMIT @__p_0 LEFT JOIN LATERAL ( 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`, `t1`.`Id` AS `Id1`, `t1`.`Id0` AS `Id00`, `t1`.`c` + END AS `Id`, `t1`.`Level2_Name` AS `Name`, `t1`.`OneToMany_Required_Inverse2Id` AS `Level1Id`, `t1`.`Level1_Required_Id` AS `Level2Id`, `l0`.`Id` AS `Id0`, `l0`.`Date`, `l0`.`Name` AS `Name0`, `t1`.`Id` AS `Id1`, `t1`.`c` FROM ( - SELECT `l0`.`Id`, `l0`.`OneToOne_Required_PK_Date`, `l0`.`Level1_Required_Id`, `l0`.`Level2_Name`, `l0`.`OneToMany_Required_Inverse2Id`, `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` + SELECT `l1`.`Id`, `l1`.`OneToOne_Required_PK_Date`, `l1`.`Level1_Required_Id`, `l1`.`Level2_Name`, `l1`.`OneToMany_Required_Inverse2Id`, CASE + WHEN (`l1`.`OneToOne_Required_PK_Date` IS NOT NULL AND (`l1`.`Level1_Required_Id` IS NOT NULL)) AND `l1`.`OneToMany_Required_Inverse2Id` IS NOT NULL THEN `l1`.`Id` END AS `c` - FROM `Level1` AS `l0` - INNER JOIN `Level1` 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`) + FROM `Level1` AS `l1` + 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) AND (`t`.`Id` = `l1`.`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` + WHEN (`l1`.`OneToOne_Required_PK_Date` IS NOT NULL AND (`l1`.`Level1_Required_Id` IS NOT NULL)) AND `l1`.`OneToMany_Required_Inverse2Id` IS NOT NULL THEN `l1`.`Id` END LIMIT 3 ) AS `t1` - INNER JOIN `Level1` AS `l1` ON `t1`.`Level1_Required_Id` = `l1`.`Id` + INNER JOIN `Level1` AS `l0` ON `t1`.`Level1_Required_Id` = `l0`.`Id` ) AS `t0` ON TRUE -ORDER BY `t`.`Id`, `t0`.`c`, `t0`.`Id1`, `t0`.`Id00`"); +ORDER BY `t`.`Id`, `t0`.`c`, `t0`.`Id1`"); } public override async Task Skip_Take_Select_collection_Skip_Take(bool async) @@ -110,7 +100,7 @@ public override async Task Skip_Take_Select_collection_Skip_Take(bool 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`.`Id1`, `t0`.`Id00` +SELECT `t`.`Id`, `t`.`Name`, `t0`.`Id`, `t0`.`Name`, `t0`.`Level1Id`, `t0`.`Level2Id`, `t0`.`Id0`, `t0`.`Date`, `t0`.`Name0`, `t0`.`Id1` FROM ( SELECT `l`.`Id`, `l`.`Name` FROM `Level1` AS `l` @@ -120,22 +110,21 @@ LIMIT @__p_0 OFFSET @__p_0 LEFT JOIN LATERAL ( 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`, `t1`.`Id` AS `Id1`, `t1`.`Id0` AS `Id00`, `t1`.`c` + END AS `Id`, `t1`.`Level2_Name` AS `Name`, `t1`.`OneToMany_Required_Inverse2Id` AS `Level1Id`, `t1`.`Level1_Required_Id` AS `Level2Id`, `l0`.`Id` AS `Id0`, `l0`.`Date`, `l0`.`Name` AS `Name0`, `t1`.`Id` AS `Id1`, `t1`.`c` FROM ( - SELECT `l0`.`Id`, `l0`.`OneToOne_Required_PK_Date`, `l0`.`Level1_Required_Id`, `l0`.`Level2_Name`, `l0`.`OneToMany_Required_Inverse2Id`, `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` + SELECT `l1`.`Id`, `l1`.`OneToOne_Required_PK_Date`, `l1`.`Level1_Required_Id`, `l1`.`Level2_Name`, `l1`.`OneToMany_Required_Inverse2Id`, CASE + WHEN (`l1`.`OneToOne_Required_PK_Date` IS NOT NULL AND (`l1`.`Level1_Required_Id` IS NOT NULL)) AND `l1`.`OneToMany_Required_Inverse2Id` IS NOT NULL THEN `l1`.`Id` END AS `c` - FROM `Level1` AS `l0` - INNER JOIN `Level1` 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`) + FROM `Level1` AS `l1` + 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) AND (`t`.`Id` = `l1`.`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` + WHEN (`l1`.`OneToOne_Required_PK_Date` IS NOT NULL AND (`l1`.`Level1_Required_Id` IS NOT NULL)) AND `l1`.`OneToMany_Required_Inverse2Id` IS NOT NULL THEN `l1`.`Id` END LIMIT 3 OFFSET 1 ) AS `t1` - INNER JOIN `Level1` AS `l1` ON `t1`.`Level1_Required_Id` = `l1`.`Id` + INNER JOIN `Level1` AS `l0` ON `t1`.`Level1_Required_Id` = `l0`.`Id` ) AS `t0` ON TRUE -ORDER BY `t`.`Id`, `t0`.`c`, `t0`.`Id1`, `t0`.`Id00`"); +ORDER BY `t`.`Id`, `t0`.`c`, `t0`.`Id1`"); } public override async Task Skip_Take_on_grouping_element_inside_collection_projection(bool async) @@ -195,14 +184,14 @@ public override async Task Skip_Take_on_grouping_element_with_collection_include await base.Skip_Take_on_grouping_element_with_collection_include(async); AssertSql( - @"SELECT `t`.`Date`, `t1`.`Id`, `t1`.`Date`, `t1`.`Name`, `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`.`Id00` + @"SELECT `t`.`Date`, `t1`.`Id`, `t1`.`Date`, `t1`.`Name`, `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` FROM ( SELECT `l`.`Date` FROM `Level1` AS `l` GROUP BY `l`.`Date` ) AS `t` LEFT JOIN LATERAL ( - SELECT `t0`.`Id`, `t0`.`Date`, `t0`.`Name`, `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`.`Id0` AS `Id00` + SELECT `t0`.`Id`, `t0`.`Date`, `t0`.`Name`, `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` FROM ( SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Name` FROM `Level1` AS `l0` @@ -211,13 +200,12 @@ ORDER BY `l0`.`Name` LIMIT 5 OFFSET 1 ) 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`, `l2`.`Id` AS `Id0` + 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` FROM `Level1` AS `l1` - INNER JOIN `Level1` 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` ON TRUE -ORDER BY `t`.`Date`, `t1`.`Name`, `t1`.`Id`, `t1`.`Id0`"); +ORDER BY `t`.`Date`, `t1`.`Name`, `t1`.`Id`"); } public override async Task Skip_Take_on_grouping_element_with_reference_include(bool async) @@ -225,14 +213,14 @@ public override async Task Skip_Take_on_grouping_element_with_reference_include( await base.Skip_Take_on_grouping_element_with_reference_include(async); AssertSql( - @"SELECT `t`.`Date`, `t1`.`Id`, `t1`.`Date`, `t1`.`Name`, `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`.`Id00` + @"SELECT `t`.`Date`, `t1`.`Id`, `t1`.`Date`, `t1`.`Name`, `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` FROM ( SELECT `l`.`Date` FROM `Level1` AS `l` GROUP BY `l`.`Date` ) AS `t` LEFT JOIN LATERAL ( - SELECT `t0`.`Id`, `t0`.`Date`, `t0`.`Name`, `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`.`Id0` AS `Id00` + SELECT `t0`.`Id`, `t0`.`Date`, `t0`.`Name`, `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` FROM ( SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Name` FROM `Level1` AS `l0` @@ -241,13 +229,12 @@ ORDER BY `l0`.`Name` LIMIT 5 OFFSET 1 ) 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`, `l2`.`Id` AS `Id0` + 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` FROM `Level1` AS `l1` - INNER JOIN `Level1` 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` ON TRUE -ORDER BY `t`.`Date`, `t1`.`Name`, `t1`.`Id`, `t1`.`Id0`"); +ORDER BY `t`.`Date`, `t1`.`Name`, `t1`.`Id`"); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQueryMySqlTest.cs index 2f2b828dd..4267c5173 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQueryMySqlTest.cs @@ -44,13 +44,10 @@ public override async Task Filtered_include_OrderBy(bool async) FROM `LevelOne` AS `l` ORDER BY `l`.`Id`", // - @"SELECT `t`.`Id`, `t`.`Date`, `t`.`Level1_Optional_Id`, `t`.`Level1_Required_Id`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id`, `t`.`OneToMany_Optional_Self_Inverse2Id`, `t`.`OneToMany_Required_Inverse2Id`, `t`.`OneToMany_Required_Self_Inverse2Id`, `t`.`OneToOne_Optional_PK_Inverse2Id`, `t`.`OneToOne_Optional_Self2Id`, `l`.`Id` + @"SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id`, `l`.`Id` FROM `LevelOne` AS `l` -INNER JOIN ( - SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id` - FROM `LevelTwo` AS `l0` -) AS `t` ON `l`.`Id` = `t`.`OneToMany_Optional_Inverse2Id` -ORDER BY `l`.`Id`, `t`.`Name`"); +INNER JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` +ORDER BY `l`.`Id`, `l0`.`Name`"); } public override async Task Filtered_ThenInclude_OrderBy(bool async) @@ -67,14 +64,11 @@ public override async Task Filtered_ThenInclude_OrderBy(bool async) INNER JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` ORDER BY `l`.`Id`, `l0`.`Id`", // - @"SELECT `t`.`Id`, `t`.`Level2_Optional_Id`, `t`.`Level2_Required_Id`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse3Id`, `t`.`OneToMany_Optional_Self_Inverse3Id`, `t`.`OneToMany_Required_Inverse3Id`, `t`.`OneToMany_Required_Self_Inverse3Id`, `t`.`OneToOne_Optional_PK_Inverse3Id`, `t`.`OneToOne_Optional_Self3Id`, `l`.`Id`, `l0`.`Id` + @"SELECT `l1`.`Id`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id`, `l`.`Id`, `l0`.`Id` FROM `LevelOne` AS `l` INNER JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` -INNER JOIN ( - SELECT `l1`.`Id`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id` - FROM `LevelThree` AS `l1` -) AS `t` ON `l0`.`Id` = `t`.`OneToMany_Optional_Inverse3Id` -ORDER BY `l`.`Id`, `l0`.`Id`, `t`.`Name`"); +INNER JOIN `LevelThree` AS `l1` ON `l0`.`Id` = `l1`.`OneToMany_Optional_Inverse3Id` +ORDER BY `l`.`Id`, `l0`.`Id`, `l1`.`Name`"); } public override async Task Filtered_include_ThenInclude_OrderBy(bool async) @@ -86,25 +80,16 @@ public override async Task Filtered_include_ThenInclude_OrderBy(bool async) FROM `LevelOne` AS `l` ORDER BY `l`.`Id`", // - @"SELECT `t`.`Id`, `t`.`Date`, `t`.`Level1_Optional_Id`, `t`.`Level1_Required_Id`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id`, `t`.`OneToMany_Optional_Self_Inverse2Id`, `t`.`OneToMany_Required_Inverse2Id`, `t`.`OneToMany_Required_Self_Inverse2Id`, `t`.`OneToOne_Optional_PK_Inverse2Id`, `t`.`OneToOne_Optional_Self2Id`, `l`.`Id` + @"SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id`, `l`.`Id` FROM `LevelOne` AS `l` -INNER JOIN ( - SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Level1_Optional_Id`, `l0`.`Level1_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id`, `l0`.`OneToMany_Optional_Self_Inverse2Id`, `l0`.`OneToMany_Required_Inverse2Id`, `l0`.`OneToMany_Required_Self_Inverse2Id`, `l0`.`OneToOne_Optional_PK_Inverse2Id`, `l0`.`OneToOne_Optional_Self2Id` - FROM `LevelTwo` AS `l0` -) AS `t` ON `l`.`Id` = `t`.`OneToMany_Optional_Inverse2Id` -ORDER BY `l`.`Id`, `t`.`Name`, `t`.`Id`", +INNER JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` +ORDER BY `l`.`Id`, `l0`.`Name`, `l0`.`Id`", // - @"SELECT `t0`.`Id`, `t0`.`Level2_Optional_Id`, `t0`.`Level2_Required_Id`, `t0`.`Name`, `t0`.`OneToMany_Optional_Inverse3Id`, `t0`.`OneToMany_Optional_Self_Inverse3Id`, `t0`.`OneToMany_Required_Inverse3Id`, `t0`.`OneToMany_Required_Self_Inverse3Id`, `t0`.`OneToOne_Optional_PK_Inverse3Id`, `t0`.`OneToOne_Optional_Self3Id`, `l`.`Id`, `t`.`Id` + @"SELECT `l1`.`Id`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id`, `l`.`Id`, `l0`.`Id` FROM `LevelOne` AS `l` -INNER JOIN ( - SELECT `l0`.`Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse2Id` - FROM `LevelTwo` AS `l0` -) AS `t` ON `l`.`Id` = `t`.`OneToMany_Optional_Inverse2Id` -INNER JOIN ( - SELECT `l1`.`Id`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id` - FROM `LevelThree` AS `l1` -) AS `t0` ON `t`.`Id` = `t0`.`OneToMany_Optional_Inverse3Id` -ORDER BY `l`.`Id`, `t`.`Name`, `t`.`Id`, `t0`.`Name` DESC"); +INNER JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` +INNER JOIN `LevelThree` AS `l1` ON `l0`.`Id` = `l1`.`OneToMany_Optional_Inverse3Id` +ORDER BY `l`.`Id`, `l0`.`Name`, `l0`.`Id`, `l1`.`Name` DESC"); } public override async Task Filtered_include_basic_OrderBy_Take(bool async) @@ -1073,7 +1058,7 @@ LEFT JOIN ( ) AS `t0` ON `l`.`Id` = `t0`.`OneToMany_Optional_Inverse2Id` ORDER BY `l`.`Id`, `t0`.`Id`", // - @"SELECT `t1`.`Id`, `l`.`Id`, `t0`.`Id` + @"SELECT `l1`.`Id`, `l`.`Id`, `t0`.`Id` FROM `LevelOne` AS `l` LEFT JOIN ( SELECT `t`.`Id`, `t`.`OneToMany_Optional_Inverse2Id` @@ -1083,11 +1068,8 @@ LEFT JOIN ( ) AS `t` WHERE `t`.`row` <= 1 ) AS `t0` ON `l`.`Id` = `t0`.`OneToMany_Optional_Inverse2Id` -INNER JOIN ( - SELECT `l1`.`Id`, `l1`.`OneToMany_Optional_Inverse3Id` - FROM `LevelThree` AS `l1` -) AS `t1` ON `t0`.`Id` = `t1`.`OneToMany_Optional_Inverse3Id` -ORDER BY `l`.`Id`, `t0`.`Id`, `t1`.`Id`"); +INNER JOIN `LevelThree` AS `l1` ON `t0`.`Id` = `l1`.`OneToMany_Optional_Inverse3Id` +ORDER BY `l`.`Id`, `t0`.`Id`, `l1`.`Id`"); } public override async Task Select_subquery_single_nested_subquery2(bool async) @@ -1099,55 +1081,73 @@ public override async Task Select_subquery_single_nested_subquery2(bool async) FROM `LevelOne` AS `l` ORDER BY `l`.`Id`", // - @"SELECT `l`.`Id`, `t`.`Id`, `t0`.`Id`, `t0`.`c` + @"SELECT `l`.`Id`, `l0`.`Id`, `t0`.`Id`, `t0`.`c` FROM `LevelOne` AS `l` -INNER JOIN ( - SELECT `l0`.`Id`, `l0`.`OneToMany_Optional_Inverse2Id` - FROM `LevelTwo` AS `l0` -) AS `t` ON `l`.`Id` = `t`.`OneToMany_Optional_Inverse2Id` +INNER JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` LEFT JOIN ( - SELECT `t1`.`c`, `t1`.`Id`, `t1`.`OneToMany_Optional_Inverse3Id` + SELECT `t`.`c`, `t`.`Id`, `t`.`OneToMany_Optional_Inverse3Id` FROM ( SELECT 1 AS `c`, `l1`.`Id`, `l1`.`OneToMany_Optional_Inverse3Id`, ROW_NUMBER() OVER(PARTITION BY `l1`.`OneToMany_Optional_Inverse3Id` ORDER BY `l1`.`Id`) AS `row` FROM `LevelThree` AS `l1` - ) AS `t1` - WHERE `t1`.`row` <= 1 -) AS `t0` ON `t`.`Id` = `t0`.`OneToMany_Optional_Inverse3Id` -ORDER BY `l`.`Id`, `t`.`Id`, `t0`.`Id`", + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `l0`.`Id` = `t0`.`OneToMany_Optional_Inverse3Id` +ORDER BY `l`.`Id`, `l0`.`Id`, `t0`.`Id`", // - @"SELECT `t2`.`Id`, `l`.`Id`, `t`.`Id`, `t0`.`Id` + @"SELECT `l2`.`Id`, `l`.`Id`, `l0`.`Id`, `t0`.`Id` FROM `LevelOne` AS `l` -INNER JOIN ( - SELECT `l0`.`Id`, `l0`.`OneToMany_Optional_Inverse2Id` - FROM `LevelTwo` AS `l0` -) AS `t` ON `l`.`Id` = `t`.`OneToMany_Optional_Inverse2Id` +INNER JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` LEFT JOIN ( - SELECT `t1`.`Id`, `t1`.`OneToMany_Optional_Inverse3Id` + SELECT `t`.`Id`, `t`.`OneToMany_Optional_Inverse3Id` FROM ( SELECT `l1`.`Id`, `l1`.`OneToMany_Optional_Inverse3Id`, ROW_NUMBER() OVER(PARTITION BY `l1`.`OneToMany_Optional_Inverse3Id` ORDER BY `l1`.`Id`) AS `row` FROM `LevelThree` AS `l1` - ) AS `t1` - WHERE `t1`.`row` <= 1 -) AS `t0` ON `t`.`Id` = `t0`.`OneToMany_Optional_Inverse3Id` -INNER JOIN ( - SELECT `l2`.`Id`, `l2`.`OneToMany_Optional_Inverse4Id` - FROM `LevelFour` AS `l2` -) AS `t2` ON `t0`.`Id` = `t2`.`OneToMany_Optional_Inverse4Id` -ORDER BY `l`.`Id`, `t`.`Id`, `t0`.`Id`, `t2`.`Id`"); + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `l0`.`Id` = `t0`.`OneToMany_Optional_Inverse3Id` +INNER JOIN `LevelFour` AS `l2` ON `t0`.`Id` = `l2`.`OneToMany_Optional_Inverse4Id` +ORDER BY `l`.`Id`, `l0`.`Id`, `t0`.`Id`, `l2`.`Id`"); } public override async Task Queryable_in_subquery_works_when_final_projection_is_List(bool async) { await base.Queryable_in_subquery_works_when_final_projection_is_List(async); - AssertSql(" "); + AssertSql(); } public override async Task Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(bool async) { await base.Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(async); - AssertSql(" "); + AssertSql( + @"SELECT `l`.`Id`, `t`.`Id`, `t`.`c` +FROM `LevelOne` AS `l` +LEFT JOIN LATERAL ( + SELECT 1 AS `c`, `l0`.`Id` + FROM `LevelTwo` AS `l0` + WHERE (`l0`.`Name` <> 'Foo') OR `l0`.`Name` IS NULL + LIMIT 1 +) AS `t` ON TRUE +ORDER BY `l`.`Id`, `t`.`Id`", + // + @"SELECT `t0`.`Name`, `l`.`Id`, `t`.`Id` +FROM `LevelOne` AS `l` +LEFT JOIN LATERAL ( + SELECT `l0`.`Id` + FROM `LevelTwo` AS `l0` + WHERE (`l0`.`Name` <> 'Foo') OR `l0`.`Name` IS NULL + LIMIT 1 +) AS `t` ON TRUE +JOIN LATERAL ( + SELECT `l1`.`Name` + FROM `LevelOne` AS `l1` + WHERE EXISTS ( + SELECT 1 + FROM `LevelTwo` AS `l2` + WHERE (`l1`.`Id` = `l2`.`OneToMany_Optional_Inverse2Id`) AND (`l2`.`Id` = `t`.`Id`)) +) AS `t0` ON TRUE +ORDER BY `l`.`Id`, `t`.`Id`"); } public override async Task Complex_query_with_let_collection_projection_FirstOrDefault(bool async) diff --git a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsQueryMySqlTest.cs index 0b8d3ea70..866186922 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsQueryMySqlTest.cs @@ -1,8 +1,15 @@ +using System; +using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; +using Pomelo.EntityFrameworkCore.MySql.Tests; using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; +using Xunit; using Xunit.Abstractions; +using Xunit.Sdk; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query { @@ -23,5 +30,75 @@ public override Task Contains_with_subquery_optional_navigation_and_constant_ite { return base.Contains_with_subquery_optional_navigation_and_constant_item(async); } + + public override async Task SelectMany_subquery_with_custom_projection(bool async) + { + // TODO: Fix test in EF Core upstream. + // ORDER BY `l`.`Id` + // is ambiguous, since all 5 queried rows have an `Id` of `1`. + await AssertQuery( + async, + ss => ss.Set()/*.OrderBy(l1 => l1.Id)*/.SelectMany( // <-- has no effect anymore + l1 => l1.OneToMany_Optional1.Select( + l2 => new { l2.Name })) + .OrderBy(l0 => l0.Name) // <-- fix + .Take(1)); + + AssertSql( + @"@__p_0='1' + +SELECT `l0`.`Name` +FROM `LevelOne` AS `l` +INNER JOIN `LevelTwo` AS `l0` ON `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` +ORDER BY `l0`.`Name` +LIMIT @__p_0"); + } + + public override async Task GroupJoin_client_method_in_OrderBy(bool async) + { + await AssertTranslationFailedWithDetails( + () => base.GroupJoin_client_method_in_OrderBy(async), + CoreStrings.QueryUnableToTranslateMethod( + "Microsoft.EntityFrameworkCore.Query.ComplexNavigationsQueryTestBase", + "ClientMethodNullableInt")); + + AssertSql(); + } + + public override async Task Join_with_result_selector_returning_queryable_throws_validation_error(bool async) + { + // Expression cannot be used for return type. Issue #23302. + await Assert.ThrowsAsync( + () => base.Join_with_result_selector_returning_queryable_throws_validation_error(async)); + + AssertSql(); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterApply))] + public override async Task Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(bool async) + { + // DefaultIfEmpty on child collection. Issue #19095. + await Assert.ThrowsAsync( + async () => await base.Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(async)); + + AssertSql( + @"SELECT `t0`.`l1Name`, `t0`.`l2Name`, `t0`.`l3Name` +FROM `LevelOne` AS `l` +LEFT JOIN LATERAL ( + SELECT `t`.`l1Name`, `t`.`l2Name`, `t`.`l3Name` + FROM `LevelTwo` AS `l0` + LEFT JOIN `LevelThree` AS `l1` ON `l0`.`Id` = `l1`.`Id` + JOIN LATERAL ( + SELECT `l`.`Name` AS `l1Name`, `l1`.`Name` AS `l2Name`, `l3`.`Name` AS `l3Name` + FROM `LevelFour` AS `l2` + LEFT JOIN `LevelThree` AS `l3` ON `l2`.`OneToOne_Optional_PK_Inverse4Id` = `l3`.`Id` + WHERE `l1`.`Id` IS NOT NULL AND (`l1`.`Id` = `l2`.`OneToMany_Optional_Inverse4Id`) + ) AS `t` ON TRUE + WHERE `l`.`Id` = `l0`.`OneToMany_Optional_Inverse2Id` +) AS `t0` ON TRUE"); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryMySqlTest.cs index 39d64bd8c..31893354c 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryMySqlTest.cs @@ -1,12 +1,16 @@ -using System.Linq; +using System; +using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel; using Microsoft.EntityFrameworkCore.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; +using Xunit; using Xunit.Abstractions; +using Xunit.Sdk; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query { @@ -49,6 +53,68 @@ where l1.Id < 3 select l3).Distinct().OrderBy(e => e.Id).Skip(1).FirstOrDefault().Name); // Apply OrderBy before Skip } + public override async Task SelectMany_subquery_with_custom_projection(bool async) + { + // TODO: Fix test in EF Core upstream. + // ORDER BY `l`.`Id` + // is ambiguous, since all 5 queried rows have an `Id` of `1`. + await AssertQuery( + async, + ss => ss.Set()/*.OrderBy(l1 => l1.Id)*/.SelectMany( // <-- has no effect anymore + l1 => l1.OneToMany_Optional1.Select( + l2 => new { l2.Name })) + .OrderBy(e => e.Name) // <-- fix + .Take(1)); + + AssertSql( + @"@__p_0='1' + +SELECT `t`.`Name` +FROM `Level1` AS `l` +INNER JOIN ( + SELECT `l0`.`Level2_Name` AS `Name`, `l0`.`OneToMany_Optional_Inverse2Id` + FROM `Level1` AS `l0` + 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 `t`.`Name` +LIMIT @__p_0"); + } + + [ConditionalTheory(Skip = "https://github.com/dotnet/efcore/issues/26104")] + public override Task GroupBy_aggregate_where_required_relationship(bool async) + => base.GroupBy_aggregate_where_required_relationship(async); + + [ConditionalTheory(Skip = "https://github.com/dotnet/efcore/issues/26104")] + public override Task GroupBy_aggregate_where_required_relationship_2(bool async) + => base.GroupBy_aggregate_where_required_relationship_2(async); + + public override async Task GroupJoin_client_method_in_OrderBy(bool async) + { + await Assert.ThrowsAsync( + async () => await base.GroupJoin_client_method_in_OrderBy(async)); + + AssertSql(); + } + + public override async Task Join_with_result_selector_returning_queryable_throws_validation_error(bool async) + { + // Expression cannot be used for return type. Issue #23302. + await Assert.ThrowsAsync( + () => base.Join_with_result_selector_returning_queryable_throws_validation_error(async)); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Does not throw an EqualException, but still does not work.")] + public override async Task Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(bool async) + { + // DefaultIfEmpty on child collection. Issue #19095. + await Assert.ThrowsAsync( + async () => await base.Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(async)); + + AssertSql(); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.MySql.FunctionalTests/Query/CompositeKeysQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/CompositeKeysQueryMySqlTest.cs index 5cfcdddbb..02fbb5d28 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/CompositeKeysQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/CompositeKeysQueryMySqlTest.cs @@ -47,17 +47,11 @@ public override async Task Projecting_multiple_collections_with_ordering_same_le await base.Projecting_multiple_collections_with_ordering_same_level(async); AssertSql( - @"SELECT `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2`, `t`.`Date`, `t`.`Level1_Optional_Id1`, `t`.`Level1_Optional_Id2`, `t`.`Level1_Required_Id1`, `t`.`Level1_Required_Id2`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id1`, `t`.`OneToMany_Optional_Inverse2Id2`, `t`.`OneToMany_Optional_Self_Inverse2Id1`, `t`.`OneToMany_Optional_Self_Inverse2Id2`, `t`.`OneToMany_Required_Inverse2Id1`, `t`.`OneToMany_Required_Inverse2Id2`, `t`.`OneToMany_Required_Self_Inverse2Id1`, `t`.`OneToMany_Required_Self_Inverse2Id2`, `t`.`OneToOne_Optional_PK_Inverse2Id1`, `t`.`OneToOne_Optional_PK_Inverse2Id2`, `t`.`OneToOne_Optional_Self2Id1`, `t`.`OneToOne_Optional_Self2Id2`, `t0`.`Id1`, `t0`.`Id2`, `t0`.`Date`, `t0`.`Level1_Optional_Id1`, `t0`.`Level1_Optional_Id2`, `t0`.`Level1_Required_Id1`, `t0`.`Level1_Required_Id2`, `t0`.`Name`, `t0`.`OneToMany_Optional_Inverse2Id1`, `t0`.`OneToMany_Optional_Inverse2Id2`, `t0`.`OneToMany_Optional_Self_Inverse2Id1`, `t0`.`OneToMany_Optional_Self_Inverse2Id2`, `t0`.`OneToMany_Required_Inverse2Id1`, `t0`.`OneToMany_Required_Inverse2Id2`, `t0`.`OneToMany_Required_Self_Inverse2Id1`, `t0`.`OneToMany_Required_Self_Inverse2Id2`, `t0`.`OneToOne_Optional_PK_Inverse2Id1`, `t0`.`OneToOne_Optional_PK_Inverse2Id2`, `t0`.`OneToOne_Optional_Self2Id1`, `t0`.`OneToOne_Optional_Self2Id2` + @"SELECT `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2`, `c1`.`Id1`, `c1`.`Id2`, `c1`.`Date`, `c1`.`Level1_Optional_Id1`, `c1`.`Level1_Optional_Id2`, `c1`.`Level1_Required_Id1`, `c1`.`Level1_Required_Id2`, `c1`.`Name`, `c1`.`OneToMany_Optional_Inverse2Id1`, `c1`.`OneToMany_Optional_Inverse2Id2`, `c1`.`OneToMany_Optional_Self_Inverse2Id1`, `c1`.`OneToMany_Optional_Self_Inverse2Id2`, `c1`.`OneToMany_Required_Inverse2Id1`, `c1`.`OneToMany_Required_Inverse2Id2`, `c1`.`OneToMany_Required_Self_Inverse2Id1`, `c1`.`OneToMany_Required_Self_Inverse2Id2`, `c1`.`OneToOne_Optional_PK_Inverse2Id1`, `c1`.`OneToOne_Optional_PK_Inverse2Id2`, `c1`.`OneToOne_Optional_Self2Id1`, `c1`.`OneToOne_Optional_Self2Id2` FROM `CompositeOnes` AS `c` -LEFT JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Optional_Inverse2Id2`) -LEFT JOIN ( - SELECT `c1`.`Id1`, `c1`.`Id2`, `c1`.`Date`, `c1`.`Level1_Optional_Id1`, `c1`.`Level1_Optional_Id2`, `c1`.`Level1_Required_Id1`, `c1`.`Level1_Required_Id2`, `c1`.`Name`, `c1`.`OneToMany_Optional_Inverse2Id1`, `c1`.`OneToMany_Optional_Inverse2Id2`, `c1`.`OneToMany_Optional_Self_Inverse2Id1`, `c1`.`OneToMany_Optional_Self_Inverse2Id2`, `c1`.`OneToMany_Required_Inverse2Id1`, `c1`.`OneToMany_Required_Inverse2Id2`, `c1`.`OneToMany_Required_Self_Inverse2Id1`, `c1`.`OneToMany_Required_Self_Inverse2Id2`, `c1`.`OneToOne_Optional_PK_Inverse2Id1`, `c1`.`OneToOne_Optional_PK_Inverse2Id2`, `c1`.`OneToOne_Optional_Self2Id1`, `c1`.`OneToOne_Optional_Self2Id2` - FROM `CompositeTwos` AS `c1` -) AS `t0` ON (`c`.`Id1` = `t0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t0`.`OneToMany_Required_Inverse2Id2`) -ORDER BY `c`.`Id1`, `c`.`Id2`, `t`.`Id2`, `t`.`Id1`, `t0`.`Name` DESC, `t0`.`Id1`"); +LEFT JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Optional_Inverse2Id2`) +LEFT JOIN `CompositeTwos` AS `c1` ON (`c`.`Id1` = `c1`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c1`.`OneToMany_Required_Inverse2Id2`) +ORDER BY `c`.`Id1`, `c`.`Id2`, `c0`.`Id2`, `c0`.`Id1`, `c1`.`Name` DESC, `c1`.`Id1`"); } public override async Task Projecting_multiple_collections_with_ordering_same_level_top_level_ordering(bool async) @@ -65,17 +59,11 @@ public override async Task Projecting_multiple_collections_with_ordering_same_le await base.Projecting_multiple_collections_with_ordering_same_level_top_level_ordering(async); AssertSql( - @"SELECT `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2`, `t`.`Date`, `t`.`Level1_Optional_Id1`, `t`.`Level1_Optional_Id2`, `t`.`Level1_Required_Id1`, `t`.`Level1_Required_Id2`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id1`, `t`.`OneToMany_Optional_Inverse2Id2`, `t`.`OneToMany_Optional_Self_Inverse2Id1`, `t`.`OneToMany_Optional_Self_Inverse2Id2`, `t`.`OneToMany_Required_Inverse2Id1`, `t`.`OneToMany_Required_Inverse2Id2`, `t`.`OneToMany_Required_Self_Inverse2Id1`, `t`.`OneToMany_Required_Self_Inverse2Id2`, `t`.`OneToOne_Optional_PK_Inverse2Id1`, `t`.`OneToOne_Optional_PK_Inverse2Id2`, `t`.`OneToOne_Optional_Self2Id1`, `t`.`OneToOne_Optional_Self2Id2`, `t0`.`Id1`, `t0`.`Id2`, `t0`.`Date`, `t0`.`Level1_Optional_Id1`, `t0`.`Level1_Optional_Id2`, `t0`.`Level1_Required_Id1`, `t0`.`Level1_Required_Id2`, `t0`.`Name`, `t0`.`OneToMany_Optional_Inverse2Id1`, `t0`.`OneToMany_Optional_Inverse2Id2`, `t0`.`OneToMany_Optional_Self_Inverse2Id1`, `t0`.`OneToMany_Optional_Self_Inverse2Id2`, `t0`.`OneToMany_Required_Inverse2Id1`, `t0`.`OneToMany_Required_Inverse2Id2`, `t0`.`OneToMany_Required_Self_Inverse2Id1`, `t0`.`OneToMany_Required_Self_Inverse2Id2`, `t0`.`OneToOne_Optional_PK_Inverse2Id1`, `t0`.`OneToOne_Optional_PK_Inverse2Id2`, `t0`.`OneToOne_Optional_Self2Id1`, `t0`.`OneToOne_Optional_Self2Id2` + @"SELECT `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2`, `c1`.`Id1`, `c1`.`Id2`, `c1`.`Date`, `c1`.`Level1_Optional_Id1`, `c1`.`Level1_Optional_Id2`, `c1`.`Level1_Required_Id1`, `c1`.`Level1_Required_Id2`, `c1`.`Name`, `c1`.`OneToMany_Optional_Inverse2Id1`, `c1`.`OneToMany_Optional_Inverse2Id2`, `c1`.`OneToMany_Optional_Self_Inverse2Id1`, `c1`.`OneToMany_Optional_Self_Inverse2Id2`, `c1`.`OneToMany_Required_Inverse2Id1`, `c1`.`OneToMany_Required_Inverse2Id2`, `c1`.`OneToMany_Required_Self_Inverse2Id1`, `c1`.`OneToMany_Required_Self_Inverse2Id2`, `c1`.`OneToOne_Optional_PK_Inverse2Id1`, `c1`.`OneToOne_Optional_PK_Inverse2Id2`, `c1`.`OneToOne_Optional_Self2Id1`, `c1`.`OneToOne_Optional_Self2Id2` FROM `CompositeOnes` AS `c` -LEFT JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Optional_Inverse2Id2`) -LEFT JOIN ( - SELECT `c1`.`Id1`, `c1`.`Id2`, `c1`.`Date`, `c1`.`Level1_Optional_Id1`, `c1`.`Level1_Optional_Id2`, `c1`.`Level1_Required_Id1`, `c1`.`Level1_Required_Id2`, `c1`.`Name`, `c1`.`OneToMany_Optional_Inverse2Id1`, `c1`.`OneToMany_Optional_Inverse2Id2`, `c1`.`OneToMany_Optional_Self_Inverse2Id1`, `c1`.`OneToMany_Optional_Self_Inverse2Id2`, `c1`.`OneToMany_Required_Inverse2Id1`, `c1`.`OneToMany_Required_Inverse2Id2`, `c1`.`OneToMany_Required_Self_Inverse2Id1`, `c1`.`OneToMany_Required_Self_Inverse2Id2`, `c1`.`OneToOne_Optional_PK_Inverse2Id1`, `c1`.`OneToOne_Optional_PK_Inverse2Id2`, `c1`.`OneToOne_Optional_Self2Id1`, `c1`.`OneToOne_Optional_Self2Id2` - FROM `CompositeTwos` AS `c1` -) AS `t0` ON (`c`.`Id1` = `t0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t0`.`OneToMany_Required_Inverse2Id2`) -ORDER BY `c`.`Id2`, `c`.`Id1`, `t`.`Id2`, `t`.`Id1`, `t0`.`Name` DESC, `t0`.`Id1`"); +LEFT JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Optional_Inverse2Id2`) +LEFT JOIN `CompositeTwos` AS `c1` ON (`c`.`Id1` = `c1`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c1`.`OneToMany_Required_Inverse2Id2`) +ORDER BY `c`.`Id2`, `c`.`Id1`, `c0`.`Id2`, `c0`.`Id1`, `c1`.`Name` DESC, `c1`.`Id1`"); } public override async Task Projecting_collections_multi_level(bool async) @@ -83,17 +71,14 @@ public override async Task Projecting_collections_multi_level(bool async) await base.Projecting_collections_multi_level(async); AssertSql( - @"SELECT `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t0`.`Name`, `t0`.`Id1`, `t0`.`Id2`, `t0`.`Id10`, `t0`.`Id20`, `t0`.`Level2_Optional_Id1`, `t0`.`Level2_Optional_Id2`, `t0`.`Level2_Required_Id1`, `t0`.`Level2_Required_Id2`, `t0`.`Name0`, `t0`.`OneToMany_Optional_Inverse3Id1`, `t0`.`OneToMany_Optional_Inverse3Id2`, `t0`.`OneToMany_Optional_Self_Inverse3Id1`, `t0`.`OneToMany_Optional_Self_Inverse3Id2`, `t0`.`OneToMany_Required_Inverse3Id1`, `t0`.`OneToMany_Required_Inverse3Id2`, `t0`.`OneToMany_Required_Self_Inverse3Id1`, `t0`.`OneToMany_Required_Self_Inverse3Id2`, `t0`.`OneToOne_Optional_PK_Inverse3Id1`, `t0`.`OneToOne_Optional_PK_Inverse3Id2`, `t0`.`OneToOne_Optional_Self3Id1`, `t0`.`OneToOne_Optional_Self3Id2` + @"SELECT `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`Name`, `t`.`Id1`, `t`.`Id2`, `t`.`Id10`, `t`.`Id20`, `t`.`Level2_Optional_Id1`, `t`.`Level2_Optional_Id2`, `t`.`Level2_Required_Id1`, `t`.`Level2_Required_Id2`, `t`.`Name0`, `t`.`OneToMany_Optional_Inverse3Id1`, `t`.`OneToMany_Optional_Inverse3Id2`, `t`.`OneToMany_Optional_Self_Inverse3Id1`, `t`.`OneToMany_Optional_Self_Inverse3Id2`, `t`.`OneToMany_Required_Inverse3Id1`, `t`.`OneToMany_Required_Inverse3Id2`, `t`.`OneToMany_Required_Self_Inverse3Id1`, `t`.`OneToMany_Required_Self_Inverse3Id2`, `t`.`OneToOne_Optional_PK_Inverse3Id1`, `t`.`OneToOne_Optional_PK_Inverse3Id2`, `t`.`OneToOne_Optional_Self3Id1`, `t`.`OneToOne_Optional_Self3Id2` FROM `CompositeOnes` AS `c` LEFT JOIN ( - SELECT `c0`.`Name`, `c0`.`Id1`, `c0`.`Id2`, `t`.`Id1` AS `Id10`, `t`.`Id2` AS `Id20`, `t`.`Level2_Optional_Id1`, `t`.`Level2_Optional_Id2`, `t`.`Level2_Required_Id1`, `t`.`Level2_Required_Id2`, `t`.`Name` AS `Name0`, `t`.`OneToMany_Optional_Inverse3Id1`, `t`.`OneToMany_Optional_Inverse3Id2`, `t`.`OneToMany_Optional_Self_Inverse3Id1`, `t`.`OneToMany_Optional_Self_Inverse3Id2`, `t`.`OneToMany_Required_Inverse3Id1`, `t`.`OneToMany_Required_Inverse3Id2`, `t`.`OneToMany_Required_Self_Inverse3Id1`, `t`.`OneToMany_Required_Self_Inverse3Id2`, `t`.`OneToOne_Optional_PK_Inverse3Id1`, `t`.`OneToOne_Optional_PK_Inverse3Id2`, `t`.`OneToOne_Optional_Self3Id1`, `t`.`OneToOne_Optional_Self3Id2`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2` + SELECT `c0`.`Name`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1` AS `Id10`, `c1`.`Id2` AS `Id20`, `c1`.`Level2_Optional_Id1`, `c1`.`Level2_Optional_Id2`, `c1`.`Level2_Required_Id1`, `c1`.`Level2_Required_Id2`, `c1`.`Name` AS `Name0`, `c1`.`OneToMany_Optional_Inverse3Id1`, `c1`.`OneToMany_Optional_Inverse3Id2`, `c1`.`OneToMany_Optional_Self_Inverse3Id1`, `c1`.`OneToMany_Optional_Self_Inverse3Id2`, `c1`.`OneToMany_Required_Inverse3Id1`, `c1`.`OneToMany_Required_Inverse3Id2`, `c1`.`OneToMany_Required_Self_Inverse3Id1`, `c1`.`OneToMany_Required_Self_Inverse3Id2`, `c1`.`OneToOne_Optional_PK_Inverse3Id1`, `c1`.`OneToOne_Optional_PK_Inverse3Id2`, `c1`.`OneToOne_Optional_Self3Id1`, `c1`.`OneToOne_Optional_Self3Id2`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2` FROM `CompositeTwos` AS `c0` - LEFT JOIN ( - SELECT `c1`.`Id1`, `c1`.`Id2`, `c1`.`Level2_Optional_Id1`, `c1`.`Level2_Optional_Id2`, `c1`.`Level2_Required_Id1`, `c1`.`Level2_Required_Id2`, `c1`.`Name`, `c1`.`OneToMany_Optional_Inverse3Id1`, `c1`.`OneToMany_Optional_Inverse3Id2`, `c1`.`OneToMany_Optional_Self_Inverse3Id1`, `c1`.`OneToMany_Optional_Self_Inverse3Id2`, `c1`.`OneToMany_Required_Inverse3Id1`, `c1`.`OneToMany_Required_Inverse3Id2`, `c1`.`OneToMany_Required_Self_Inverse3Id1`, `c1`.`OneToMany_Required_Self_Inverse3Id2`, `c1`.`OneToOne_Optional_PK_Inverse3Id1`, `c1`.`OneToOne_Optional_PK_Inverse3Id2`, `c1`.`OneToOne_Optional_Self3Id1`, `c1`.`OneToOne_Optional_Self3Id2` - FROM `CompositeThrees` AS `c1` - ) AS `t` ON (`c0`.`Id1` = `t`.`OneToMany_Required_Inverse3Id1`) AND (`c0`.`Id2` = `t`.`OneToMany_Required_Inverse3Id2`) -) AS `t0` ON (`c`.`Id1` = `t0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `t0`.`OneToMany_Optional_Inverse2Id2`) -ORDER BY `c`.`Id2`, `c`.`Id1`, `t0`.`Id2`, `t0`.`Id1`, `t0`.`Id20` DESC"); + LEFT JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Required_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Required_Inverse3Id2`) +) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Optional_Inverse2Id2`) +ORDER BY `c`.`Id2`, `c`.`Id1`, `t`.`Id2`, `t`.`Id1`, `t`.`Id20` DESC"); } public override async Task Projecting_multiple_collections_on_multiple_levels_no_explicit_ordering(bool async) @@ -171,13 +156,10 @@ LEFT JOIN ( LEFT JOIN `CompositeFours` AS `c10` ON (`c8`.`Id1` = `c10`.`OneToMany_Optional_Inverse4Id1`) AND (`c8`.`Id2` = `c10`.`OneToMany_Optional_Inverse4Id2`) ) AS `t3` ON (`c7`.`Id1` = `t3`.`OneToMany_Optional_Inverse3Id1`) AND (`c7`.`Id2` = `t3`.`OneToMany_Optional_Inverse3Id2`) LEFT JOIN ( - SELECT `c11`.`Name`, `c11`.`Id1`, `c11`.`Id2`, `c12`.`Id1` AS `Id10`, `c12`.`Id2` AS `Id20`, `c12`.`Level3_Optional_Id1`, `c12`.`Level3_Optional_Id2`, `c12`.`Level3_Required_Id1`, `c12`.`Level3_Required_Id2`, `c12`.`Name` AS `Name0`, `c12`.`OneToMany_Optional_Inverse4Id1`, `c12`.`OneToMany_Optional_Inverse4Id2`, `c12`.`OneToMany_Optional_Self_Inverse4Id1`, `c12`.`OneToMany_Optional_Self_Inverse4Id2`, `c12`.`OneToMany_Required_Inverse4Id1`, `c12`.`OneToMany_Required_Inverse4Id2`, `c12`.`OneToMany_Required_Self_Inverse4Id1`, `c12`.`OneToMany_Required_Self_Inverse4Id2`, `c12`.`OneToOne_Optional_PK_Inverse4Id1`, `c12`.`OneToOne_Optional_PK_Inverse4Id2`, `c12`.`OneToOne_Optional_Self4Id1`, `c12`.`OneToOne_Optional_Self4Id2`, `t5`.`Id1` AS `Id11`, `t5`.`Id2` AS `Id21`, `t5`.`Level3_Optional_Id1` AS `Level3_Optional_Id10`, `t5`.`Level3_Optional_Id2` AS `Level3_Optional_Id20`, `t5`.`Level3_Required_Id1` AS `Level3_Required_Id10`, `t5`.`Level3_Required_Id2` AS `Level3_Required_Id20`, `t5`.`Name` AS `Name1`, `t5`.`OneToMany_Optional_Inverse4Id1` AS `OneToMany_Optional_Inverse4Id10`, `t5`.`OneToMany_Optional_Inverse4Id2` AS `OneToMany_Optional_Inverse4Id20`, `t5`.`OneToMany_Optional_Self_Inverse4Id1` AS `OneToMany_Optional_Self_Inverse4Id10`, `t5`.`OneToMany_Optional_Self_Inverse4Id2` AS `OneToMany_Optional_Self_Inverse4Id20`, `t5`.`OneToMany_Required_Inverse4Id1` AS `OneToMany_Required_Inverse4Id10`, `t5`.`OneToMany_Required_Inverse4Id2` AS `OneToMany_Required_Inverse4Id20`, `t5`.`OneToMany_Required_Self_Inverse4Id1` AS `OneToMany_Required_Self_Inverse4Id10`, `t5`.`OneToMany_Required_Self_Inverse4Id2` AS `OneToMany_Required_Self_Inverse4Id20`, `t5`.`OneToOne_Optional_PK_Inverse4Id1` AS `OneToOne_Optional_PK_Inverse4Id10`, `t5`.`OneToOne_Optional_PK_Inverse4Id2` AS `OneToOne_Optional_PK_Inverse4Id20`, `t5`.`OneToOne_Optional_Self4Id1` AS `OneToOne_Optional_Self4Id10`, `t5`.`OneToOne_Optional_Self4Id2` AS `OneToOne_Optional_Self4Id20`, `t5`.`c`, `c11`.`OneToMany_Optional_Inverse3Id1`, `c11`.`OneToMany_Optional_Inverse3Id2` + SELECT `c11`.`Name`, `c11`.`Id1`, `c11`.`Id2`, `c12`.`Id1` AS `Id10`, `c12`.`Id2` AS `Id20`, `c12`.`Level3_Optional_Id1`, `c12`.`Level3_Optional_Id2`, `c12`.`Level3_Required_Id1`, `c12`.`Level3_Required_Id2`, `c12`.`Name` AS `Name0`, `c12`.`OneToMany_Optional_Inverse4Id1`, `c12`.`OneToMany_Optional_Inverse4Id2`, `c12`.`OneToMany_Optional_Self_Inverse4Id1`, `c12`.`OneToMany_Optional_Self_Inverse4Id2`, `c12`.`OneToMany_Required_Inverse4Id1`, `c12`.`OneToMany_Required_Inverse4Id2`, `c12`.`OneToMany_Required_Self_Inverse4Id1`, `c12`.`OneToMany_Required_Self_Inverse4Id2`, `c12`.`OneToOne_Optional_PK_Inverse4Id1`, `c12`.`OneToOne_Optional_PK_Inverse4Id2`, `c12`.`OneToOne_Optional_Self4Id1`, `c12`.`OneToOne_Optional_Self4Id2`, `c13`.`Id1` AS `Id11`, `c13`.`Id2` AS `Id21`, `c13`.`Level3_Optional_Id1` AS `Level3_Optional_Id10`, `c13`.`Level3_Optional_Id2` AS `Level3_Optional_Id20`, `c13`.`Level3_Required_Id1` AS `Level3_Required_Id10`, `c13`.`Level3_Required_Id2` AS `Level3_Required_Id20`, `c13`.`Name` AS `Name1`, `c13`.`OneToMany_Optional_Inverse4Id1` AS `OneToMany_Optional_Inverse4Id10`, `c13`.`OneToMany_Optional_Inverse4Id2` AS `OneToMany_Optional_Inverse4Id20`, `c13`.`OneToMany_Optional_Self_Inverse4Id1` AS `OneToMany_Optional_Self_Inverse4Id10`, `c13`.`OneToMany_Optional_Self_Inverse4Id2` AS `OneToMany_Optional_Self_Inverse4Id20`, `c13`.`OneToMany_Required_Inverse4Id1` AS `OneToMany_Required_Inverse4Id10`, `c13`.`OneToMany_Required_Inverse4Id2` AS `OneToMany_Required_Inverse4Id20`, `c13`.`OneToMany_Required_Self_Inverse4Id1` AS `OneToMany_Required_Self_Inverse4Id10`, `c13`.`OneToMany_Required_Self_Inverse4Id2` AS `OneToMany_Required_Self_Inverse4Id20`, `c13`.`OneToOne_Optional_PK_Inverse4Id1` AS `OneToOne_Optional_PK_Inverse4Id10`, `c13`.`OneToOne_Optional_PK_Inverse4Id2` AS `OneToOne_Optional_PK_Inverse4Id20`, `c13`.`OneToOne_Optional_Self4Id1` AS `OneToOne_Optional_Self4Id10`, `c13`.`OneToOne_Optional_Self4Id2` AS `OneToOne_Optional_Self4Id20`, CONCAT(`c13`.`Id1`, CAST(`c13`.`Id2` AS char)) AS `c`, `c11`.`OneToMany_Optional_Inverse3Id1`, `c11`.`OneToMany_Optional_Inverse3Id2` FROM `CompositeThrees` AS `c11` LEFT JOIN `CompositeFours` AS `c12` ON (`c11`.`Id1` = `c12`.`OneToMany_Optional_Inverse4Id1`) AND (`c11`.`Id2` = `c12`.`OneToMany_Optional_Inverse4Id2`) - LEFT JOIN ( - SELECT `c13`.`Id1`, `c13`.`Id2`, `c13`.`Level3_Optional_Id1`, `c13`.`Level3_Optional_Id2`, `c13`.`Level3_Required_Id1`, `c13`.`Level3_Required_Id2`, `c13`.`Name`, `c13`.`OneToMany_Optional_Inverse4Id1`, `c13`.`OneToMany_Optional_Inverse4Id2`, `c13`.`OneToMany_Optional_Self_Inverse4Id1`, `c13`.`OneToMany_Optional_Self_Inverse4Id2`, `c13`.`OneToMany_Required_Inverse4Id1`, `c13`.`OneToMany_Required_Inverse4Id2`, `c13`.`OneToMany_Required_Self_Inverse4Id1`, `c13`.`OneToMany_Required_Self_Inverse4Id2`, `c13`.`OneToOne_Optional_PK_Inverse4Id1`, `c13`.`OneToOne_Optional_PK_Inverse4Id2`, `c13`.`OneToOne_Optional_Self4Id1`, `c13`.`OneToOne_Optional_Self4Id2`, CONCAT(`c13`.`Id1`, CAST(`c13`.`Id2` AS char)) AS `c` - FROM `CompositeFours` AS `c13` - ) AS `t5` ON (`c11`.`Id1` = `t5`.`OneToMany_Required_Inverse4Id1`) AND (`c11`.`Id2` = `t5`.`OneToMany_Required_Inverse4Id2`) + LEFT JOIN `CompositeFours` AS `c13` ON (`c11`.`Id1` = `c13`.`OneToMany_Required_Inverse4Id1`) AND (`c11`.`Id2` = `c13`.`OneToMany_Required_Inverse4Id2`) ) AS `t4` ON (`c7`.`Id1` = `t4`.`OneToMany_Optional_Inverse3Id1`) AND (`c7`.`Id2` = `t4`.`OneToMany_Optional_Inverse3Id2`) ) AS `t2` ON (`c`.`Id1` = `t2`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t2`.`OneToMany_Required_Inverse2Id2`) ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t1`.`Id1`, `t1`.`Id2`, `t1`.`Id20` DESC, `t1`.`Id10` DESC, `t1`.`Id100`, `t1`.`Id200`, `t1`.`Id11`, `t1`.`Id21`, `t1`.`Id12`, `t1`.`Id22`, `t1`.`Id101`, `t1`.`Id201`, `t1`.`Id110`, `t1`.`Id210`, `t2`.`c`, `t2`.`Id1`, `t2`.`Id2`, `t2`.`Id10`, `t2`.`Id20`, `t2`.`Id100`, `t2`.`Id200`, `t2`.`Id11`, `t2`.`Id21`, `t2`.`Id12`, `t2`.`Id22`, `t2`.`Id101`, `t2`.`Id201`, `t2`.`c0` DESC, `t2`.`Id110`"); diff --git a/test/EFCore.MySql.FunctionalTests/Query/CompositeKeysSplitQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/CompositeKeysSplitQueryMySqlTest.cs index eb6ac802c..27da7e812 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/CompositeKeysSplitQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/CompositeKeysSplitQueryMySqlTest.cs @@ -27,25 +27,16 @@ public override async Task Projecting_collections_multi_level(bool async) FROM `CompositeOnes` AS `c` ORDER BY `c`.`Id2`, `c`.`Id1`", // - @"SELECT `t`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2` -FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Name`, `c0`.`Id1`, `c0`.`Id2`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Optional_Inverse2Id2`) -ORDER BY `c`.`Id2`, `c`.`Id1`, `t`.`Id2`, `t`.`Id1`", - // - @"SELECT `t0`.`Id1`, `t0`.`Id2`, `t0`.`Level2_Optional_Id1`, `t0`.`Level2_Optional_Id2`, `t0`.`Level2_Required_Id1`, `t0`.`Level2_Required_Id2`, `t0`.`Name`, `t0`.`OneToMany_Optional_Inverse3Id1`, `t0`.`OneToMany_Optional_Inverse3Id2`, `t0`.`OneToMany_Optional_Self_Inverse3Id1`, `t0`.`OneToMany_Optional_Self_Inverse3Id2`, `t0`.`OneToMany_Required_Inverse3Id1`, `t0`.`OneToMany_Required_Inverse3Id2`, `t0`.`OneToMany_Required_Self_Inverse3Id1`, `t0`.`OneToMany_Required_Self_Inverse3Id2`, `t0`.`OneToOne_Optional_PK_Inverse3Id1`, `t0`.`OneToOne_Optional_PK_Inverse3Id2`, `t0`.`OneToOne_Optional_Self3Id1`, `t0`.`OneToOne_Optional_Self3Id2`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2` -FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Optional_Inverse2Id2`) -INNER JOIN ( - SELECT `c1`.`Id1`, `c1`.`Id2`, `c1`.`Level2_Optional_Id1`, `c1`.`Level2_Optional_Id2`, `c1`.`Level2_Required_Id1`, `c1`.`Level2_Required_Id2`, `c1`.`Name`, `c1`.`OneToMany_Optional_Inverse3Id1`, `c1`.`OneToMany_Optional_Inverse3Id2`, `c1`.`OneToMany_Optional_Self_Inverse3Id1`, `c1`.`OneToMany_Optional_Self_Inverse3Id2`, `c1`.`OneToMany_Required_Inverse3Id1`, `c1`.`OneToMany_Required_Inverse3Id2`, `c1`.`OneToMany_Required_Self_Inverse3Id1`, `c1`.`OneToMany_Required_Self_Inverse3Id2`, `c1`.`OneToOne_Optional_PK_Inverse3Id1`, `c1`.`OneToOne_Optional_PK_Inverse3Id2`, `c1`.`OneToOne_Optional_Self3Id1`, `c1`.`OneToOne_Optional_Self3Id2` - FROM `CompositeThrees` AS `c1` -) AS `t0` ON (`t`.`Id1` = `t0`.`OneToMany_Required_Inverse3Id1`) AND (`t`.`Id2` = `t0`.`OneToMany_Required_Inverse3Id2`) -ORDER BY `c`.`Id2`, `c`.`Id1`, `t`.`Id2`, `t`.`Id1`, `t0`.`Id2` DESC"); + @"SELECT `c0`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2` +FROM `CompositeOnes` AS `c` +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Optional_Inverse2Id2`) +ORDER BY `c`.`Id2`, `c`.`Id1`, `c0`.`Id2`, `c0`.`Id1`", + // + @"SELECT `c1`.`Id1`, `c1`.`Id2`, `c1`.`Level2_Optional_Id1`, `c1`.`Level2_Optional_Id2`, `c1`.`Level2_Required_Id1`, `c1`.`Level2_Required_Id2`, `c1`.`Name`, `c1`.`OneToMany_Optional_Inverse3Id1`, `c1`.`OneToMany_Optional_Inverse3Id2`, `c1`.`OneToMany_Optional_Self_Inverse3Id1`, `c1`.`OneToMany_Optional_Self_Inverse3Id2`, `c1`.`OneToMany_Required_Inverse3Id1`, `c1`.`OneToMany_Required_Inverse3Id2`, `c1`.`OneToMany_Required_Self_Inverse3Id1`, `c1`.`OneToMany_Required_Self_Inverse3Id2`, `c1`.`OneToOne_Optional_PK_Inverse3Id1`, `c1`.`OneToOne_Optional_PK_Inverse3Id2`, `c1`.`OneToOne_Optional_Self3Id1`, `c1`.`OneToOne_Optional_Self3Id2`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2` +FROM `CompositeOnes` AS `c` +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Optional_Inverse2Id2`) +INNER JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Required_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Required_Inverse3Id2`) +ORDER BY `c`.`Id2`, `c`.`Id1`, `c0`.`Id2`, `c0`.`Id1`, `c1`.`Id2` DESC"); } public override async Task Projecting_multiple_collections_on_multiple_levels_no_explicit_ordering(bool async) @@ -138,8 +129,8 @@ public override async Task Projecting_multiple_collections_on_multiple_levels_so { await base.Projecting_multiple_collections_on_multiple_levels_some_explicit_ordering(async); - AssertSql( - @"SELECT `c`.`Id1`, `c`.`Id2` + AssertSql( + @"SELECT `c`.`Id1`, `c`.`Id2` FROM `CompositeOnes` AS `c` ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`", // @@ -148,14 +139,11 @@ public override async Task Projecting_multiple_collections_on_multiple_levels_so INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Optional_Inverse2Id2`) ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`", // - @"SELECT `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `t`.`Id1`, `t`.`Id2` + @"SELECT `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2` FROM `CompositeOnes` AS `c` INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Optional_Inverse2Id2`) -INNER JOIN ( - SELECT `c1`.`Id1`, `c1`.`Id2`, `c1`.`OneToMany_Required_Inverse3Id1`, `c1`.`OneToMany_Required_Inverse3Id2` - FROM `CompositeThrees` AS `c1` -) AS `t` ON (`c0`.`Id1` = `t`.`OneToMany_Required_Inverse3Id1`) AND (`c0`.`Id2` = `t`.`OneToMany_Required_Inverse3Id2`) -ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `t`.`Id2` DESC, `t`.`Id1` DESC", +INNER JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Required_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Required_Inverse3Id2`) +ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id2` DESC, `c1`.`Id1` DESC", // @"SELECT `c1`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2` FROM `CompositeOnes` AS `c` @@ -177,74 +165,50 @@ INNER JOIN ( INNER JOIN `CompositeFours` AS `c2` ON (`c1`.`Id1` = `c2`.`OneToMany_Optional_Inverse4Id1`) AND (`c1`.`Id2` = `c2`.`OneToMany_Optional_Inverse4Id2`) ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", // - @"SELECT `t`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2` + @"SELECT `c0`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Name`, `c0`.`Id1`, `c0`.`Id2`, CHAR_LENGTH(`c0`.`Name`) AS `c`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`c`, `t`.`Id1`, `t`.`Id2`", +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, CHAR_LENGTH(`c0`.`Name`), `c0`.`Id1`, `c0`.`Id2`", // - @"SELECT `c1`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2` + @"SELECT `c1`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, CHAR_LENGTH(`c0`.`Name`) AS `c`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -INNER JOIN `CompositeThrees` AS `c1` ON (`t`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`t`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) -ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`c`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +INNER JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) +ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, CHAR_LENGTH(`c0`.`Name`), `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", // - @"SELECT `c2`.`Id1`, `c2`.`Id2`, `c2`.`Level3_Optional_Id1`, `c2`.`Level3_Optional_Id2`, `c2`.`Level3_Required_Id1`, `c2`.`Level3_Required_Id2`, `c2`.`Name`, `c2`.`OneToMany_Optional_Inverse4Id1`, `c2`.`OneToMany_Optional_Inverse4Id2`, `c2`.`OneToMany_Optional_Self_Inverse4Id1`, `c2`.`OneToMany_Optional_Self_Inverse4Id2`, `c2`.`OneToMany_Required_Inverse4Id1`, `c2`.`OneToMany_Required_Inverse4Id2`, `c2`.`OneToMany_Required_Self_Inverse4Id1`, `c2`.`OneToMany_Required_Self_Inverse4Id2`, `c2`.`OneToOne_Optional_PK_Inverse4Id1`, `c2`.`OneToOne_Optional_PK_Inverse4Id2`, `c2`.`OneToOne_Optional_Self4Id1`, `c2`.`OneToOne_Optional_Self4Id2`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2` + @"SELECT `c2`.`Id1`, `c2`.`Id2`, `c2`.`Level3_Optional_Id1`, `c2`.`Level3_Optional_Id2`, `c2`.`Level3_Required_Id1`, `c2`.`Level3_Required_Id2`, `c2`.`Name`, `c2`.`OneToMany_Optional_Inverse4Id1`, `c2`.`OneToMany_Optional_Inverse4Id2`, `c2`.`OneToMany_Optional_Self_Inverse4Id1`, `c2`.`OneToMany_Optional_Self_Inverse4Id2`, `c2`.`OneToMany_Required_Inverse4Id1`, `c2`.`OneToMany_Required_Inverse4Id2`, `c2`.`OneToMany_Required_Self_Inverse4Id1`, `c2`.`OneToMany_Required_Self_Inverse4Id2`, `c2`.`OneToOne_Optional_PK_Inverse4Id1`, `c2`.`OneToOne_Optional_PK_Inverse4Id2`, `c2`.`OneToOne_Optional_Self4Id1`, `c2`.`OneToOne_Optional_Self4Id2`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, CHAR_LENGTH(`c0`.`Name`) AS `c`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -INNER JOIN `CompositeThrees` AS `c1` ON (`t`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`t`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +INNER JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) INNER JOIN `CompositeFours` AS `c2` ON (`c1`.`Id1` = `c2`.`OneToMany_Required_Inverse4Id1`) AND (`c1`.`Id2` = `c2`.`OneToMany_Required_Inverse4Id2`) -ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`c`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", +ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, CHAR_LENGTH(`c0`.`Name`), `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", // - @"SELECT `c2`.`Id1`, `c2`.`Id2`, `c2`.`Level3_Optional_Id1`, `c2`.`Level3_Optional_Id2`, `c2`.`Level3_Required_Id1`, `c2`.`Level3_Required_Id2`, `c2`.`Name`, `c2`.`OneToMany_Optional_Inverse4Id1`, `c2`.`OneToMany_Optional_Inverse4Id2`, `c2`.`OneToMany_Optional_Self_Inverse4Id1`, `c2`.`OneToMany_Optional_Self_Inverse4Id2`, `c2`.`OneToMany_Required_Inverse4Id1`, `c2`.`OneToMany_Required_Inverse4Id2`, `c2`.`OneToMany_Required_Self_Inverse4Id1`, `c2`.`OneToMany_Required_Self_Inverse4Id2`, `c2`.`OneToOne_Optional_PK_Inverse4Id1`, `c2`.`OneToOne_Optional_PK_Inverse4Id2`, `c2`.`OneToOne_Optional_Self4Id1`, `c2`.`OneToOne_Optional_Self4Id2`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2` + @"SELECT `c2`.`Id1`, `c2`.`Id2`, `c2`.`Level3_Optional_Id1`, `c2`.`Level3_Optional_Id2`, `c2`.`Level3_Required_Id1`, `c2`.`Level3_Required_Id2`, `c2`.`Name`, `c2`.`OneToMany_Optional_Inverse4Id1`, `c2`.`OneToMany_Optional_Inverse4Id2`, `c2`.`OneToMany_Optional_Self_Inverse4Id1`, `c2`.`OneToMany_Optional_Self_Inverse4Id2`, `c2`.`OneToMany_Required_Inverse4Id1`, `c2`.`OneToMany_Required_Inverse4Id2`, `c2`.`OneToMany_Required_Self_Inverse4Id1`, `c2`.`OneToMany_Required_Self_Inverse4Id2`, `c2`.`OneToOne_Optional_PK_Inverse4Id1`, `c2`.`OneToOne_Optional_PK_Inverse4Id2`, `c2`.`OneToOne_Optional_Self4Id1`, `c2`.`OneToOne_Optional_Self4Id2`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, CHAR_LENGTH(`c0`.`Name`) AS `c`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -INNER JOIN `CompositeThrees` AS `c1` ON (`t`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`t`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +INNER JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) INNER JOIN `CompositeFours` AS `c2` ON (`c1`.`Id1` = `c2`.`OneToMany_Optional_Inverse4Id1`) AND (`c1`.`Id2` = `c2`.`OneToMany_Optional_Inverse4Id2`) -ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`c`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", +ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, CHAR_LENGTH(`c0`.`Name`), `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", // - @"SELECT `c1`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2` + @"SELECT `c1`.`Name`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, CHAR_LENGTH(`c0`.`Name`) AS `c`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -INNER JOIN `CompositeThrees` AS `c1` ON (`t`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`t`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) -ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`c`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +INNER JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) +ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, CHAR_LENGTH(`c0`.`Name`), `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", // - @"SELECT `c2`.`Id1`, `c2`.`Id2`, `c2`.`Level3_Optional_Id1`, `c2`.`Level3_Optional_Id2`, `c2`.`Level3_Required_Id1`, `c2`.`Level3_Required_Id2`, `c2`.`Name`, `c2`.`OneToMany_Optional_Inverse4Id1`, `c2`.`OneToMany_Optional_Inverse4Id2`, `c2`.`OneToMany_Optional_Self_Inverse4Id1`, `c2`.`OneToMany_Optional_Self_Inverse4Id2`, `c2`.`OneToMany_Required_Inverse4Id1`, `c2`.`OneToMany_Required_Inverse4Id2`, `c2`.`OneToMany_Required_Self_Inverse4Id1`, `c2`.`OneToMany_Required_Self_Inverse4Id2`, `c2`.`OneToOne_Optional_PK_Inverse4Id1`, `c2`.`OneToOne_Optional_PK_Inverse4Id2`, `c2`.`OneToOne_Optional_Self4Id1`, `c2`.`OneToOne_Optional_Self4Id2`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2` + @"SELECT `c2`.`Id1`, `c2`.`Id2`, `c2`.`Level3_Optional_Id1`, `c2`.`Level3_Optional_Id2`, `c2`.`Level3_Required_Id1`, `c2`.`Level3_Required_Id2`, `c2`.`Name`, `c2`.`OneToMany_Optional_Inverse4Id1`, `c2`.`OneToMany_Optional_Inverse4Id2`, `c2`.`OneToMany_Optional_Self_Inverse4Id1`, `c2`.`OneToMany_Optional_Self_Inverse4Id2`, `c2`.`OneToMany_Required_Inverse4Id1`, `c2`.`OneToMany_Required_Inverse4Id2`, `c2`.`OneToMany_Required_Self_Inverse4Id1`, `c2`.`OneToMany_Required_Self_Inverse4Id2`, `c2`.`OneToOne_Optional_PK_Inverse4Id1`, `c2`.`OneToOne_Optional_PK_Inverse4Id2`, `c2`.`OneToOne_Optional_Self4Id1`, `c2`.`OneToOne_Optional_Self4Id2`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, CHAR_LENGTH(`c0`.`Name`) AS `c`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -INNER JOIN `CompositeThrees` AS `c1` ON (`t`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`t`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +INNER JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) INNER JOIN `CompositeFours` AS `c2` ON (`c1`.`Id1` = `c2`.`OneToMany_Optional_Inverse4Id1`) AND (`c1`.`Id2` = `c2`.`OneToMany_Optional_Inverse4Id2`) -ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`c`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", - // - @"SELECT `t0`.`Id1`, `t0`.`Id2`, `t0`.`Level3_Optional_Id1`, `t0`.`Level3_Optional_Id2`, `t0`.`Level3_Required_Id1`, `t0`.`Level3_Required_Id2`, `t0`.`Name`, `t0`.`OneToMany_Optional_Inverse4Id1`, `t0`.`OneToMany_Optional_Inverse4Id2`, `t0`.`OneToMany_Optional_Self_Inverse4Id1`, `t0`.`OneToMany_Optional_Self_Inverse4Id2`, `t0`.`OneToMany_Required_Inverse4Id1`, `t0`.`OneToMany_Required_Inverse4Id2`, `t0`.`OneToMany_Required_Self_Inverse4Id1`, `t0`.`OneToMany_Required_Self_Inverse4Id2`, `t0`.`OneToOne_Optional_PK_Inverse4Id1`, `t0`.`OneToOne_Optional_PK_Inverse4Id2`, `t0`.`OneToOne_Optional_Self4Id1`, `t0`.`OneToOne_Optional_Self4Id2`, `c`.`Id1`, `c`.`Id2`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2` -FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, CHAR_LENGTH(`c0`.`Name`) AS `c`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -INNER JOIN `CompositeThrees` AS `c1` ON (`t`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`t`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) -INNER JOIN ( - SELECT `c2`.`Id1`, `c2`.`Id2`, `c2`.`Level3_Optional_Id1`, `c2`.`Level3_Optional_Id2`, `c2`.`Level3_Required_Id1`, `c2`.`Level3_Required_Id2`, `c2`.`Name`, `c2`.`OneToMany_Optional_Inverse4Id1`, `c2`.`OneToMany_Optional_Inverse4Id2`, `c2`.`OneToMany_Optional_Self_Inverse4Id1`, `c2`.`OneToMany_Optional_Self_Inverse4Id2`, `c2`.`OneToMany_Required_Inverse4Id1`, `c2`.`OneToMany_Required_Inverse4Id2`, `c2`.`OneToMany_Required_Self_Inverse4Id1`, `c2`.`OneToMany_Required_Self_Inverse4Id2`, `c2`.`OneToOne_Optional_PK_Inverse4Id1`, `c2`.`OneToOne_Optional_PK_Inverse4Id2`, `c2`.`OneToOne_Optional_Self4Id1`, `c2`.`OneToOne_Optional_Self4Id2`, CONCAT(`c2`.`Id1`, CAST(`c2`.`Id2` AS char)) AS `c` - FROM `CompositeFours` AS `c2` -) AS `t0` ON (`c1`.`Id1` = `t0`.`OneToMany_Required_Inverse4Id1`) AND (`c1`.`Id2` = `t0`.`OneToMany_Required_Inverse4Id2`) -ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, `t`.`c`, `t`.`Id1`, `t`.`Id2`, `c1`.`Id1`, `c1`.`Id2`, `t0`.`c` DESC"); +ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, CHAR_LENGTH(`c0`.`Name`), `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2`", + // + @"SELECT `c2`.`Id1`, `c2`.`Id2`, `c2`.`Level3_Optional_Id1`, `c2`.`Level3_Optional_Id2`, `c2`.`Level3_Required_Id1`, `c2`.`Level3_Required_Id2`, `c2`.`Name`, `c2`.`OneToMany_Optional_Inverse4Id1`, `c2`.`OneToMany_Optional_Inverse4Id2`, `c2`.`OneToMany_Optional_Self_Inverse4Id1`, `c2`.`OneToMany_Optional_Self_Inverse4Id2`, `c2`.`OneToMany_Required_Inverse4Id1`, `c2`.`OneToMany_Required_Inverse4Id2`, `c2`.`OneToMany_Required_Self_Inverse4Id1`, `c2`.`OneToMany_Required_Self_Inverse4Id2`, `c2`.`OneToOne_Optional_PK_Inverse4Id1`, `c2`.`OneToOne_Optional_PK_Inverse4Id2`, `c2`.`OneToOne_Optional_Self4Id1`, `c2`.`OneToOne_Optional_Self4Id2`, `c`.`Id1`, `c`.`Id2`, `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2` +FROM `CompositeOnes` AS `c` +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +INNER JOIN `CompositeThrees` AS `c1` ON (`c0`.`Id1` = `c1`.`OneToMany_Optional_Inverse3Id1`) AND (`c0`.`Id2` = `c1`.`OneToMany_Optional_Inverse3Id2`) +INNER JOIN `CompositeFours` AS `c2` ON (`c1`.`Id1` = `c2`.`OneToMany_Required_Inverse4Id1`) AND (`c1`.`Id2` = `c2`.`OneToMany_Required_Inverse4Id2`) +ORDER BY `c`.`Name`, `c`.`Id1`, `c`.`Id2`, CHAR_LENGTH(`c0`.`Name`), `c0`.`Id1`, `c0`.`Id2`, `c1`.`Id1`, `c1`.`Id2`, CONCAT(`c2`.`Id1`, CAST(`c2`.`Id2` AS char)) DESC"); } public override async Task Projecting_multiple_collections_same_level_top_level_ordering(bool async) @@ -296,21 +260,15 @@ public override async Task Projecting_multiple_collections_with_ordering_same_le FROM `CompositeOnes` AS `c` ORDER BY `c`.`Id1`, `c`.`Id2`", // - @"SELECT `t`.`Id1`, `t`.`Id2`, `t`.`Date`, `t`.`Level1_Optional_Id1`, `t`.`Level1_Optional_Id2`, `t`.`Level1_Required_Id1`, `t`.`Level1_Required_Id2`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id1`, `t`.`OneToMany_Optional_Inverse2Id2`, `t`.`OneToMany_Optional_Self_Inverse2Id1`, `t`.`OneToMany_Optional_Self_Inverse2Id2`, `t`.`OneToMany_Required_Inverse2Id1`, `t`.`OneToMany_Required_Inverse2Id2`, `t`.`OneToMany_Required_Self_Inverse2Id1`, `t`.`OneToMany_Required_Self_Inverse2Id2`, `t`.`OneToOne_Optional_PK_Inverse2Id1`, `t`.`OneToOne_Optional_PK_Inverse2Id2`, `t`.`OneToOne_Optional_Self2Id1`, `t`.`OneToOne_Optional_Self2Id2`, `c`.`Id1`, `c`.`Id2` + @"SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2`, `c`.`Id1`, `c`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Optional_Inverse2Id2`) -ORDER BY `c`.`Id1`, `c`.`Id2`, `t`.`Id2`", +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Optional_Inverse2Id2`) +ORDER BY `c`.`Id1`, `c`.`Id2`, `c0`.`Id2`", // - @"SELECT `t`.`Id1`, `t`.`Id2`, `t`.`Date`, `t`.`Level1_Optional_Id1`, `t`.`Level1_Optional_Id2`, `t`.`Level1_Required_Id1`, `t`.`Level1_Required_Id2`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id1`, `t`.`OneToMany_Optional_Inverse2Id2`, `t`.`OneToMany_Optional_Self_Inverse2Id1`, `t`.`OneToMany_Optional_Self_Inverse2Id2`, `t`.`OneToMany_Required_Inverse2Id1`, `t`.`OneToMany_Required_Inverse2Id2`, `t`.`OneToMany_Required_Self_Inverse2Id1`, `t`.`OneToMany_Required_Self_Inverse2Id2`, `t`.`OneToOne_Optional_PK_Inverse2Id1`, `t`.`OneToOne_Optional_PK_Inverse2Id2`, `t`.`OneToOne_Optional_Self2Id1`, `t`.`OneToOne_Optional_Self2Id2`, `c`.`Id1`, `c`.`Id2` + @"SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2`, `c`.`Id1`, `c`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -ORDER BY `c`.`Id1`, `c`.`Id2`, `t`.`Name` DESC"); +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +ORDER BY `c`.`Id1`, `c`.`Id2`, `c0`.`Name` DESC"); } public override async Task Projecting_multiple_collections_with_ordering_same_level_top_level_ordering(bool async) @@ -322,21 +280,15 @@ public override async Task Projecting_multiple_collections_with_ordering_same_le FROM `CompositeOnes` AS `c` ORDER BY `c`.`Id2`, `c`.`Id1`", // - @"SELECT `t`.`Id1`, `t`.`Id2`, `t`.`Date`, `t`.`Level1_Optional_Id1`, `t`.`Level1_Optional_Id2`, `t`.`Level1_Required_Id1`, `t`.`Level1_Required_Id2`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id1`, `t`.`OneToMany_Optional_Inverse2Id2`, `t`.`OneToMany_Optional_Self_Inverse2Id1`, `t`.`OneToMany_Optional_Self_Inverse2Id2`, `t`.`OneToMany_Required_Inverse2Id1`, `t`.`OneToMany_Required_Inverse2Id2`, `t`.`OneToMany_Required_Self_Inverse2Id1`, `t`.`OneToMany_Required_Self_Inverse2Id2`, `t`.`OneToOne_Optional_PK_Inverse2Id1`, `t`.`OneToOne_Optional_PK_Inverse2Id2`, `t`.`OneToOne_Optional_Self2Id1`, `t`.`OneToOne_Optional_Self2Id2`, `c`.`Id1`, `c`.`Id2` + @"SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2`, `c`.`Id1`, `c`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Optional_Inverse2Id2`) -ORDER BY `c`.`Id2`, `c`.`Id1`, `t`.`Id2`", +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Optional_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Optional_Inverse2Id2`) +ORDER BY `c`.`Id2`, `c`.`Id1`, `c0`.`Id2`", // - @"SELECT `t`.`Id1`, `t`.`Id2`, `t`.`Date`, `t`.`Level1_Optional_Id1`, `t`.`Level1_Optional_Id2`, `t`.`Level1_Required_Id1`, `t`.`Level1_Required_Id2`, `t`.`Name`, `t`.`OneToMany_Optional_Inverse2Id1`, `t`.`OneToMany_Optional_Inverse2Id2`, `t`.`OneToMany_Optional_Self_Inverse2Id1`, `t`.`OneToMany_Optional_Self_Inverse2Id2`, `t`.`OneToMany_Required_Inverse2Id1`, `t`.`OneToMany_Required_Inverse2Id2`, `t`.`OneToMany_Required_Self_Inverse2Id1`, `t`.`OneToMany_Required_Self_Inverse2Id2`, `t`.`OneToOne_Optional_PK_Inverse2Id1`, `t`.`OneToOne_Optional_PK_Inverse2Id2`, `t`.`OneToOne_Optional_Self2Id1`, `t`.`OneToOne_Optional_Self2Id2`, `c`.`Id1`, `c`.`Id2` + @"SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2`, `c`.`Id1`, `c`.`Id2` FROM `CompositeOnes` AS `c` -INNER JOIN ( - SELECT `c0`.`Id1`, `c0`.`Id2`, `c0`.`Date`, `c0`.`Level1_Optional_Id1`, `c0`.`Level1_Optional_Id2`, `c0`.`Level1_Required_Id1`, `c0`.`Level1_Required_Id2`, `c0`.`Name`, `c0`.`OneToMany_Optional_Inverse2Id1`, `c0`.`OneToMany_Optional_Inverse2Id2`, `c0`.`OneToMany_Optional_Self_Inverse2Id1`, `c0`.`OneToMany_Optional_Self_Inverse2Id2`, `c0`.`OneToMany_Required_Inverse2Id1`, `c0`.`OneToMany_Required_Inverse2Id2`, `c0`.`OneToMany_Required_Self_Inverse2Id1`, `c0`.`OneToMany_Required_Self_Inverse2Id2`, `c0`.`OneToOne_Optional_PK_Inverse2Id1`, `c0`.`OneToOne_Optional_PK_Inverse2Id2`, `c0`.`OneToOne_Optional_Self2Id1`, `c0`.`OneToOne_Optional_Self2Id2` - FROM `CompositeTwos` AS `c0` -) AS `t` ON (`c`.`Id1` = `t`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `t`.`OneToMany_Required_Inverse2Id2`) -ORDER BY `c`.`Id2`, `c`.`Id1`, `t`.`Name` DESC"); +INNER JOIN `CompositeTwos` AS `c0` ON (`c`.`Id1` = `c0`.`OneToMany_Required_Inverse2Id1`) AND (`c`.`Id2` = `c0`.`OneToMany_Required_Inverse2Id2`) +ORDER BY `c`.`Id2`, `c`.`Id1`, `c0`.`Name` DESC"); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.MySql.FunctionalTests/Query/DateOnlyQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/DateOnlyQueryMySqlTest.cs index 4815f2cfd..a0f957dd2 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/DateOnlyQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/DateOnlyQueryMySqlTest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; @@ -209,16 +210,15 @@ public Func GetContextCreator() public ISetSource GetExpectedData() => new DateOnlyQueryData(); - public IReadOnlyDictionary GetEntitySorters() + public IReadOnlyDictionary EntitySorters => new Dictionary> { { typeof(Model.IceCream), e => ((Model.IceCream)e)?.IceCreamId }, }.ToDictionary( - e => e.Key, e => (object)e.Value); + e => e.Key, e => (object)e.Value); - public IReadOnlyDictionary GetEntityAsserters() + public IReadOnlyDictionary EntityAsserters => new Dictionary> { { - typeof(Model.IceCream), - (e, a) => + typeof(Model.IceCream), (e, a) => { Assert.Equal(e == null, a == null); diff --git a/test/EFCore.MySql.FunctionalTests/Query/Ef6GroupByMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/Ef6GroupByMySqlTest.cs new file mode 100644 index 000000000..1810b87fc --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/Ef6GroupByMySqlTest.cs @@ -0,0 +1,930 @@ +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class Ef6GroupByMySqlTest : Ef6GroupByTestBase +{ + public Ef6GroupByMySqlTest(Ef6GroupByMySqlFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + // Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task GroupBy_is_optimized_when_projecting_group_key(bool async) + { + await base.GroupBy_is_optimized_when_projecting_group_key(async); + + AssertSql( +""" +SELECT `a`.`FirstName` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // [Distinct1].[FirstName] AS [FirstName] + // FROM ( SELECT DISTINCT + // [Extent1].[FirstName] AS [FirstName] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // ) AS [Distinct1]"; + } + + public override async Task GroupBy_is_optimized_when_projecting_group_count(bool async) + { + await base.GroupBy_is_optimized_when_projecting_group_count(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // [GroupBy1].[A1] AS [C1] + // FROM ( SELECT + // [Extent1].[FirstName] AS [K1], + // COUNT(1) AS [A1] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // GROUP BY [Extent1].[FirstName] + // ) AS [GroupBy1]"; + } + + public override async Task GroupBy_is_optimized_when_projecting_expression_containing_group_key(bool async) + { + await base.GroupBy_is_optimized_when_projecting_expression_containing_group_key(async); + + AssertSql( +""" +SELECT `a`.`Id` * 2 +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id` +"""); + + // EF6 SQL: + // @"SELECT + // [Extent1].[Id] * 2 AS [C1] + // FROM [dbo].[ArubaOwners] AS [Extent1]"; + } + + public override async Task GroupBy_is_optimized_when_projecting_aggregate_on_the_group(bool async) + { + await base.GroupBy_is_optimized_when_projecting_aggregate_on_the_group(async); + + AssertSql( +""" +SELECT MAX(`a`.`Id`) +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // [GroupBy1].[A1] AS [C1] + // FROM ( SELECT + // [Extent1].[FirstName] AS [K1], + // MAX([Extent1].[Id]) AS [A1] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // GROUP BY [Extent1].[FirstName] + // ) AS [GroupBy1]"; + } + + public override async Task GroupBy_is_optimized_when_projecting_anonymous_type_containing_group_key_and_group_aggregate(bool async) + { + await base.GroupBy_is_optimized_when_projecting_anonymous_type_containing_group_key_and_group_aggregate(async); + + AssertSql( +""" +SELECT `a`.`FirstName` AS `Key`, MAX(`a`.`Id`) AS `Aggregate` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // 1 AS [C1], + // [GroupBy1].[K1] AS [FirstName], + // [GroupBy1].[A1] AS [C2] + // FROM ( SELECT + // [Extent1].[FirstName] AS [K1], + // MAX([Extent1].[Id]) AS [A1] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // GROUP BY [Extent1].[FirstName] + // ) AS [GroupBy1]"; + } + + public override async Task GroupBy_is_optimized_when_projecting_anonymous_type_containing_group_key_and_multiple_group_aggregates( + bool async) + { + await base.GroupBy_is_optimized_when_projecting_anonymous_type_containing_group_key_and_multiple_group_aggregates(async); + + AssertSql( +""" +SELECT `a`.`FirstName` AS `key1`, MAX(`a`.`Id`) AS `max`, MIN(`a`.`Id` + 2) AS `min` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // 1 AS [C1], + // [GroupBy1].[K1] AS [FirstName], + // [GroupBy1].[A1] AS [C2], + // [GroupBy1].[A2] AS [C3] + // FROM ( SELECT + // [Extent1].[K1] AS [K1], + // MAX([Extent1].[A1_0]) AS [A1], + // MIN([Extent1].[A2_0]) AS [A2] + // FROM ( SELECT + // [Extent1].[FirstName] AS [K1], + // [Extent1].[Id] AS [A1_0], + // [Extent1].[Id] + 2 AS [A2_0] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // ) AS [Extent1] + // GROUP BY [K1] + // ) AS [GroupBy1]"; + } + + public override async Task GroupBy_is_optimized_when_projecting_conditional_expression_containing_group_key(bool async) + { + await base.GroupBy_is_optimized_when_projecting_conditional_expression_containing_group_key(async); + + AssertSql( +""" +@__p_0='False' + +SELECT CASE + WHEN `a`.`FirstName` IS NULL THEN 'is null' + ELSE 'not null' +END AS `keyIsNull`, @__p_0 AS `logicExpression` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // 1 AS [C1], + // CASE WHEN ([Distinct1].[FirstName] IS NULL) THEN N'is null' ELSE N'not null' END AS [C2], + // CASE WHEN (((@p__linq__0 = 1) AND (@p__linq__1 = 1)) OR ((@p__linq__2 = 1) AND (@p__linq__3 = 1))) THEN cast(1 as bit) WHEN ( NOT (((@p__linq__0 = 1) AND (@p__linq__1 = 1)) OR ((@p__linq__2 = 1) AND (@p__linq__3 = 1)))) THEN cast(0 as bit) END AS [C3] + // FROM ( SELECT DISTINCT + // [Extent1].[FirstName] AS [FirstName] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // ) AS [Distinct1]"; + } + + public override async Task GroupBy_is_optimized_when_filerting_and_projecting_anonymous_type_with_group_key_and_function_aggregate( + bool async) + { + await base.GroupBy_is_optimized_when_filerting_and_projecting_anonymous_type_with_group_key_and_function_aggregate(async); + + AssertSql( +$""" +SELECT `a`.`FirstName`, AVG({MySqlTestHelpers.CastAsDouble("`a`.`Id`")}) AS `AverageId` +FROM `ArubaOwner` AS `a` +WHERE `a`.`Id` > 5 +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // 1 AS [C1], + // [GroupBy1].[K1] AS [FirstName], + // [GroupBy1].[A1] AS [C2] + // FROM ( SELECT + // [Extent1].[FirstName] AS [K1], + // AVG( CAST( [Extent1].[Id] AS float)) AS [A1] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // WHERE [Extent1].[Id] > 5 + // GROUP BY [Extent1].[FirstName] + // ) AS [GroupBy1]"; + } + + public override async Task GroupBy_is_optimized_when_projecting_function_aggregate_with_expression(bool async) + { + await base.GroupBy_is_optimized_when_projecting_function_aggregate_with_expression(async); + + AssertSql( +""" +SELECT MAX(`a`.`Id` * 2) +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // [GroupBy1].[A1] AS [C1] + // FROM ( SELECT + // [Extent1].[K1] AS [K1], + // MAX([Extent1].[A1_0]) AS [A1] + // FROM ( SELECT + // [Extent1].[FirstName] AS [K1], + // [Extent1].[Id] * 2 AS [A1_0] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // ) AS [Extent1] + // GROUP BY [K1] + // ) AS [GroupBy1]"; + } + + public override async Task GroupBy_is_optimized_when_projecting_expression_with_multiple_function_aggregates(bool async) + { + await base.GroupBy_is_optimized_when_projecting_expression_with_multiple_function_aggregates(async); + + AssertSql( +""" +SELECT MAX(`a`.`Id`) - MIN(`a`.`Id`) AS `maxMinusMin` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // 1 AS [C1], + // [GroupBy1].[A1] - [GroupBy1].[A2] AS [C2] + // FROM ( SELECT + // [Extent1].[FirstName] AS [K1], + // MAX([Extent1].[Id]) AS [A1], + // MIN([Extent1].[Id]) AS [A2] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // GROUP BY [Extent1].[FirstName] + // ) AS [GroupBy1]"; + } + + public override async Task GroupBy_is_optimized_when_grouping_by_row_and_projecting_column_of_the_key_row(bool async) + { + await base.GroupBy_is_optimized_when_grouping_by_row_and_projecting_column_of_the_key_row(async); + + AssertSql( +""" +SELECT `a`.`FirstName` +FROM `ArubaOwner` AS `a` +WHERE `a`.`Id` < 4 +GROUP BY `a`.`FirstName` +"""); + + // EF6 SQL: + // @"SELECT + // [Distinct1].[FirstName] AS [FirstName] + // FROM ( SELECT DISTINCT + // [Extent1].[FirstName] AS [FirstName] + // FROM [dbo].[ArubaOwners] AS [Extent1] + // WHERE [Extent1].[Id] < 4 + // ) AS [Distinct1]"; + } + + public override async Task Grouping_by_all_columns_doesnt_produce_a_groupby_statement(bool async) + { + await base.Grouping_by_all_columns_doesnt_produce_a_groupby_statement(async); + + AssertSql( +""" +SELECT `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_1(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_1(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`FirstName`, `a`.`LastName`, `a`.`Alias` +"""); + + // EF6 SQL: + // @"SELECT + // (SELECT + // COUNT(1) AS [A1] + // FROM [dbo].[ArubaOwners] AS [Extent2] + // WHERE [Extent1].[Id] = [Extent2].[Id]) AS [C1] + // FROM [dbo].[ArubaOwners] AS [Extent1]"; + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_2(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_2(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_3(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_3(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_4(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_4(async); + + AssertSql( +""" +SELECT COUNT(*) AS `Count` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_5(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_5(async); + + AssertSql( +""" +SELECT `a`.`Id`, COUNT(*) AS `Count` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_6(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_6(async); + + AssertSql( +""" +SELECT `a`.`Id`, `a`.`Alias`, COUNT(*) AS `Count` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_7(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_7(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_8(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_8(async); + + AssertSql( +""" +SELECT `a`.`Id`, COUNT(*) AS `Count` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_9(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_9(async); + + AssertSql( +""" +SELECT `a`.`Id`, `a`.`Alias`, COUNT(*) AS `Count` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task Grouping_by_all_columns_with_aggregate_function_works_10(bool async) + { + await base.Grouping_by_all_columns_with_aggregate_function_works_10(async); + + AssertSql( +""" +SELECT `a`.`Id`, COALESCE(SUM(`a`.`Id`), 0) AS `Sum`, COUNT(*) AS `Count` +FROM `ArubaOwner` AS `a` +GROUP BY `a`.`Id`, `a`.`Alias`, `a`.`FirstName`, `a`.`LastName` +"""); + } + + public override async Task GroupBy_Simple_1_from_LINQ_101(bool async) + { + await base.GroupBy_Simple_1_from_LINQ_101(async); + + AssertSql(); + } + + public override async Task GroupBy_Simple_2_from_LINQ_101(bool async) + { + await base.GroupBy_Simple_2_from_LINQ_101(async); + + AssertSql(); + } + + public override async Task GroupBy_Simple_3_from_LINQ_101(bool async) + { + await base.GroupBy_Simple_3_from_LINQ_101(async); + + AssertSql(); + } + + public override async Task GroupBy_Nested_from_LINQ_101(bool async) + { + await base.GroupBy_Nested_from_LINQ_101(async); + + AssertSql(); + } + + public override async Task Any_Grouped_from_LINQ_101(bool async) + { + await base.Any_Grouped_from_LINQ_101(async); + + AssertSql(); + } + + public override async Task All_Grouped_from_LINQ_101(bool async) + { + await base.All_Grouped_from_LINQ_101(async); + + AssertSql(); + } + + public override async Task Min_Elements_from_LINQ_101(bool async) + { + await base.Min_Elements_from_LINQ_101(async); + + AssertSql(); + } + + public override async Task Max_Elements_from_LINQ_101(bool async) + { + await base.Max_Elements_from_LINQ_101(async); + + AssertSql(); + } + + public override async Task Group_Join_from_LINQ_101(bool async) + { + await base.Group_Join_from_LINQ_101(async); + + AssertSql( +""" +SELECT `c`.`Id`, `c`.`CompanyName`, `c`.`Region`, `t`.`Id`, `t`.`CustomerId`, `t`.`OrderDate`, `t`.`Total`, `t`.`Id0` +FROM `CustomerForLinq` AS `c` +LEFT JOIN LATERAL ( + SELECT `o`.`Id`, `o`.`CustomerId`, `o`.`OrderDate`, `o`.`Total`, `c0`.`Id` AS `Id0` + FROM `OrderForLinq` AS `o` + LEFT JOIN `CustomerForLinq` AS `c0` ON `o`.`CustomerId` = `c0`.`Id` + WHERE `c`.`Id` = `c0`.`Id` +) AS `t` ON TRUE +ORDER BY `c`.`Id`, `t`.`Id` +"""); + } + + [ConditionalTheory(Skip = "Check why this does not throw in CI (MySQL 8.0.x), but does locally in the mysql:latest docker container.")] + public override async Task Whats_new_2021_sample_3(bool async) + { + // GroupBy debug assert. Issue #26104. + Assert.StartsWith( + "Missing alias in the list", + (await Assert.ThrowsAsync( + () => base.Whats_new_2021_sample_3(async))).Message); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Check why this does not throw in CI (MySQL 8.0.x), but does locally in the mysql:latest docker container.")] + public override async Task Whats_new_2021_sample_5(bool async) + { + await base.Whats_new_2021_sample_5(async); + + AssertSql( + """ +SELECT ( + SELECT p1."LastName" + FROM "Person" AS p1 + WHERE p."FirstName" = p1."FirstName" OR ((p."FirstName" IS NULL) AND (p1."FirstName" IS NULL)) + LIMIT 1) +FROM "Person" AS p +GROUP BY p."FirstName" +ORDER BY ( + SELECT p1."LastName" + FROM "Person" AS p1 + WHERE p."FirstName" = p1."FirstName" OR ((p."FirstName" IS NULL) AND (p1."FirstName" IS NULL)) + LIMIT 1) NULLS FIRST +"""); + } + + [ConditionalTheory(Skip = "Check why this does not throw in CI (MySQL 8.0.x), but does locally in the mysql:latest docker container.")] + public override async Task Whats_new_2021_sample_6(bool async) + { + // GroupBy debug assert. Issue #26104. + Assert.StartsWith( + "Missing alias in the list", + (await Assert.ThrowsAsync( + () => base.Whats_new_2021_sample_6(async))).Message); + + AssertSql(); + } + + public override async Task Whats_new_2021_sample_14(bool async) + { + await base.Whats_new_2021_sample_14(async); + + AssertSql(); + } + + public override async Task Whats_new_2021_sample_15(bool async) + { + await base.Whats_new_2021_sample_15(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Age`, `t0`.`FirstName`, `t0`.`LastName`, `t0`.`MiddleInitial` +FROM ( + SELECT `f`.`Id`, `f`.`Size` + FROM `Person` AS `p` + LEFT JOIN `Feet` AS `f` ON `p`.`Id` = `f`.`Id` + GROUP BY `f`.`Id`, `f`.`Size` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Id`, `t1`.`Age`, `t1`.`FirstName`, `t1`.`LastName`, `t1`.`MiddleInitial`, `t1`.`Id0`, `t1`.`Size` + FROM ( + SELECT `p0`.`Id`, `p0`.`Age`, `p0`.`FirstName`, `p0`.`LastName`, `p0`.`MiddleInitial`, `f0`.`Id` AS `Id0`, `f0`.`Size`, ROW_NUMBER() OVER(PARTITION BY `f0`.`Id`, `f0`.`Size` ORDER BY `p0`.`Id` DESC) AS `row` + FROM `Person` AS `p0` + LEFT JOIN `Feet` AS `f0` ON `p0`.`Id` = `f0`.`Id` + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON ((`t`.`Id` = `t0`.`Id0`) OR (`t`.`Id` IS NULL AND (`t0`.`Id0` IS NULL))) AND ((`t`.`Size` = `t0`.`Size`) OR (`t`.`Size` IS NULL AND (`t0`.`Size` IS NULL))) +"""); + } + + public override async Task Whats_new_2021_sample_16(bool async) + { + await base.Whats_new_2021_sample_16(async); + + AssertSql(); + } + + public override async Task Min_Grouped_from_LINQ_101(bool async) + { + await base.Min_Grouped_from_LINQ_101(async); + + AssertSql( +""" +SELECT `p`.`Category`, MIN(`p`.`UnitPrice`) AS `CheapestPrice` +FROM `ProductForLinq` AS `p` +GROUP BY `p`.`Category` +"""); + } + + public override async Task Average_Grouped_from_LINQ_101(bool async) + { + await base.Average_Grouped_from_LINQ_101(async); + + AssertSql( +""" +SELECT `p`.`Category`, AVG(`p`.`UnitPrice`) AS `AveragePrice` +FROM `ProductForLinq` AS `p` +GROUP BY `p`.`Category` +"""); + } + + public override async Task Whats_new_2021_sample_8(bool async) + { + await base.Whats_new_2021_sample_8(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM ( + SELECT `f`.`Id`, `f`.`Size` + FROM `Person` AS `p` + LEFT JOIN `Feet` AS `f` ON `p`.`Id` = `f`.`Id` + GROUP BY `f`.`Id`, `f`.`Size` +) AS `t` +"""); + } + + public override async Task Whats_new_2021_sample_12(bool async) + { + await base.Whats_new_2021_sample_12(async); + + AssertSql( +""" +SELECT `t`.`FirstName`, `t0`.`Id`, `t0`.`Age`, `t0`.`FirstName`, `t0`.`LastName`, `t0`.`MiddleInitial`, `t0`.`Id0`, `t0`.`Age0`, `t0`.`PersonId`, `t0`.`Style` +FROM ( + SELECT `p`.`FirstName` + FROM `Person` AS `p` + GROUP BY `p`.`FirstName` +) AS `t` +LEFT JOIN ( + SELECT `p0`.`Id`, `p0`.`Age`, `p0`.`FirstName`, `p0`.`LastName`, `p0`.`MiddleInitial`, `s`.`Id` AS `Id0`, `s`.`Age` AS `Age0`, `s`.`PersonId`, `s`.`Style` + FROM `Person` AS `p0` + LEFT JOIN `Shoes` AS `s` ON `p0`.`Id` = `s`.`PersonId` +) AS `t0` ON `t`.`FirstName` = `t0`.`FirstName` +ORDER BY `t`.`FirstName`, `t0`.`Id` +"""); + } + + public override async Task Whats_new_2021_sample_10(bool async) + { + await base.Whats_new_2021_sample_10(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Age`, `t`.`Style`, `t0`.`Id`, `t0`.`Style`, `t0`.`Age`, `t0`.`Id0` +FROM ( + SELECT `p`.`Id`, `s`.`Age`, `s`.`Style` + FROM `Person` AS `p` + INNER JOIN `Shoes` AS `s` ON `p`.`Age` = `s`.`Age` + GROUP BY `p`.`Id`, `s`.`Style`, `s`.`Age` +) AS `t` +LEFT JOIN ( + SELECT `s0`.`Id`, `s0`.`Style`, `s0`.`Age`, `p0`.`Id` AS `Id0` + FROM `Person` AS `p0` + INNER JOIN `Shoes` AS `s0` ON `p0`.`Age` = `s0`.`Age` +) AS `t0` ON ((`t`.`Id` = `t0`.`Id0`) AND ((`t`.`Style` = `t0`.`Style`) OR (`t`.`Style` IS NULL AND (`t0`.`Style` IS NULL)))) AND (`t`.`Age` = `t0`.`Age`) +ORDER BY `t`.`Id`, `t`.`Style`, `t`.`Age`, `t0`.`Id0` +"""); + } + + public override async Task Whats_new_2021_sample_13(bool async) + { + await base.Whats_new_2021_sample_13(async); + + AssertSql( +""" +SELECT `t`.`FirstName`, `t`.`MiddleInitial`, `p0`.`Id`, `p0`.`Age`, `p0`.`FirstName`, `p0`.`LastName`, `p0`.`MiddleInitial` +FROM ( + SELECT `p`.`FirstName`, `p`.`MiddleInitial` + FROM `Person` AS `p` + GROUP BY `p`.`FirstName`, `p`.`MiddleInitial` +) AS `t` +LEFT JOIN `Person` AS `p0` ON ((`t`.`FirstName` = `p0`.`FirstName`) OR (`t`.`FirstName` IS NULL AND (`p0`.`FirstName` IS NULL))) AND ((`t`.`MiddleInitial` = `p0`.`MiddleInitial`) OR (`t`.`MiddleInitial` IS NULL AND (`p0`.`MiddleInitial` IS NULL))) +ORDER BY `t`.`FirstName`, `t`.`MiddleInitial`, `p0`.`Id` +"""); + } + + public override async Task Cross_Join_with_Group_Join_from_LINQ_101(bool async) + { + await base.Cross_Join_with_Group_Join_from_LINQ_101(async); + + AssertSql( +""" +SELECT `c`.`Id`, `c`.`CompanyName`, `c`.`Region`, `t`.`Id` +FROM `CustomerForLinq` AS `c` +INNER JOIN ( + SELECT `o`.`Id`, `c0`.`Id` AS `Id0` + FROM `OrderForLinq` AS `o` + LEFT JOIN `CustomerForLinq` AS `c0` ON `o`.`CustomerId` = `c0`.`Id` +) AS `t` ON `c`.`Id` = `t`.`Id0` +"""); + } + + public override async Task Whats_new_2021_sample_2(bool async) + { + await base.Whats_new_2021_sample_2(async); + + AssertSql( +""" +SELECT `t0`.`FirstName`, `t0`.`FullName`, `t0`.`c` +FROM ( + SELECT `p`.`FirstName` + FROM `Person` AS `p` + GROUP BY `p`.`FirstName` + ORDER BY `p`.`FirstName` + LIMIT 1 +) AS `t` +LEFT JOIN ( + SELECT `t1`.`FirstName`, `t1`.`FullName`, `t1`.`c` + FROM ( + SELECT `p0`.`FirstName`, CONCAT(CONCAT(CONCAT(CONCAT(COALESCE(`p0`.`FirstName`, ''), ' '), COALESCE(`p0`.`MiddleInitial`, '')), ' '), COALESCE(`p0`.`LastName`, '')) AS `FullName`, 1 AS `c`, ROW_NUMBER() OVER(PARTITION BY `p0`.`FirstName` ORDER BY `p0`.`Id`) AS `row` + FROM `Person` AS `p0` + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`FirstName` = `t0`.`FirstName` +ORDER BY `t`.`FirstName` +"""); + } + + public override async Task Whats_new_2021_sample_1(bool async) + { + await base.Whats_new_2021_sample_1(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Age`, `t0`.`FirstName`, `t0`.`LastName`, `t0`.`MiddleInitial`, `t`.`FirstName`, `s`.`Id`, `s`.`Age`, `s`.`PersonId`, `s`.`Style` +FROM ( + SELECT `p`.`FirstName` + FROM `Person` AS `p` + GROUP BY `p`.`FirstName` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Id`, `t1`.`Age`, `t1`.`FirstName`, `t1`.`LastName`, `t1`.`MiddleInitial` + FROM ( + SELECT `p0`.`Id`, `p0`.`Age`, `p0`.`FirstName`, `p0`.`LastName`, `p0`.`MiddleInitial`, ROW_NUMBER() OVER(PARTITION BY `p0`.`FirstName` ORDER BY `p0`.`FirstName`, `p0`.`LastName`) AS `row` + FROM `Person` AS `p0` + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`FirstName` = `t0`.`FirstName` +LEFT JOIN `Shoes` AS `s` ON `t0`.`Id` = `s`.`PersonId` +ORDER BY `t`.`FirstName`, `t0`.`Id` +"""); + } + + public override async Task Whats_new_2021_sample_7(bool async) + { + await base.Whats_new_2021_sample_7(async); + + AssertSql( +""" +@__size_0='11' + +SELECT `p0`.`LastName`, `f`.`Size`, ( + SELECT MIN(`f1`.`Size`) + FROM `Person` AS `p1` + LEFT JOIN `Feet` AS `f0` ON `p1`.`Id` = `f0`.`Id` + LEFT JOIN `Person` AS `p2` ON `f0`.`Id` = `p2`.`Id` + LEFT JOIN `Feet` AS `f1` ON `p1`.`Id` = `f1`.`Id` + WHERE (((`f0`.`Size` = @__size_0) AND `p1`.`MiddleInitial` IS NOT NULL) AND ((`f0`.`Id` <> 1) OR `f0`.`Id` IS NULL)) AND (((`f`.`Size` = `f0`.`Size`) OR (`f`.`Size` IS NULL AND (`f0`.`Size` IS NULL))) AND ((`p0`.`LastName` = `p2`.`LastName`) OR (`p0`.`LastName` IS NULL AND (`p2`.`LastName` IS NULL))))) AS `Min` +FROM `Person` AS `p` +LEFT JOIN `Feet` AS `f` ON `p`.`Id` = `f`.`Id` +LEFT JOIN `Person` AS `p0` ON `f`.`Id` = `p0`.`Id` +WHERE ((`f`.`Size` = @__size_0) AND `p`.`MiddleInitial` IS NOT NULL) AND ((`f`.`Id` <> 1) OR `f`.`Id` IS NULL) +GROUP BY `f`.`Size`, `p0`.`LastName` +"""); + } + + public override async Task Sum_Grouped_from_LINQ_101(bool async) + { + await base.Sum_Grouped_from_LINQ_101(async); + + AssertSql( +""" +SELECT `p`.`Category`, COALESCE(SUM(`p`.`UnitsInStock`), 0) AS `TotalUnitsInStock` +FROM `ProductForLinq` AS `p` +GROUP BY `p`.`Category` +"""); + } + + public override async Task Count_Grouped_from_LINQ_101(bool async) + { + await base.Count_Grouped_from_LINQ_101(async); + + AssertSql( +""" +SELECT `p`.`Category`, COUNT(*) AS `ProductCount` +FROM `ProductForLinq` AS `p` +GROUP BY `p`.`Category` +"""); + } + + public override async Task Whats_new_2021_sample_9(bool async) + { + await base.Whats_new_2021_sample_9(async); + + AssertSql( +""" +SELECT `p`.`FirstName` AS `Feet`, ( + SELECT COALESCE(SUM(`f`.`Size`), 0) + FROM `Person` AS `p0` + LEFT JOIN `Feet` AS `f` ON `p0`.`Id` = `f`.`Id` + WHERE (`p`.`FirstName` = `p0`.`FirstName`) OR (`p`.`FirstName` IS NULL AND (`p0`.`FirstName` IS NULL))) AS `Total` +FROM `Person` AS `p` +GROUP BY `p`.`FirstName` +"""); + } + + public override async Task LongCount_Grouped_from_LINQ_101(bool async) + { + await base.LongCount_Grouped_from_LINQ_101(async); + + AssertSql( +""" +SELECT `p`.`Category`, COUNT(*) AS `ProductLongCount` +FROM `ProductForLinq` AS `p` +GROUP BY `p`.`Category` +"""); + } + + public override async Task Whats_new_2021_sample_4(bool async) + { + await base.Whats_new_2021_sample_4(async); + + AssertSql( +""" +SELECT `s`.`Style` AS `Key`, ( + SELECT `s0`.`Style` + FROM `Person` AS `p0` + INNER JOIN `Shoes` AS `s0` ON `p0`.`Age` = `s0`.`Age` + WHERE (`s`.`Style` = `s0`.`Style`) OR (`s`.`Style` IS NULL AND (`s0`.`Style` IS NULL)) + LIMIT 1) AS `Style`, COUNT(*) AS `Count` +FROM `Person` AS `p` +INNER JOIN `Shoes` AS `s` ON `p`.`Age` = `s`.`Age` +GROUP BY `s`.`Style` +"""); + } + + public override async Task Left_Outer_Join_with_Group_Join_from_LINQ_101(bool async) + { + await base.Left_Outer_Join_with_Group_Join_from_LINQ_101(async); + + AssertSql( +""" +SELECT `c`.`Id`, `c`.`CompanyName`, `c`.`Region`, `t`.`Id`, `t`.`Id0`, `o0`.`Id`, `o0`.`CustomerId`, `o0`.`OrderDate`, `o0`.`Total`, CASE + WHEN `t`.`Id` IS NULL THEN -1 + ELSE `t`.`Id` +END +FROM `CustomerForLinq` AS `c` +LEFT JOIN ( + SELECT `o`.`Id`, `c0`.`Id` AS `Id0` + FROM `OrderForLinq` AS `o` + LEFT JOIN `CustomerForLinq` AS `c0` ON `o`.`CustomerId` = `c0`.`Id` +) AS `t` ON `c`.`Id` = `t`.`Id0` +LEFT JOIN `OrderForLinq` AS `o0` ON `c`.`Id` = `o0`.`CustomerId` +ORDER BY `c`.`Id`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Max_Grouped_from_LINQ_101(bool async) + { + await base.Max_Grouped_from_LINQ_101(async); + + AssertSql( +""" +SELECT `p`.`Category`, MAX(`p`.`UnitPrice`) AS `MostExpensivePrice` +FROM `ProductForLinq` AS `p` +GROUP BY `p`.`Category` +"""); + } + + public override async Task Whats_new_2021_sample_11(bool async) + { + await base.Whats_new_2021_sample_11(async); + + AssertSql( +""" +SELECT `t`.`LastName`, `t`.`c`, `t0`.`Id`, `t2`.`Id`, `t2`.`Age`, `t2`.`FirstName`, `t2`.`LastName`, `t2`.`MiddleInitial`, `t0`.`Age`, `t0`.`FirstName`, `t0`.`LastName`, `t0`.`MiddleInitial` +FROM ( + SELECT `p`.`LastName`, COUNT(*) AS `c` + FROM `Person` AS `p` + GROUP BY `p`.`LastName` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Id`, `t1`.`Age`, `t1`.`FirstName`, `t1`.`LastName`, `t1`.`MiddleInitial` + FROM ( + SELECT `p0`.`Id`, `p0`.`Age`, `p0`.`FirstName`, `p0`.`LastName`, `p0`.`MiddleInitial`, ROW_NUMBER() OVER(PARTITION BY `p0`.`LastName` ORDER BY `p0`.`Id`) AS `row` + FROM `Person` AS `p0` + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`LastName` = `t0`.`LastName` +LEFT JOIN ( + SELECT `t3`.`Id`, `t3`.`Age`, `t3`.`FirstName`, `t3`.`LastName`, `t3`.`MiddleInitial` + FROM ( + SELECT `p1`.`Id`, `p1`.`Age`, `p1`.`FirstName`, `p1`.`LastName`, `p1`.`MiddleInitial`, ROW_NUMBER() OVER(PARTITION BY `p1`.`LastName` ORDER BY `p1`.`Id`) AS `row` + FROM `Person` AS `p1` + ) AS `t3` + WHERE `t3`.`row` <= 2 +) AS `t2` ON `t`.`LastName` = `t2`.`LastName` +ORDER BY `t`.`LastName` DESC, `t0`.`Id`, `t2`.`LastName`, `t2`.`Id` +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + public class Ef6GroupByMySqlFixture : Ef6GroupByFixtureBase + { + public TestSqlLoggerFactory TestSqlLoggerFactory + => (TestSqlLoggerFactory)ListLoggerFactory; + + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + // modelBuilder.Entity().Property(o => o.OrderDate).HasColumnType("timestamp"); + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/EntitySplittingQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/EntitySplittingQueryMySqlTest.cs new file mode 100644 index 000000000..16693507e --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/EntitySplittingQueryMySqlTest.cs @@ -0,0 +1,788 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class EntitySplittingQueryMySqlTest : EntitySplittingQueryTestBase +{ + public EntitySplittingQueryMySqlTest(ITestOutputHelper testOutputHelper) + { + // Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Can_query_entity_which_is_split_in_two(bool async) + { + await base.Can_query_entity_which_is_split_in_two(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityThreeId`, `e`.`IntValue1`, `e`.`IntValue2`, `s`.`IntValue3`, `s`.`IntValue4`, `e`.`StringValue1`, `e`.`StringValue2`, `s`.`StringValue3`, `s`.`StringValue4` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart` AS `s` ON `e`.`Id` = `s`.`Id` +"""); + } + + public override async Task Can_query_entity_which_is_split_selecting_only_main_properties(bool async) + { + await base.Can_query_entity_which_is_split_selecting_only_main_properties(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`IntValue1`, `e`.`StringValue1` +FROM `EntityOne` AS `e` +"""); + } + + public override async Task Can_query_entity_which_is_split_in_three(bool async) + { + await base.Can_query_entity_which_is_split_in_three(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityThreeId`, `e`.`IntValue1`, `e`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e`.`StringValue1`, `e`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart3` AS `s` ON `e`.`Id` = `s`.`Id` +INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e`.`Id` = `s0`.`Id` +"""); + } + + public override async Task Can_query_entity_which_is_split_selecting_only_part_2_properties(bool async) + { + await base.Can_query_entity_which_is_split_selecting_only_part_2_properties(async); + + AssertSql( +""" +SELECT `e`.`Id`, `s0`.`IntValue3`, `s0`.`StringValue3` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e`.`Id` = `s0`.`Id` +"""); + } + + public override async Task Can_query_entity_which_is_split_selecting_only_part_3_properties(bool async) + { + await base.Can_query_entity_which_is_split_selecting_only_part_3_properties(async); + + AssertSql( +""" +SELECT `e`.`Id`, `s`.`IntValue4`, `s`.`StringValue4` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart3` AS `s` ON `e`.`Id` = `s`.`Id` +"""); + } + + public override async Task Include_reference_to_split_entity(bool async) + { + await base.Include_reference_to_split_entity(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityOneId`, `e`.`Name`, `t`.`Id`, `t`.`EntityThreeId`, `t`.`IntValue1`, `t`.`IntValue2`, `t`.`IntValue3`, `t`.`IntValue4`, `t`.`StringValue1`, `t`.`StringValue2`, `t`.`StringValue3`, `t`.`StringValue4` +FROM `EntityTwo` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`EntityThreeId`, `e0`.`IntValue1`, `e0`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e0`.`StringValue1`, `e0`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4` + FROM `EntityOne` AS `e0` + INNER JOIN `SplitEntityOnePart3` AS `s` ON `e0`.`Id` = `s`.`Id` + INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e0`.`Id` = `s0`.`Id` +) AS `t` ON `e`.`EntityOneId` = `t`.`Id` +"""); + } + + public override async Task Include_collection_to_split_entity(bool async) + { + await base.Include_collection_to_split_entity(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t`.`Id`, `t`.`EntityThreeId`, `t`.`IntValue1`, `t`.`IntValue2`, `t`.`IntValue3`, `t`.`IntValue4`, `t`.`StringValue1`, `t`.`StringValue2`, `t`.`StringValue3`, `t`.`StringValue4` +FROM `EntityThree` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`EntityThreeId`, `e0`.`IntValue1`, `e0`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e0`.`StringValue1`, `e0`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4` + FROM `EntityOne` AS `e0` + INNER JOIN `SplitEntityOnePart3` AS `s` ON `e0`.`Id` = `s`.`Id` + INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e0`.`Id` = `s0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`EntityThreeId` +ORDER BY `e`.`Id` +"""); + } + + public override async Task Include_reference_to_split_entity_including_reference(bool async) + { + await base.Include_reference_to_split_entity_including_reference(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityOneId`, `e`.`Name`, `t`.`Id`, `t`.`EntityThreeId`, `t`.`IntValue1`, `t`.`IntValue2`, `t`.`IntValue3`, `t`.`IntValue4`, `t`.`StringValue1`, `t`.`StringValue2`, `t`.`StringValue3`, `t`.`StringValue4`, `e1`.`Id`, `e1`.`Name` +FROM `EntityTwo` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`EntityThreeId`, `e0`.`IntValue1`, `e0`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e0`.`StringValue1`, `e0`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4` + FROM `EntityOne` AS `e0` + INNER JOIN `SplitEntityOnePart3` AS `s` ON `e0`.`Id` = `s`.`Id` + INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e0`.`Id` = `s0`.`Id` +) AS `t` ON `e`.`EntityOneId` = `t`.`Id` +LEFT JOIN `EntityThree` AS `e1` ON `t`.`EntityThreeId` = `e1`.`Id` +"""); + } + + public override async Task Include_collection_to_split_entity_including_collection(bool async) + { + await base.Include_collection_to_split_entity_including_collection(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t`.`Id`, `t`.`EntityThreeId`, `t`.`IntValue1`, `t`.`IntValue2`, `t`.`IntValue3`, `t`.`IntValue4`, `t`.`StringValue1`, `t`.`StringValue2`, `t`.`StringValue3`, `t`.`StringValue4`, `t`.`Id0`, `t`.`EntityOneId`, `t`.`Name` +FROM `EntityThree` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`EntityThreeId`, `e0`.`IntValue1`, `e0`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e0`.`StringValue1`, `e0`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4`, `e1`.`Id` AS `Id0`, `e1`.`EntityOneId`, `e1`.`Name` + FROM `EntityOne` AS `e0` + INNER JOIN `SplitEntityOnePart3` AS `s` ON `e0`.`Id` = `s`.`Id` + INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e0`.`Id` = `s0`.`Id` + LEFT JOIN `EntityTwo` AS `e1` ON `e0`.`Id` = `e1`.`EntityOneId` +) AS `t` ON `e`.`Id` = `t`.`EntityThreeId` +ORDER BY `e`.`Id`, `t`.`Id` +"""); + } + + public override async Task Include_reference_on_split_entity(bool async) + { + await base.Include_reference_on_split_entity(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityThreeId`, `e`.`IntValue1`, `e`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e`.`StringValue1`, `e`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4`, `e0`.`Id`, `e0`.`Name` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart3` AS `s` ON `e`.`Id` = `s`.`Id` +INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e`.`Id` = `s0`.`Id` +LEFT JOIN `EntityThree` AS `e0` ON `e`.`EntityThreeId` = `e0`.`Id` +"""); + } + + public override async Task Include_collection_on_split_entity(bool async) + { + await base.Include_collection_on_split_entity(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityThreeId`, `e`.`IntValue1`, `e`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e`.`StringValue1`, `e`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4`, `e0`.`Id`, `e0`.`EntityOneId`, `e0`.`Name` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart3` AS `s` ON `e`.`Id` = `s`.`Id` +INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e`.`Id` = `s0`.`Id` +LEFT JOIN `EntityTwo` AS `e0` ON `e`.`Id` = `e0`.`EntityOneId` +ORDER BY `e`.`Id` +"""); + } + + public override async Task Custom_projection_trim_when_multiple_tables(bool async) + { + await base.Custom_projection_trim_when_multiple_tables(async); + + AssertSql( +""" +SELECT `e`.`IntValue1`, `s0`.`IntValue3`, `e0`.`Id`, `e0`.`Name` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e`.`Id` = `s0`.`Id` +LEFT JOIN `EntityThree` AS `e0` ON `e`.`EntityThreeId` = `e0`.`Id` +"""); + } + + public override async Task Normal_entity_owning_a_split_reference_with_main_fragment_sharing(bool async) + { + await base.Normal_entity_owning_a_split_reference_with_main_fragment_sharing(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityThreeId`, `e`.`IntValue1`, `e`.`IntValue2`, `e`.`IntValue3`, `e`.`IntValue4`, `e`.`StringValue1`, `e`.`StringValue2`, `e`.`StringValue3`, `e`.`StringValue4`, `e`.`OwnedReference_Id`, `e`.`OwnedReference_OwnedIntValue1`, `e`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `e`.`OwnedReference_OwnedStringValue1`, `e`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `EntityOne` AS `e` +LEFT JOIN `OwnedReferenceExtras2` AS `o` ON `e`.`Id` = `o`.`EntityOneId` +LEFT JOIN `OwnedReferenceExtras1` AS `o0` ON `e`.`Id` = `o0`.`EntityOneId` +"""); + } + + public override async Task Normal_entity_owning_a_split_reference_with_main_fragment_sharing_custom_projection(bool async) + { + await base.Normal_entity_owning_a_split_reference_with_main_fragment_sharing_custom_projection(async); + + AssertSql( +""" +SELECT `e`.`Id`, CASE + WHEN (((`e`.`OwnedReference_Id` IS NOT NULL AND (`e`.`OwnedReference_OwnedIntValue1` IS NOT NULL)) AND `e`.`OwnedReference_OwnedIntValue2` IS NOT NULL) AND `o0`.`OwnedIntValue3` IS NOT NULL) AND `o`.`OwnedIntValue4` IS NOT NULL THEN `o`.`OwnedIntValue4` +END AS `OwnedIntValue4`, CASE + WHEN (((`e`.`OwnedReference_Id` IS NOT NULL AND (`e`.`OwnedReference_OwnedIntValue1` IS NOT NULL)) AND `e`.`OwnedReference_OwnedIntValue2` IS NOT NULL) AND `o0`.`OwnedIntValue3` IS NOT NULL) AND `o`.`OwnedIntValue4` IS NOT NULL THEN `o`.`OwnedStringValue4` +END AS `OwnedStringValue4` +FROM `EntityOnes` AS `e` +LEFT JOIN `OwnedReferenceExtras2` AS `o` ON `e`.`Id` = `o`.`EntityOneId` +LEFT JOIN `OwnedReferenceExtras1` AS `o0` ON `e`.`Id` = `o0`.`EntityOneId` +"""); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Normal_entity_owning_a_split_reference_with_main_fragment_not_sharing(bool async) + { + await base.Normal_entity_owning_a_split_reference_with_main_fragment_not_sharing(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Normal_entity_owning_a_split_reference_with_main_fragment_not_sharing_custom_projection(bool async) + { + await base.Normal_entity_owning_a_split_reference_with_main_fragment_not_sharing_custom_projection(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Normal_entity_owning_a_split_collection(bool async) + { + await base.Normal_entity_owning_a_split_collection(async); + + AssertSql(); + } + + public override async Task Normal_entity_owning_a_split_reference_with_main_fragment_sharing_multiple_level(bool async) + { + await base.Normal_entity_owning_a_split_reference_with_main_fragment_sharing_multiple_level(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityThreeId`, `e`.`IntValue1`, `e`.`IntValue2`, `e`.`IntValue3`, `e`.`IntValue4`, `e`.`StringValue1`, `e`.`StringValue2`, `e`.`StringValue3`, `e`.`StringValue4`, `e`.`OwnedReference_Id`, `e`.`OwnedReference_OwnedIntValue1`, `e`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `e`.`OwnedReference_OwnedStringValue1`, `e`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4`, `e`.`OwnedReference_OwnedNestedReference_Id`, `e`.`OwnedReference_OwnedNestedReference_OwnedNestedIntValue1`, `e`.`OwnedReference_OwnedNestedReference_OwnedNestedIntValue2`, `o2`.`OwnedNestedIntValue3`, `o1`.`OwnedNestedIntValue4`, `e`.`OwnedReference_OwnedNestedReference_OwnedNestedStringValue1`, `e`.`OwnedReference_OwnedNestedReference_OwnedNestedStringValue2`, `o2`.`OwnedNestedStringValue3`, `o1`.`OwnedNestedStringValue4` +FROM `EntityOnes` AS `e` +LEFT JOIN `OwnedReferenceExtras2` AS `o` ON `e`.`Id` = `o`.`EntityOneId` +LEFT JOIN `OwnedReferenceExtras1` AS `o0` ON `e`.`Id` = `o0`.`EntityOneId` +LEFT JOIN `OwnedNestedReferenceExtras2` AS `o1` ON `e`.`Id` = `o1`.`OwnedReferenceEntityOneId` +LEFT JOIN `OwnedNestedReferenceExtras1` AS `o2` ON `e`.`Id` = `o2`.`OwnedReferenceEntityOneId` +"""); + } + + public override async Task Split_entity_owning_a_reference(bool async) + { + await base.Split_entity_owning_a_reference(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityThreeId`, `e`.`IntValue1`, `e`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e`.`StringValue1`, `e`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4`, `e`.`OwnedReference_Id`, `e`.`OwnedReference_OwnedIntValue1`, `e`.`OwnedReference_OwnedIntValue2`, `e`.`OwnedReference_OwnedIntValue3`, `e`.`OwnedReference_OwnedIntValue4`, `e`.`OwnedReference_OwnedStringValue1`, `e`.`OwnedReference_OwnedStringValue2`, `e`.`OwnedReference_OwnedStringValue3`, `e`.`OwnedReference_OwnedStringValue4` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart3` AS `s` ON `e`.`Id` = `s`.`Id` +INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e`.`Id` = `s0`.`Id` +"""); + } + + public override async Task Split_entity_owning_a_collection(bool async) + { + await base.Split_entity_owning_a_collection(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`EntityThreeId`, `e`.`IntValue1`, `e`.`IntValue2`, `s0`.`IntValue3`, `s`.`IntValue4`, `e`.`StringValue1`, `e`.`StringValue2`, `s0`.`StringValue3`, `s`.`StringValue4`, `o`.`EntityOneId`, `o`.`Id`, `o`.`OwnedIntValue1`, `o`.`OwnedIntValue2`, `o`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `o`.`OwnedStringValue1`, `o`.`OwnedStringValue2`, `o`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `EntityOne` AS `e` +INNER JOIN `SplitEntityOnePart3` AS `s` ON `e`.`Id` = `s`.`Id` +INNER JOIN `SplitEntityOnePart2` AS `s0` ON `e`.`Id` = `s0`.`Id` +LEFT JOIN `OwnedCollection` AS `o` ON `e`.`Id` = `o`.`EntityOneId` +ORDER BY `e`.`Id`, `o`.`EntityOneId` +"""); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Split_entity_owning_a_split_reference_without_table_sharing(bool async) + { + await base.Split_entity_owning_a_split_reference_without_table_sharing(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Split_entity_owning_a_split_collection(bool async) + { + await base.Split_entity_owning_a_split_collection(async); + + AssertSql(); + } + + public override async Task Split_entity_owning_a_split_reference_with_table_sharing_1(bool async) + { + await base.Split_entity_owning_a_split_reference_with_table_sharing_1(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`EntityThreeId`, `s`.`IntValue1`, `s`.`IntValue2`, `s1`.`IntValue3`, `s0`.`IntValue4`, `s`.`StringValue1`, `s`.`StringValue2`, `s1`.`StringValue3`, `s0`.`StringValue4`, `s`.`OwnedReference_Id`, `s`.`OwnedReference_OwnedIntValue1`, `s`.`OwnedReference_OwnedIntValue2`, `s1`.`OwnedReference_OwnedIntValue3`, `s0`.`OwnedReference_OwnedIntValue4`, `s`.`OwnedReference_OwnedStringValue1`, `s`.`OwnedReference_OwnedStringValue2`, `s1`.`OwnedReference_OwnedStringValue3`, `s0`.`OwnedReference_OwnedStringValue4` +FROM `SplitEntityOnePart1` AS `s` +INNER JOIN `SplitEntityOnePart3` AS `s0` ON `s`.`Id` = `s0`.`Id` +INNER JOIN `SplitEntityOnePart2` AS `s1` ON `s`.`Id` = `s1`.`Id` +"""); + } + + public override async Task Split_entity_owning_a_split_reference_with_table_sharing_4(bool async) + { + await base.Split_entity_owning_a_split_reference_with_table_sharing_4(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`EntityThreeId`, `s`.`IntValue1`, `s`.`IntValue2`, `s1`.`IntValue3`, `s0`.`IntValue4`, `s`.`StringValue1`, `s`.`StringValue2`, `s1`.`StringValue3`, `s0`.`StringValue4`, `s`.`OwnedReference_Id`, `s`.`OwnedReference_OwnedIntValue1`, `s`.`OwnedReference_OwnedIntValue2`, `s1`.`OwnedReference_OwnedIntValue3`, `o`.`OwnedIntValue4`, `s`.`OwnedReference_OwnedStringValue1`, `s`.`OwnedReference_OwnedStringValue2`, `s1`.`OwnedReference_OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `SplitEntityOnePart1` AS `s` +INNER JOIN `SplitEntityOnePart3` AS `s0` ON `s`.`Id` = `s0`.`Id` +INNER JOIN `SplitEntityOnePart2` AS `s1` ON `s`.`Id` = `s1`.`Id` +LEFT JOIN `OwnedReferencePart3` AS `o` ON `s`.`Id` = `o`.`EntityOneId` +"""); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Split_entity_owning_a_split_reference_with_table_sharing_6(bool async) + { + await base.Split_entity_owning_a_split_reference_with_table_sharing_6(async); + + AssertSql( +""" +SELECT s."Id", s."EntityThreeId", s."IntValue1", s."IntValue2", s1."IntValue3", s0."IntValue4", s."StringValue1", s."StringValue2", s1."StringValue3", s0."StringValue4", s1."Id", s1."OwnedReference_Id", s1."OwnedReference_OwnedIntValue1", s1."OwnedReference_OwnedIntValue2", o0."OwnedIntValue3", o."OwnedIntValue4", s1."OwnedReference_OwnedStringValue1", s1."OwnedReference_OwnedStringValue2", o0."OwnedStringValue3", o."OwnedStringValue4" +FROM "SplitEntityOnePart1" AS s +INNER JOIN "SplitEntityOnePart3" AS s0 ON s."Id" = s0."Id" +INNER JOIN "SplitEntityOnePart2" AS s1 ON s."Id" = s1."Id" +LEFT JOIN "OwnedReferencePart3" AS o ON s1."Id" = o."EntityOneId" +LEFT JOIN "OwnedReferencePart2" AS o0 ON s1."Id" = o0."EntityOneId" +"""); + } + + public override async Task Tph_entity_owning_a_split_reference_on_base_with_table_sharing(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_base_with_table_sharing(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `b`.`Discriminator`, `b`.`MiddleValue`, `b`.`SiblingValue`, `b`.`LeafValue`, `b`.`OwnedReference_Id`, `b`.`OwnedReference_OwnedIntValue1`, `b`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `b`.`OwnedReference_OwnedStringValue1`, `b`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `BaseEntity` AS `b` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `b`.`Id` = `o`.`BaseEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `b`.`Id` = `o0`.`BaseEntityId` +"""); + } + + public override async Task Tpt_entity_owning_a_split_reference_on_base_with_table_sharing(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_base_with_table_sharing(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `m`.`MiddleValue`, `s`.`SiblingValue`, `l`.`LeafValue`, CASE + WHEN `l`.`Id` IS NOT NULL THEN 'LeafEntity' + WHEN `s`.`Id` IS NOT NULL THEN 'SiblingEntity' + WHEN `m`.`Id` IS NOT NULL THEN 'MiddleEntity' +END AS `Discriminator`, `b`.`OwnedReference_Id`, `b`.`OwnedReference_OwnedIntValue1`, `b`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `b`.`OwnedReference_OwnedStringValue1`, `b`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `BaseEntity` AS `b` +LEFT JOIN `MiddleEntity` AS `m` ON `b`.`Id` = `m`.`Id` +LEFT JOIN `SiblingEntity` AS `s` ON `b`.`Id` = `s`.`Id` +LEFT JOIN `LeafEntity` AS `l` ON `b`.`Id` = `l`.`Id` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `b`.`Id` = `o`.`BaseEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `b`.`Id` = `o0`.`BaseEntityId` +"""); + } + + public override async Task Tph_entity_owning_a_split_reference_on_middle_with_table_sharing(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_middle_with_table_sharing(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `b`.`Discriminator`, `b`.`MiddleValue`, `b`.`SiblingValue`, `b`.`LeafValue`, `b`.`OwnedReference_Id`, `b`.`OwnedReference_OwnedIntValue1`, `b`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `b`.`OwnedReference_OwnedStringValue1`, `b`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `BaseEntity` AS `b` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `b`.`Id` = `o`.`MiddleEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `b`.`Id` = `o0`.`MiddleEntityId` +"""); + } + + public override async Task Tpt_entity_owning_a_split_reference_on_middle_with_table_sharing(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_middle_with_table_sharing(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `m`.`MiddleValue`, `s`.`SiblingValue`, `l`.`LeafValue`, CASE + WHEN `l`.`Id` IS NOT NULL THEN 'LeafEntity' + WHEN `s`.`Id` IS NOT NULL THEN 'SiblingEntity' + WHEN `m`.`Id` IS NOT NULL THEN 'MiddleEntity' +END AS `Discriminator`, `m`.`Id`, `m`.`OwnedReference_Id`, `m`.`OwnedReference_OwnedIntValue1`, `m`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `m`.`OwnedReference_OwnedStringValue1`, `m`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `BaseEntity` AS `b` +LEFT JOIN `MiddleEntity` AS `m` ON `b`.`Id` = `m`.`Id` +LEFT JOIN `SiblingEntity` AS `s` ON `b`.`Id` = `s`.`Id` +LEFT JOIN `LeafEntity` AS `l` ON `b`.`Id` = `l`.`Id` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `m`.`Id` = `o`.`MiddleEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `m`.`Id` = `o0`.`MiddleEntityId` +"""); + } + + public override async Task Tph_entity_owning_a_split_reference_on_leaf_with_table_sharing(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_leaf_with_table_sharing(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `b`.`Discriminator`, `b`.`MiddleValue`, `b`.`SiblingValue`, `b`.`LeafValue`, `b`.`OwnedReference_Id`, `b`.`OwnedReference_OwnedIntValue1`, `b`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `b`.`OwnedReference_OwnedStringValue1`, `b`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `BaseEntity` AS `b` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `b`.`Id` = `o`.`LeafEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `b`.`Id` = `o0`.`LeafEntityId` +"""); + } + + public override async Task Tpt_entity_owning_a_split_reference_on_leaf_with_table_sharing(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_leaf_with_table_sharing(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `m`.`MiddleValue`, `s`.`SiblingValue`, `l`.`LeafValue`, CASE + WHEN `l`.`Id` IS NOT NULL THEN 'LeafEntity' + WHEN `s`.`Id` IS NOT NULL THEN 'SiblingEntity' + WHEN `m`.`Id` IS NOT NULL THEN 'MiddleEntity' +END AS `Discriminator`, `l`.`Id`, `l`.`OwnedReference_Id`, `l`.`OwnedReference_OwnedIntValue1`, `l`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `l`.`OwnedReference_OwnedStringValue1`, `l`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `BaseEntity` AS `b` +LEFT JOIN `MiddleEntity` AS `m` ON `b`.`Id` = `m`.`Id` +LEFT JOIN `SiblingEntity` AS `s` ON `b`.`Id` = `s`.`Id` +LEFT JOIN `LeafEntity` AS `l` ON `b`.`Id` = `l`.`Id` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `l`.`Id` = `o`.`LeafEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `l`.`Id` = `o0`.`LeafEntityId` +"""); + } + + public override async Task Tpc_entity_owning_a_split_reference_on_leaf_with_table_sharing(bool async) + { + await base.Tpc_entity_owning_a_split_reference_on_leaf_with_table_sharing(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseValue`, `t`.`MiddleValue`, `t`.`SiblingValue`, `t`.`LeafValue`, `t`.`Discriminator`, `l`.`Id`, `l`.`OwnedReference_Id`, `l`.`OwnedReference_OwnedIntValue1`, `l`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `l`.`OwnedReference_OwnedStringValue1`, `l`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM ( + SELECT `b`.`Id`, `b`.`BaseValue`, NULL AS `MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'BaseEntity' AS `Discriminator` + FROM `BaseEntity` AS `b` + UNION ALL + SELECT `m`.`Id`, `m`.`BaseValue`, `m`.`MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'MiddleEntity' AS `Discriminator` + FROM `MiddleEntity` AS `m` + UNION ALL + SELECT `s`.`Id`, `s`.`BaseValue`, NULL AS `MiddleValue`, `s`.`SiblingValue`, NULL AS `LeafValue`, 'SiblingEntity' AS `Discriminator` + FROM `SiblingEntity` AS `s` + UNION ALL + SELECT `l0`.`Id`, `l0`.`BaseValue`, `l0`.`MiddleValue`, NULL AS `SiblingValue`, `l0`.`LeafValue`, 'LeafEntity' AS `Discriminator` + FROM `LeafEntity` AS `l0` +) AS `t` +LEFT JOIN `LeafEntity` AS `l` ON `t`.`Id` = `l`.`Id` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `l`.`Id` = `o`.`LeafEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `l`.`Id` = `o0`.`LeafEntityId` +"""); + } + + public override async Task Tph_entity_owning_a_split_reference_on_base_with_table_sharing_querying_sibling(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_base_with_table_sharing_querying_sibling(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `b`.`Discriminator`, `b`.`SiblingValue`, `b`.`OwnedReference_Id`, `b`.`OwnedReference_OwnedIntValue1`, `b`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `b`.`OwnedReference_OwnedStringValue1`, `b`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `BaseEntity` AS `b` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `b`.`Id` = `o`.`BaseEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `b`.`Id` = `o0`.`BaseEntityId` +WHERE `b`.`Discriminator` = 'SiblingEntity' +"""); + } + + public override async Task Tpt_entity_owning_a_split_reference_on_base_with_table_sharing_querying_sibling(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_base_with_table_sharing_querying_sibling(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `s`.`SiblingValue`, `b`.`OwnedReference_Id`, `b`.`OwnedReference_OwnedIntValue1`, `b`.`OwnedReference_OwnedIntValue2`, `o0`.`OwnedIntValue3`, `o`.`OwnedIntValue4`, `b`.`OwnedReference_OwnedStringValue1`, `b`.`OwnedReference_OwnedStringValue2`, `o0`.`OwnedStringValue3`, `o`.`OwnedStringValue4` +FROM `BaseEntity` AS `b` +INNER JOIN `SiblingEntity` AS `s` ON `b`.`Id` = `s`.`Id` +LEFT JOIN `OwnedReferencePart4` AS `o` ON `b`.`Id` = `o`.`BaseEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o0` ON `b`.`Id` = `o0`.`BaseEntityId` +"""); + } + + public override async Task Tph_entity_owning_a_split_reference_on_middle_with_table_sharing_querying_sibling(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_middle_with_table_sharing_querying_sibling(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `b`.`Discriminator`, `b`.`SiblingValue` +FROM `BaseEntity` AS `b` +WHERE `b`.`Discriminator` = 'SiblingEntity' +"""); + } + + public override async Task Tpt_entity_owning_a_split_reference_on_middle_with_table_sharing_querying_sibling(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_middle_with_table_sharing_querying_sibling(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `s`.`SiblingValue` +FROM `BaseEntity` AS `b` +INNER JOIN `SiblingEntity` AS `s` ON `b`.`Id` = `s`.`Id` +"""); + } + + public override async Task Tph_entity_owning_a_split_reference_on_leaf_with_table_sharing_querying_sibling(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_leaf_with_table_sharing_querying_sibling(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `b`.`Discriminator`, `b`.`SiblingValue` +FROM `BaseEntity` AS `b` +WHERE `b`.`Discriminator` = 'SiblingEntity' +"""); + } + + public override async Task Tpt_entity_owning_a_split_reference_on_leaf_with_table_sharing_querying_sibling(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_leaf_with_table_sharing_querying_sibling(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`BaseValue`, `s`.`SiblingValue` +FROM `BaseEntity` AS `b` +INNER JOIN `SiblingEntity` AS `s` ON `b`.`Id` = `s`.`Id` +"""); + } + + public override async Task Tpc_entity_owning_a_split_reference_on_leaf_with_table_sharing_querying_sibling(bool async) + { + await base.Tpc_entity_owning_a_split_reference_on_leaf_with_table_sharing_querying_sibling(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`BaseValue`, `s`.`SiblingValue` +FROM `SiblingEntity` AS `s` +"""); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tph_entity_owning_a_split_reference_on_base_without_table_sharing(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_base_without_table_sharing(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tpt_entity_owning_a_split_reference_on_base_without_table_sharing(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_base_without_table_sharing(async); + + AssertSql(); + } + + public override async Task Tpc_entity_owning_a_split_reference_on_base_without_table_sharing(bool async) + { + await base.Tpc_entity_owning_a_split_reference_on_base_without_table_sharing(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseValue`, `t`.`MiddleValue`, `t`.`SiblingValue`, `t`.`LeafValue`, `t`.`Discriminator`, `o`.`BaseEntityId`, `o`.`Id`, `o`.`OwnedIntValue1`, `o`.`OwnedIntValue2`, `o1`.`OwnedIntValue3`, `o0`.`OwnedIntValue4`, `o`.`OwnedStringValue1`, `o`.`OwnedStringValue2`, `o1`.`OwnedStringValue3`, `o0`.`OwnedStringValue4` +FROM ( + SELECT `b`.`Id`, `b`.`BaseValue`, NULL AS `MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'BaseEntity' AS `Discriminator` + FROM `BaseEntity` AS `b` + UNION ALL + SELECT `m`.`Id`, `m`.`BaseValue`, `m`.`MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'MiddleEntity' AS `Discriminator` + FROM `MiddleEntity` AS `m` + UNION ALL + SELECT `s`.`Id`, `s`.`BaseValue`, NULL AS `MiddleValue`, `s`.`SiblingValue`, NULL AS `LeafValue`, 'SiblingEntity' AS `Discriminator` + FROM `SiblingEntity` AS `s` + UNION ALL + SELECT `l`.`Id`, `l`.`BaseValue`, `l`.`MiddleValue`, NULL AS `SiblingValue`, `l`.`LeafValue`, 'LeafEntity' AS `Discriminator` + FROM `LeafEntity` AS `l` +) AS `t` +LEFT JOIN `OwnedReferencePart1` AS `o` ON `t`.`Id` = `o`.`BaseEntityId` +LEFT JOIN `OwnedReferencePart4` AS `o0` ON `o`.`BaseEntityId` = `o0`.`BaseEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o1` ON `o`.`BaseEntityId` = `o1`.`BaseEntityId` +"""); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tph_entity_owning_a_split_reference_on_middle_without_table_sharing(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_middle_without_table_sharing(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tpt_entity_owning_a_split_reference_on_middle_without_table_sharing(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_middle_without_table_sharing(async); + + AssertSql(); + } + + public override async Task Tpc_entity_owning_a_split_reference_on_middle_without_table_sharing(bool async) + { + await base.Tpc_entity_owning_a_split_reference_on_middle_without_table_sharing(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseValue`, `t`.`MiddleValue`, `t`.`SiblingValue`, `t`.`LeafValue`, `t`.`Discriminator`, `o`.`MiddleEntityId`, `o`.`Id`, `o`.`OwnedIntValue1`, `o`.`OwnedIntValue2`, `o1`.`OwnedIntValue3`, `o0`.`OwnedIntValue4`, `o`.`OwnedStringValue1`, `o`.`OwnedStringValue2`, `o1`.`OwnedStringValue3`, `o0`.`OwnedStringValue4` +FROM ( + SELECT `b`.`Id`, `b`.`BaseValue`, NULL AS `MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'BaseEntity' AS `Discriminator` + FROM `BaseEntity` AS `b` + UNION ALL + SELECT `m`.`Id`, `m`.`BaseValue`, `m`.`MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'MiddleEntity' AS `Discriminator` + FROM `MiddleEntity` AS `m` + UNION ALL + SELECT `s`.`Id`, `s`.`BaseValue`, NULL AS `MiddleValue`, `s`.`SiblingValue`, NULL AS `LeafValue`, 'SiblingEntity' AS `Discriminator` + FROM `SiblingEntity` AS `s` + UNION ALL + SELECT `l`.`Id`, `l`.`BaseValue`, `l`.`MiddleValue`, NULL AS `SiblingValue`, `l`.`LeafValue`, 'LeafEntity' AS `Discriminator` + FROM `LeafEntity` AS `l` +) AS `t` +LEFT JOIN `OwnedReferencePart1` AS `o` ON `t`.`Id` = `o`.`MiddleEntityId` +LEFT JOIN `OwnedReferencePart4` AS `o0` ON `o`.`MiddleEntityId` = `o0`.`MiddleEntityId` +LEFT JOIN `OwnedReferencePart3` AS `o1` ON `o`.`MiddleEntityId` = `o1`.`MiddleEntityId` +"""); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tph_entity_owning_a_split_reference_on_leaf_without_table_sharing(bool async) + { + await base.Tph_entity_owning_a_split_reference_on_leaf_without_table_sharing(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tpt_entity_owning_a_split_reference_on_leaf_without_table_sharing(bool async) + { + await base.Tpt_entity_owning_a_split_reference_on_leaf_without_table_sharing(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tpc_entity_owning_a_split_reference_on_leaf_without_table_sharing(bool async) + { + await base.Tpc_entity_owning_a_split_reference_on_leaf_without_table_sharing(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tph_entity_owning_a_split_collection_on_base(bool async) + { + await base.Tph_entity_owning_a_split_collection_on_base(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tpt_entity_owning_a_split_collection_on_base(bool async) + { + await base.Tpt_entity_owning_a_split_collection_on_base(async); + + AssertSql(); + } + + public override async Task Tpc_entity_owning_a_split_collection_on_base(bool async) + { + await base.Tpc_entity_owning_a_split_collection_on_base(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseValue`, `t`.`MiddleValue`, `t`.`SiblingValue`, `t`.`LeafValue`, `t`.`Discriminator`, `t0`.`BaseEntityId`, `t0`.`Id`, `t0`.`OwnedIntValue1`, `t0`.`OwnedIntValue2`, `t0`.`OwnedIntValue3`, `t0`.`OwnedIntValue4`, `t0`.`OwnedStringValue1`, `t0`.`OwnedStringValue2`, `t0`.`OwnedStringValue3`, `t0`.`OwnedStringValue4` +FROM ( + SELECT `b`.`Id`, `b`.`BaseValue`, NULL AS `MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'BaseEntity' AS `Discriminator` + FROM `BaseEntity` AS `b` + UNION ALL + SELECT `m`.`Id`, `m`.`BaseValue`, `m`.`MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'MiddleEntity' AS `Discriminator` + FROM `MiddleEntity` AS `m` + UNION ALL + SELECT `s`.`Id`, `s`.`BaseValue`, NULL AS `MiddleValue`, `s`.`SiblingValue`, NULL AS `LeafValue`, 'SiblingEntity' AS `Discriminator` + FROM `SiblingEntity` AS `s` + UNION ALL + SELECT `l`.`Id`, `l`.`BaseValue`, `l`.`MiddleValue`, NULL AS `SiblingValue`, `l`.`LeafValue`, 'LeafEntity' AS `Discriminator` + FROM `LeafEntity` AS `l` +) AS `t` +LEFT JOIN ( + SELECT `o`.`BaseEntityId`, `o`.`Id`, `o`.`OwnedIntValue1`, `o`.`OwnedIntValue2`, `o1`.`OwnedIntValue3`, `o0`.`OwnedIntValue4`, `o`.`OwnedStringValue1`, `o`.`OwnedStringValue2`, `o1`.`OwnedStringValue3`, `o0`.`OwnedStringValue4` + FROM `OwnedReferencePart1` AS `o` + INNER JOIN `OwnedReferencePart4` AS `o0` ON (`o`.`BaseEntityId` = `o0`.`BaseEntityId`) AND (`o`.`Id` = `o0`.`Id`) + INNER JOIN `OwnedReferencePart3` AS `o1` ON (`o`.`BaseEntityId` = `o1`.`BaseEntityId`) AND (`o`.`Id` = `o1`.`Id`) +) AS `t0` ON `t`.`Id` = `t0`.`BaseEntityId` +ORDER BY `t`.`Id`, `t0`.`BaseEntityId` +"""); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tph_entity_owning_a_split_collection_on_middle(bool async) + { + await base.Tph_entity_owning_a_split_collection_on_middle(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tpt_entity_owning_a_split_collection_on_middle(bool async) + { + await base.Tpt_entity_owning_a_split_collection_on_middle(async); + + AssertSql(); + } + + public override async Task Tpc_entity_owning_a_split_collection_on_middle(bool async) + { + await base.Tpc_entity_owning_a_split_collection_on_middle(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseValue`, `t`.`MiddleValue`, `t`.`SiblingValue`, `t`.`LeafValue`, `t`.`Discriminator`, `t0`.`MiddleEntityId`, `t0`.`Id`, `t0`.`OwnedIntValue1`, `t0`.`OwnedIntValue2`, `t0`.`OwnedIntValue3`, `t0`.`OwnedIntValue4`, `t0`.`OwnedStringValue1`, `t0`.`OwnedStringValue2`, `t0`.`OwnedStringValue3`, `t0`.`OwnedStringValue4` +FROM ( + SELECT `b`.`Id`, `b`.`BaseValue`, NULL AS `MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'BaseEntity' AS `Discriminator` + FROM `BaseEntity` AS `b` + UNION ALL + SELECT `m`.`Id`, `m`.`BaseValue`, `m`.`MiddleValue`, NULL AS `SiblingValue`, NULL AS `LeafValue`, 'MiddleEntity' AS `Discriminator` + FROM `MiddleEntity` AS `m` + UNION ALL + SELECT `s`.`Id`, `s`.`BaseValue`, NULL AS `MiddleValue`, `s`.`SiblingValue`, NULL AS `LeafValue`, 'SiblingEntity' AS `Discriminator` + FROM `SiblingEntity` AS `s` + UNION ALL + SELECT `l`.`Id`, `l`.`BaseValue`, `l`.`MiddleValue`, NULL AS `SiblingValue`, `l`.`LeafValue`, 'LeafEntity' AS `Discriminator` + FROM `LeafEntity` AS `l` +) AS `t` +LEFT JOIN ( + SELECT `o`.`MiddleEntityId`, `o`.`Id`, `o`.`OwnedIntValue1`, `o`.`OwnedIntValue2`, `o1`.`OwnedIntValue3`, `o0`.`OwnedIntValue4`, `o`.`OwnedStringValue1`, `o`.`OwnedStringValue2`, `o1`.`OwnedStringValue3`, `o0`.`OwnedStringValue4` + FROM `OwnedReferencePart1` AS `o` + INNER JOIN `OwnedReferencePart4` AS `o0` ON (`o`.`MiddleEntityId` = `o0`.`MiddleEntityId`) AND (`o`.`Id` = `o0`.`Id`) + INNER JOIN `OwnedReferencePart3` AS `o1` ON (`o`.`MiddleEntityId` = `o1`.`MiddleEntityId`) AND (`o`.`Id` = `o1`.`Id`) +) AS `t0` ON `t`.`Id` = `t0`.`MiddleEntityId` +ORDER BY `t`.`Id`, `t0`.`MiddleEntityId` +"""); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tph_entity_owning_a_split_collection_on_leaf(bool async) + { + await base.Tph_entity_owning_a_split_collection_on_leaf(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tpt_entity_owning_a_split_collection_on_leaf(bool async) + { + await base.Tpt_entity_owning_a_split_collection_on_leaf(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Issue29075")] + public override async Task Tpc_entity_owning_a_split_collection_on_leaf(bool async) + { + await base.Tpc_entity_owning_a_split_collection_on_leaf(async); + + AssertSql(); + } + + protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlNoBackslashesTest.cs b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlNoBackslashesTest.cs index 6e6f5f0a7..1fe0e3da1 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlNoBackslashesTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlNoBackslashesTest.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Tests; using Xunit; using Xunit.Abstractions; @@ -19,18 +20,34 @@ public override void Input_query_escapes_parameter() { base.Input_query_escapes_parameter(); - AssertSql( - @"@p0='Back\slash's Garden Party' (Nullable = false) (Size = 4000) + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + @"@p0='Back\slash's Garden Party' (Nullable = false) (Size = 4000) + +INSERT INTO `Artists` (`Name`) +VALUES (@p0) +RETURNING `ArtistId`;", + // + @"SELECT `a`.`ArtistId`, `a`.`Name` +FROM `Artists` AS `a` +WHERE `a`.`Name` LIKE '% Garden Party'"); + } + else + { + AssertSql( + @"@p0='Back\slash's Garden Party' (Nullable = false) (Size = 4000) INSERT INTO `Artists` (`Name`) VALUES (@p0); SELECT `ArtistId` FROM `Artists` WHERE ROW_COUNT() = 1 AND `ArtistId` = LAST_INSERT_ID();", - // - @"SELECT `a`.`ArtistId`, `a`.`Name` + // + @"SELECT `a`.`ArtistId`, `a`.`Name` FROM `Artists` AS `a` WHERE `a`.`Name` LIKE '% Garden Party'"); + } } [ConditionalTheory] diff --git a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTest.cs index de60a41c8..20792a5d2 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTest.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Tests; using Xunit; using Xunit.Abstractions; @@ -19,18 +20,34 @@ public override void Input_query_escapes_parameter() { base.Input_query_escapes_parameter(); - AssertSql( - @"@p0='Back\slash's Garden Party' (Nullable = false) (Size = 4000) + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + @"@p0='Back\slash's Garden Party' (Nullable = false) (Size = 4000) + +INSERT INTO `Artists` (`Name`) +VALUES (@p0) +RETURNING `ArtistId`;", + // + @"SELECT `a`.`ArtistId`, `a`.`Name` +FROM `Artists` AS `a` +WHERE `a`.`Name` LIKE '% Garden Party'"); + } + else + { + AssertSql( + @"@p0='Back\slash's Garden Party' (Nullable = false) (Size = 4000) INSERT INTO `Artists` (`Name`) VALUES (@p0); SELECT `ArtistId` FROM `Artists` WHERE ROW_COUNT() = 1 AND `ArtistId` = LAST_INSERT_ID();", - // - @"SELECT `a`.`ArtistId`, `a`.`Name` + // + @"SELECT `a`.`ArtistId`, `a`.`Name` FROM `Artists` AS `a` WHERE `a`.`Name` LIKE '% Garden Party'"); + } } [ConditionalTheory] diff --git a/test/EFCore.MySql.FunctionalTests/Query/FromSqlQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/FromSqlQueryMySqlTest.cs index ec3ddc030..9db9490d8 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/FromSqlQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/FromSqlQueryMySqlTest.cs @@ -3,6 +3,8 @@ using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; using MySqlConnector; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure; +using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; using Xunit; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query @@ -14,6 +16,12 @@ public FromSqlQueryMySqlTest(NorthwindQueryMySqlFixture fix { } + [SupportedServerVersionCondition(nameof(ServerVersionSupport.CommonTableExpressions))] + public override Task FromSqlRaw_composed_with_common_table_expression(bool async) + { + return base.FromSqlRaw_composed_with_common_table_expression(async); + } + protected override DbParameter CreateDbParameter(string name, object value) => new MySqlParameter { diff --git a/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlFixture.cs index cd91b79aa..adfdef379 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlFixture.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlFixture.cs @@ -1,4 +1,3 @@ -using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; @@ -35,22 +34,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con foreach (var mission in data.Missions) { - mission.Timeline = GetExpectedValue(mission.Timeline); + mission.Timeline = MySqlTestHelpers.GetExpectedValue(mission.Timeline); } return data; } - - public static DateTimeOffset GetExpectedValue(DateTimeOffset value) - { - const int mySqlMaxMillisecondDecimalPlaces = 6; - var decimalPlacesFactor = (decimal)Math.Pow(10, 7 - mySqlMaxMillisecondDecimalPlaces); - - // Change DateTimeOffset values, because MySQL does not preserve offsets and has a maximum of 6 decimal places, in contrast to - // .NET which has 7. - return new DateTimeOffset( - (long)(Math.Truncate(value.UtcTicks / decimalPlacesFactor) * decimalPlacesFactor), - TimeSpan.Zero); - } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs index 13ee566a0..046e59943 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; using Xunit; @@ -25,7 +26,7 @@ protected override bool CanExecuteQueryString public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool async) { - var dto = GearsOfWarQueryMySqlFixture.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); + var dto = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); var start = dto.AddDays(-1); var end = dto.AddDays(1); var dates = new[] { dto }; @@ -38,7 +39,7 @@ public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool async) public override Task Where_datetimeoffset_milliseconds_parameter_and_constant(bool async) { - var dateTimeOffset = GearsOfWarQueryMySqlFixture.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); + var dateTimeOffset = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); // Literal where clause var p = Expression.Parameter(typeof(Mission), "i"); @@ -54,6 +55,25 @@ public override Task Where_datetimeoffset_milliseconds_parameter_and_constant(bo ss => ss.Set().Where(m => m.Timeline == dateTimeOffset)); } + [ConditionalTheory(Skip = "TODO: Does not work as expected, probably due to some test definition issues.")] + public override async Task DateTimeOffsetNow_minus_timespan(bool async) + { + var timeSpan = new TimeSpan(10000); // <-- changed from 1000 to 10000 ticks + + await AssertQuery( + async, + ss => ss.Set().Where(e => e.Timeline > DateTimeOffset.Now - timeSpan)); + + AssertSql( +""" +@__timeSpan_0='00:00:00.0010000' (DbType = DateTimeOffset) + +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE `m`.`Timeline` > (UTC_TIMESTAMP() - @__timeSpan_0) +"""); + } + // TODO: Implement strategy as discussed with @roji (including emails) for EF Core 5. [ConditionalTheory(Skip = "#996")] public override Task Client_member_and_unsupported_string_Equals_in_the_same_query(bool async) @@ -210,5 +230,12 @@ public override Task Subquery_projecting_non_nullable_scalar_contains_non_nullab { return base.Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion(async); } + + [ConditionalTheory(Skip = "Another LATERAL JOIN bug in MySQL. Grouping leads to unexpected result set.")] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(bool async) + { + return base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); + } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/MatchQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/MatchQueryMySqlTest.cs index 657f64344..78f9b2e57 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/MatchQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/MatchQueryMySqlTest.cs @@ -320,13 +320,11 @@ public Func GetContextCreator() public ISetSource GetExpectedData() => new MatchQueryData(); - public IReadOnlyDictionary GetEntitySorters() - => new Dictionary> - { - { typeof(Herb), e => ((Herb)e)?.Id }, - }.ToDictionary(e => e.Key, e => (object)e.Value); + public IReadOnlyDictionary EntitySorters + => new Dictionary> { { typeof(Herb), e => ((Herb)e)?.Id }, }.ToDictionary(e => e.Key, + e => (object)e.Value); - public IReadOnlyDictionary GetEntityAsserters() + public IReadOnlyDictionary EntityAsserters => new Dictionary> { { diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindAggregateOperatorsQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindAggregateOperatorsQueryMySqlTest.cs index 0ebd1a124..6ec051935 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindAggregateOperatorsQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindAggregateOperatorsQueryMySqlTest.cs @@ -1,5 +1,9 @@ -using Microsoft.EntityFrameworkCore.Query; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; using Xunit.Abstractions; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query @@ -16,6 +20,31 @@ public NorthwindAggregateOperatorsQueryMySqlTest( //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + public override Task Average_over_max_subquery_is_client_eval(bool async) + => AssertAverage( + async, + ss => ss.Set().OrderBy(c => c.CustomerID).Take(3), + selector: c => (decimal)c.Orders.Average(o => 5 + o.OrderDetails.Max(od => od.ProductID)), + asserter: (a, b) => Assert.Equal(a, b, 12)); // added flouting point precision tolerance + + public override Task Average_over_nested_subquery_is_client_eval(bool async) + => AssertAverage( + async, + ss => ss.Set().OrderBy(c => c.CustomerID).Take(3), + selector: c => (decimal)c.Orders.Average(o => 5 + o.OrderDetails.Average(od => od.ProductID)), + asserter: (a, b) => Assert.Equal(a, b, 12)); // added flouting point precision tolerance + + public override async Task Contains_with_local_anonymous_type_array_closure(bool async) + { + // Aggregates. Issue #15937. + await AssertTranslationFailed(() => base.Contains_with_local_anonymous_type_array_closure(async)); + + AssertSql(); + } + + public override async Task Contains_with_local_tuple_array_closure(bool async) + => await AssertTranslationFailed(() => base.Contains_with_local_tuple_array_closure(async)); + protected override bool CanExecuteQueryString => true; diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindAggregateQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindAggregateQueryMySqlTest.cs index d55d1e60e..28de881f9 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindAggregateQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindAggregateQueryMySqlTest.cs @@ -1,6 +1,10 @@ -using System.Threading.Tasks; +using System; +using System.Linq; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; using Xunit; using Xunit.Abstractions; @@ -18,7 +22,6 @@ public NorthwindAggregateQueryMySqlTest( //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } - [ConditionalTheory] public override async Task Sum_with_coalesce(bool async) { await base.Sum_with_coalesce(async); @@ -29,6 +32,69 @@ public override async Task Sum_with_coalesce(bool async) WHERE `p`.`ProductID` < 40"); } + public override async Task Average_over_max_subquery_is_client_eval(bool async) + { + await AssertAverage( + async, + ss => ss.Set().OrderBy(c => c.CustomerID).Take(3), + selector: c => (decimal)c.Orders.Average(o => 5 + o.OrderDetails.Max(od => od.ProductID)), + asserter: (a, b) => Assert.Equal(a, b, 12)); // added flouting point precision tolerance + + AssertSql( + $@"@__p_0='3' + +SELECT AVG(CAST(( + SELECT AVG({MySqlTestHelpers.CastAsDouble(@"5 + ( + SELECT MAX(`o0`.`ProductID`) + FROM `Order Details` AS `o0` + WHERE `o`.`OrderID` = `o0`.`OrderID`)")}) + FROM `Orders` AS `o` + WHERE `t`.`CustomerID` = `o`.`CustomerID`) AS decimal(65,30))) +FROM ( + SELECT `c`.`CustomerID` + FROM `Customers` AS `c` + ORDER BY `c`.`CustomerID` + LIMIT @__p_0 +) AS `t`"); + } + + public override async Task Average_over_nested_subquery_is_client_eval(bool async) + { + await AssertAverage( + async, + ss => ss.Set().OrderBy(c => c.CustomerID).Take(3), + selector: c => (decimal)c.Orders.Average(o => 5 + o.OrderDetails.Average(od => od.ProductID)), + asserter: (a, b) => Assert.Equal(a, b, 12)); // added flouting point precision tolerance + + AssertSql( + $@"@__p_0='3' + +SELECT AVG(CAST(( + SELECT AVG(5.0 + ( + SELECT AVG({MySqlTestHelpers.CastAsDouble(@"`o0`.`ProductID`")}) + FROM `Order Details` AS `o0` + WHERE `o`.`OrderID` = `o0`.`OrderID`)) + FROM `Orders` AS `o` + WHERE `t`.`CustomerID` = `o`.`CustomerID`) AS decimal(65,30))) +FROM ( + SELECT `c`.`CustomerID` + FROM `Customers` AS `c` + ORDER BY `c`.`CustomerID` + LIMIT @__p_0 +) AS `t`"); + } + + public override async Task Contains_with_local_anonymous_type_array_closure(bool async) + { + // Aggregates. Issue #15937. + await AssertTranslationFailed(() => base.Contains_with_local_anonymous_type_array_closure(async)); + + AssertSql(); + } + + public override async Task Contains_with_local_tuple_array_closure(bool async) + => await AssertTranslationFailed(() => base.Contains_with_local_tuple_array_closure(async)); + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindEFPropertyIncludeQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindEFPropertyIncludeQueryMySqlTest.cs new file mode 100644 index 000000000..61e89c28a --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindEFPropertyIncludeQueryMySqlTest.cs @@ -0,0 +1,2297 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.Northwind; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class NorthwindEFPropertyIncludeQueryMySqlTest : NorthwindEFPropertyIncludeQueryTestBase< + NorthwindQueryMySqlFixture> +{ + // ReSharper disable once UnusedParameter.Local + public NorthwindEFPropertyIncludeQueryMySqlTest(NorthwindQueryMySqlFixture fixture) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Include_collection_with_last_no_orderby(bool async) + { + Assert.Equal( + RelationalStrings.LastUsedWithoutOrderBy(nameof(Enumerable.Last)), + (await Assert.ThrowsAsync( + () => base.Include_collection_with_last_no_orderby(async))).Message); + + AssertSql(); + } + + public override async Task Include_collection_with_filter_reordered(bool async) + { + await base.Include_collection_with_filter_reordered(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +WHERE `c`.`CustomerID` = 'ALFKI' +ORDER BY `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_order_by_non_key_with_first_or_default(bool async) + { + await base.Include_collection_order_by_non_key_with_first_or_default(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`CompanyName` DESC + LIMIT 1 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CompanyName` DESC, `t`.`CustomerID` +"""); + } + + public override async Task Include_with_cycle_does_not_throw_when_AsTracking_NoTrackingWithIdentityResolution(bool async) + { + await base.Include_with_cycle_does_not_throw_when_AsTracking_NoTrackingWithIdentityResolution(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `o`.`OrderID` < 10800 +ORDER BY `o`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_with_filter(bool async) + { + await base.Include_collection_with_filter(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +WHERE `c`.`CustomerID` = 'ALFKI' +ORDER BY `c`.`CustomerID` +"""); + } + + public override async Task Include_references_then_include_multi_level(bool async) + { + await base.Include_references_then_include_multi_level(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +WHERE (`o`.`OrderID` % 23) = 13 +"""); + } + + public override async Task Include_collection_order_by_collection_column(bool async) + { + await base.Include_collection_order_by_collection_column(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, ( + SELECT `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`OrderDate` DESC + LIMIT 1) AS `c` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'W%' + ORDER BY ( + SELECT `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`OrderDate` DESC + LIMIT 1) DESC + LIMIT 1 +) AS `t` +LEFT JOIN `Orders` AS `o0` ON `t`.`CustomerID` = `o0`.`CustomerID` +ORDER BY `t`.`c` DESC, `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_alias_generation(bool async) + { + await base.Include_collection_alias_generation(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` +FROM `Orders` AS `o` +LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE `o`.`CustomerID` IS NOT NULL AND (`o`.`CustomerID` LIKE 'F%') +ORDER BY `o`.`OrderID`, `o0`.`OrderID` +"""); + } + + public override async Task Include_collection_skip_take_no_order_by(bool async) + { + await base.Include_collection_skip_take_no_order_by(async); + + AssertSql( +""" +@__p_1='5' +@__p_0='10' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + LIMIT @__p_1 OFFSET @__p_0 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_with_cross_join_clause_with_filter(bool async) + { + await base.Include_collection_with_cross_join_clause_with_filter(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t`.`OrderID`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Customers` AS `c` +CROSS JOIN ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + ORDER BY `o`.`OrderID` + LIMIT 5 +) AS `t` +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `t`.`OrderID` +"""); + } + + public override async Task Join_Include_reference_GroupBy_Select(bool async) + { + await base.Join_Include_reference_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`CustomerID0`, `t0`.`Address`, `t0`.`City`, `t0`.`CompanyName`, `t0`.`ContactName`, `t0`.`ContactTitle`, `t0`.`Country`, `t0`.`Fax`, `t0`.`Phone`, `t0`.`PostalCode`, `t0`.`Region` +FROM ( + SELECT `o0`.`OrderID` + FROM `Order Details` AS `o` + INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` + GROUP BY `o0`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`CustomerID0`, `t1`.`Address`, `t1`.`City`, `t1`.`CompanyName`, `t1`.`ContactName`, `t1`.`ContactTitle`, `t1`.`Country`, `t1`.`Fax`, `t1`.`Phone`, `t1`.`PostalCode`, `t1`.`Region` + FROM ( + SELECT `o2`.`OrderID`, `o2`.`CustomerID`, `o2`.`EmployeeID`, `o2`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, ROW_NUMBER() OVER(PARTITION BY `o2`.`OrderID` ORDER BY `o2`.`OrderID`) AS `row` + FROM `Order Details` AS `o1` + INNER JOIN `Orders` AS `o2` ON `o1`.`OrderID` = `o2`.`OrderID` + LEFT JOIN `Customers` AS `c` ON `o2`.`CustomerID` = `c`.`CustomerID` + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +"""); + } + + public override async Task Include_multi_level_reference_and_collection_predicate(bool async) + { + await base.Include_multi_level_reference_and_collection_predicate(async); + + AssertSql( +""" +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `t`.`CustomerID0`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Orders` AS `o` + LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` + WHERE `o`.`OrderID` = 10248 + LIMIT 2 +) AS `t` +LEFT JOIN `Orders` AS `o0` ON `t`.`CustomerID0` = `o0`.`CustomerID` +ORDER BY `t`.`OrderID`, `t`.`CustomerID0` +"""); + } + + public override async Task Include_references_then_include_collection(bool async) + { + await base.Include_references_then_include_collection(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `o`.`CustomerID` IS NOT NULL AND (`o`.`CustomerID` LIKE 'F%') +ORDER BY `o`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_on_additional_from_clause_with_filter(bool async) + { + await base.Include_collection_on_additional_from_clause_with_filter(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `c`.`CustomerID`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Customers` AS `c` +CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` = 'ALFKI' +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `c`.`CustomerID`, `t`.`CustomerID` +"""); + } + + public override async Task Include_duplicate_reference3(bool async) + { + await base.Include_duplicate_reference3(async); + + AssertSql( +""" +@__p_0='2' + +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + ORDER BY `o`.`OrderID` + LIMIT @__p_0 +) AS `t` +CROSS JOIN ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + ORDER BY `o0`.`OrderID` + LIMIT 2 OFFSET 2 +) AS `t0` +LEFT JOIN `Customers` AS `c` ON `t0`.`CustomerID` = `c`.`CustomerID` +ORDER BY `t`.`OrderID` +"""); + } + + public override async Task Include_collection_order_by_non_key_with_take(bool async) + { + await base.Include_collection_order_by_non_key_with_take(async); + + AssertSql( +""" +@__p_0='10' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`ContactTitle` + LIMIT @__p_0 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`ContactTitle`, `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_then_include_collection_predicate(bool async) + { + await base.Include_collection_then_include_collection_predicate(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`OrderID0`, `t0`.`ProductID`, `t0`.`Discount`, `t0`.`Quantity`, `t0`.`UnitPrice` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` = 'ALFKI' + LIMIT 2 +) AS `t` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID` AS `OrderID0`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Orders` AS `o` + LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +) AS `t0` ON `t`.`CustomerID` = `t0`.`CustomerID` +ORDER BY `t`.`CustomerID`, `t0`.`OrderID`, `t0`.`OrderID0` +"""); + } + + public override async Task Include_collection_take_no_order_by(bool async) + { + await base.Include_collection_take_no_order_by(async); + + AssertSql( +""" +@__p_0='10' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + LIMIT @__p_0 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_principal_already_tracked(bool async) + { + await base.Include_collection_principal_already_tracked(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Customers` AS `c` +WHERE `c`.`CustomerID` = 'ALFKI' +LIMIT 2 +""", + // + """ +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` = 'ALFKI' + LIMIT 2 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_OrderBy_object(bool async) + { + await base.Include_collection_OrderBy_object(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` +FROM `Orders` AS `o` +LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE `o`.`OrderID` < 10250 +ORDER BY `o`.`OrderID`, `o0`.`OrderID` +"""); + } + + public override async Task Include_duplicate_collection_result_operator2(bool async) + { + // The order of `Orders` can be different, because it is not explicitly sorted. + // The order of the end result can be different as well. + // This is the case on MariaDB. + await AssertQuery( + async, + ss => (from c1 in ss.Set().Include(c => c.Orders).OrderBy(c => c.CustomerID).ThenBy(c => c.Orders.FirstOrDefault() != null ? c.Orders.FirstOrDefault().CustomerID : null).Take(2) + from c2 in ss.Set().OrderBy(c => c.CustomerID).Skip(2).Take(2) + select new { c1, c2 }).OrderBy(t => t.c1.CustomerID).ThenBy(t => t.c2.CustomerID).Take(1), + elementSorter: e => (e.c1.CustomerID, e.c2.CustomerID), + elementAsserter: (e, a) => + { + AssertInclude(e.c1, a.c1, new ExpectedInclude(c => c.Orders)); + AssertEqual(e.c2, a.c2); + }, + entryCount: 8); + + AssertSql( +""" +@__p_0='2' +@__p_1='1' + +SELECT `t1`.`CustomerID`, `t1`.`Address`, `t1`.`City`, `t1`.`CompanyName`, `t1`.`ContactName`, `t1`.`ContactTitle`, `t1`.`Country`, `t1`.`Fax`, `t1`.`Phone`, `t1`.`PostalCode`, `t1`.`Region`, `t1`.`CustomerID0`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `t1`.`Address0`, `t1`.`City0`, `t1`.`CompanyName0`, `t1`.`ContactName0`, `t1`.`ContactTitle0`, `t1`.`Country0`, `t1`.`Fax0`, `t1`.`Phone0`, `t1`.`PostalCode0`, `t1`.`Region0` +FROM ( + SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `t0`.`CustomerID` AS `CustomerID0`, `t0`.`Address` AS `Address0`, `t0`.`City` AS `City0`, `t0`.`CompanyName` AS `CompanyName0`, `t0`.`ContactName` AS `ContactName0`, `t0`.`ContactTitle` AS `ContactTitle0`, `t0`.`Country` AS `Country0`, `t0`.`Fax` AS `Fax0`, `t0`.`Phone` AS `Phone0`, `t0`.`PostalCode` AS `PostalCode0`, `t0`.`Region` AS `Region0` + FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`CustomerID`, ( + SELECT `o`.`CustomerID` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + LIMIT 1) + LIMIT @__p_0 + ) AS `t` + CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + ORDER BY `c0`.`CustomerID` + LIMIT 2 OFFSET 2 + ) AS `t0` + ORDER BY `t`.`CustomerID`, `t0`.`CustomerID` + LIMIT @__p_1 +) AS `t1` +LEFT JOIN `Orders` AS `o0` ON `t1`.`CustomerID` = `o0`.`CustomerID` +ORDER BY `t1`.`CustomerID`, `t1`.`CustomerID0` +"""); + } + + public override async Task Repro9735(bool async) + { + await AssertQuery( + async, + ss => ss.Set() + .Include(b => b.OrderDetails) + .OrderBy(b => b.Customer.CustomerID != null) + .ThenBy(b => b.Customer != null ? b.Customer.CustomerID : string.Empty) + .ThenBy(b => b.EmployeeID) // Needs to be explicitly ordered by EmployeeID as well + .Take(2), + entryCount: 6); + + AssertSql( +""" +@__p_0='2' + +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `t`.`CustomerID0`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` +FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `c`.`CustomerID` IS NOT NULL AS `c`, CASE + WHEN `c`.`CustomerID` IS NOT NULL THEN `c`.`CustomerID` + ELSE '' + END AS `c0` + FROM `Orders` AS `o` + LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` + ORDER BY `c`.`CustomerID` IS NOT NULL, CASE + WHEN `c`.`CustomerID` IS NOT NULL THEN `c`.`CustomerID` + ELSE '' + END, `o`.`EmployeeID` + LIMIT @__p_0 +) AS `t` +LEFT JOIN `Order Details` AS `o0` ON `t`.`OrderID` = `o0`.`OrderID` +ORDER BY `t`.`c`, `t`.`c0`, `t`.`EmployeeID`, `t`.`OrderID`, `t`.`CustomerID0`, `o0`.`OrderID` +"""); + } + + public override async Task Include_collection_single_or_default_no_result(bool async) + { + await base.Include_collection_single_or_default_no_result(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` = 'ALFKI ?' + LIMIT 2 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_with_cross_apply_with_filter(bool async) + { + await base.Include_collection_with_cross_apply_with_filter(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t`.`OrderID`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Customers` AS `c` +JOIN LATERAL ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + WHERE `o`.`CustomerID` = `c`.`CustomerID` + ORDER BY `c`.`CustomerID` + LIMIT 5 +) AS `t` ON TRUE +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `t`.`OrderID` +"""); + } + + public override async Task Include_collection_with_left_join_clause_with_filter(bool async) + { + await base.Include_collection_with_left_join_clause_with_filter(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `o`.`OrderID` +"""); + } + + public override async Task Include_duplicate_collection(bool async) + { + await base.Include_duplicate_collection(async); + + AssertSql( +""" +@__p_0='2' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `t0`.`CustomerID`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `t0`.`Address`, `t0`.`City`, `t0`.`CompanyName`, `t0`.`ContactName`, `t0`.`ContactTitle`, `t0`.`Country`, `t0`.`Fax`, `t0`.`Phone`, `t0`.`PostalCode`, `t0`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`CustomerID` + LIMIT @__p_0 +) AS `t` +CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + ORDER BY `c0`.`CustomerID` + LIMIT 2 OFFSET 2 +) AS `t0` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +LEFT JOIN `Orders` AS `o0` ON `t0`.`CustomerID` = `o0`.`CustomerID` +ORDER BY `t`.`CustomerID`, `t0`.`CustomerID`, `o`.`OrderID` +"""); + } + + public override async Task Include_collection(bool async) + { + await base.Include_collection(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_then_include_collection_then_include_reference(bool async) + { + await base.Include_collection_then_include_collection_then_include_reference(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`OrderID0`, `t0`.`ProductID`, `t0`.`Discount`, `t0`.`Quantity`, `t0`.`UnitPrice`, `t0`.`ProductID0`, `t0`.`Discontinued`, `t0`.`ProductName`, `t0`.`SupplierID`, `t0`.`UnitPrice0`, `t0`.`UnitsInStock` +FROM `Customers` AS `c` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `t`.`OrderID` AS `OrderID0`, `t`.`ProductID`, `t`.`Discount`, `t`.`Quantity`, `t`.`UnitPrice`, `t`.`ProductID0`, `t`.`Discontinued`, `t`.`ProductName`, `t`.`SupplierID`, `t`.`UnitPrice0`, `t`.`UnitsInStock` + FROM `Orders` AS `o` + LEFT JOIN ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice`, `p`.`ProductID` AS `ProductID0`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice` AS `UnitPrice0`, `p`.`UnitsInStock` + FROM `Order Details` AS `o0` + INNER JOIN `Products` AS `p` ON `o0`.`ProductID` = `p`.`ProductID` + ) AS `t` ON `o`.`OrderID` = `t`.`OrderID` +) AS `t0` ON `c`.`CustomerID` = `t0`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `t0`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID` +"""); + } + + public override async Task Include_reference_GroupBy_Select(bool async) + { + await base.Include_reference_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`CustomerID0`, `t0`.`Address`, `t0`.`City`, `t0`.`CompanyName`, `t0`.`ContactName`, `t0`.`ContactTitle`, `t0`.`Country`, `t0`.`Fax`, `t0`.`Phone`, `t0`.`PostalCode`, `t0`.`Region` +FROM ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`CustomerID0`, `t1`.`Address`, `t1`.`City`, `t1`.`CompanyName`, `t1`.`ContactName`, `t1`.`ContactTitle`, `t1`.`Country`, `t1`.`Fax`, `t1`.`Phone`, `t1`.`PostalCode`, `t1`.`Region` + FROM ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, ROW_NUMBER() OVER(PARTITION BY `o0`.`OrderID` ORDER BY `o0`.`OrderID`) AS `row` + FROM `Orders` AS `o0` + LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` + WHERE `o0`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +"""); + } + + public override async Task Include_multiple_references_multi_level_reverse(bool async) + { + await base.Include_multiple_references_multi_level_reverse(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Order Details` AS `o` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +WHERE (`o`.`OrderID` % 23) = 13 +"""); + } + + public override async Task Include_collection_with_join_clause_with_filter(bool async) + { + await base.Include_collection_with_join_clause_with_filter(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Customers` AS `c` +INNER JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `o`.`OrderID` +"""); + } + + public override async Task Include_collection_OrderBy_list_does_not_contains(bool async) + { + await base.Include_collection_OrderBy_list_does_not_contains(async); + + AssertSql( +""" +@__p_1='1' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `c`.`CustomerID` <> 'ALFKI' AS `c` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'A%' + ORDER BY `c`.`CustomerID` <> 'ALFKI' + LIMIT 18446744073709551610 OFFSET @__p_1 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`c`, `t`.`CustomerID` +"""); + } + + public override async Task Include_reference_dependent_already_tracked(bool async) + { + await base.Include_reference_dependent_already_tracked(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Customers` AS `c` +WHERE `c`.`CustomerID` = 'ALFKI' +LIMIT 2 +""", + // + """ +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +WHERE `o`.`CustomerID` = 'ALFKI' +"""); + } + + public override async Task Include_reference_with_filter(bool async) + { + await base.Include_reference_with_filter(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +WHERE `o`.`CustomerID` = 'ALFKI' +"""); + } + + public override async Task Include_duplicate_reference(bool async) + { + await base.Include_duplicate_reference(async); + + AssertSql( +""" +@__p_0='2' + +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` +FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + ORDER BY `o`.`CustomerID`, `o`.`OrderID` + LIMIT @__p_0 +) AS `t` +CROSS JOIN ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + ORDER BY `o0`.`CustomerID`, `o0`.`OrderID` + LIMIT 2 OFFSET 2 +) AS `t0` +LEFT JOIN `Customers` AS `c` ON `t`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Customers` AS `c0` ON `t0`.`CustomerID` = `c0`.`CustomerID` +ORDER BY `t`.`CustomerID`, `t`.`OrderID` +"""); + } + + public override async Task Include_with_complex_projection(bool async) + { + await base.Include_with_complex_projection(async); + + AssertSql( +""" +SELECT `c`.`CustomerID` AS `Id` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_order_by_non_key_with_skip(bool async) + { + await base.Include_collection_order_by_non_key_with_skip(async); + + AssertSql( +""" +@__p_0='2' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'F%' + ORDER BY `c`.`ContactTitle` + LIMIT 18446744073709551610 OFFSET @__p_0 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`ContactTitle`, `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_on_join_clause_with_order_by_and_filter(bool async) + { + await base.Include_collection_on_join_clause_with_order_by_and_filter(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Customers` AS `c` +INNER JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `c`.`CustomerID` = 'ALFKI' +ORDER BY `c`.`City`, `c`.`CustomerID`, `o`.`OrderID` +"""); + } + + public override async Task Multi_level_includes_are_applied_with_take(bool async) + { + await base.Multi_level_includes_are_applied_with_take(async); + + AssertSql( +""" +@__p_0='1' + +SELECT `t0`.`CustomerID`, `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`OrderID0`, `t1`.`ProductID`, `t1`.`Discount`, `t1`.`Quantity`, `t1`.`UnitPrice` +FROM ( + SELECT `t`.`CustomerID` + FROM ( + SELECT `c`.`CustomerID` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'A%' + ORDER BY `c`.`CustomerID` + LIMIT @__p_0 + ) AS `t` + ORDER BY `t`.`CustomerID` + LIMIT 1 +) AS `t0` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID` AS `OrderID0`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Orders` AS `o` + LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +) AS `t1` ON `t0`.`CustomerID` = `t1`.`CustomerID` +ORDER BY `t0`.`CustomerID`, `t1`.`OrderID`, `t1`.`OrderID0` +"""); + } + + public override async Task Include_multiple_references_then_include_collection_multi_level_reverse(bool async) + { + await base.Include_multiple_references_then_include_collection_multi_level_reverse(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate` +FROM `Order Details` AS `o` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o1` ON `c`.`CustomerID` = `o1`.`CustomerID` +WHERE (`o`.`OrderID` % 23) = 13 +ORDER BY `o`.`OrderID`, `o`.`ProductID`, `p`.`ProductID`, `o0`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_then_reference(bool async) + { + await base.Include_collection_then_reference(async); + + AssertSql( +""" +SELECT `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock`, `t`.`OrderID`, `t`.`ProductID`, `t`.`Discount`, `t`.`Quantity`, `t`.`UnitPrice`, `t`.`OrderID0`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate` +FROM `Products` AS `p` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID` AS `OrderID0`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Order Details` AS `o` + INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +) AS `t` ON `p`.`ProductID` = `t`.`ProductID` +WHERE (`p`.`ProductID` % 17) = 5 +ORDER BY `p`.`ProductID`, `t`.`OrderID`, `t`.`ProductID` +"""); + } + + public override async Task Include_collection_order_by_key(bool async) + { + await base.Include_collection_order_by_key(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_with_outer_apply_with_filter(bool async) + { + await base.Include_collection_with_outer_apply_with_filter(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t`.`OrderID`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN LATERAL ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + WHERE `o`.`CustomerID` = `c`.`CustomerID` + ORDER BY `c`.`CustomerID` + LIMIT 5 +) AS `t` ON TRUE +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `t`.`OrderID` +"""); + } + + public override async Task Include_collection_on_additional_from_clause2(bool async) + { + await base.Include_collection_on_additional_from_clause2(async); + + AssertSql( +""" +@__p_0='5' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`CustomerID` + LIMIT @__p_0 +) AS `t` +CROSS JOIN `Customers` AS `c0` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_dependent_already_tracked(bool async) + { + await base.Include_collection_dependent_already_tracked(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Orders` AS `o` +WHERE `o`.`CustomerID` = 'ALFKI' +""", + // + """ +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` = 'ALFKI' + LIMIT 2 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Include_with_complex_projection_does_not_change_ordering_of_projection(bool async) + { + await base.Include_with_complex_projection_does_not_change_ordering_of_projection(async); + + AssertSql( +""" +SELECT `c`.`CustomerID` AS `Id`, ( + SELECT COUNT(*) + FROM `Orders` AS `o0` + WHERE `c`.`CustomerID` = `o0`.`CustomerID`) AS `TotalOrders` +FROM `Customers` AS `c` +WHERE (`c`.`ContactTitle` = 'Owner') AND (( + SELECT COUNT(*) + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID`) > 2) +ORDER BY `c`.`CustomerID` +"""); + } + + public override async Task Include_multi_level_collection_and_then_include_reference_predicate(bool async) + { + await base.Include_multi_level_collection_and_then_include_reference_predicate(async); + + AssertSql( +""" +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `t0`.`OrderID`, `t0`.`ProductID`, `t0`.`Discount`, `t0`.`Quantity`, `t0`.`UnitPrice`, `t0`.`ProductID0`, `t0`.`Discontinued`, `t0`.`ProductName`, `t0`.`SupplierID`, `t0`.`UnitPrice0`, `t0`.`UnitsInStock` +FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` = 10248 + LIMIT 2 +) AS `t` +LEFT JOIN ( + SELECT `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice`, `p`.`ProductID` AS `ProductID0`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice` AS `UnitPrice0`, `p`.`UnitsInStock` + FROM `Order Details` AS `o0` + INNER JOIN `Products` AS `p` ON `o0`.`ProductID` = `p`.`ProductID` +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +ORDER BY `t`.`OrderID`, `t0`.`OrderID`, `t0`.`ProductID` +"""); + } + + public override async Task Multi_level_includes_are_applied_with_skip_take(bool async) + { + await base.Multi_level_includes_are_applied_with_skip_take(async); + + AssertSql( +""" +@__p_0='1' + +SELECT `t0`.`CustomerID`, `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`OrderID0`, `t1`.`ProductID`, `t1`.`Discount`, `t1`.`Quantity`, `t1`.`UnitPrice` +FROM ( + SELECT `t`.`CustomerID` + FROM ( + SELECT `c`.`CustomerID` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'A%' + ORDER BY `c`.`CustomerID` + LIMIT @__p_0 OFFSET @__p_0 + ) AS `t` + ORDER BY `t`.`CustomerID` + LIMIT 1 +) AS `t0` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID` AS `OrderID0`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Orders` AS `o` + LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +) AS `t1` ON `t0`.`CustomerID` = `t1`.`CustomerID` +ORDER BY `t0`.`CustomerID`, `t1`.`OrderID`, `t1`.`OrderID0` +"""); + } + + public override async Task Include_collection_OrderBy_empty_list_contains(bool async) + { + await base.Include_collection_OrderBy_empty_list_contains(async); + + AssertSql( +""" +@__p_1='1' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, FALSE AS `c` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'A%' + ORDER BY (SELECT 1) + LIMIT 18446744073709551610 OFFSET @__p_1 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`c`, `t`.`CustomerID` +"""); + } + + public override async Task Include_references_and_collection_multi_level(bool async) + { + await base.Include_references_and_collection_multi_level(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o1` ON `c`.`CustomerID` = `o1`.`CustomerID` +WHERE ((`o`.`OrderID` % 23) = 13) AND (`o`.`UnitPrice` < 10.0) +ORDER BY `o`.`OrderID`, `o`.`ProductID`, `o0`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_force_alias_uniquefication(bool async) + { + await base.Include_collection_force_alias_uniquefication(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` +FROM `Orders` AS `o` +LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE `o`.`CustomerID` = 'ALFKI' +ORDER BY `o`.`OrderID`, `o0`.`OrderID` +"""); + } + + public override async Task Include_collection_with_outer_apply_with_filter_non_equality(bool async) + { + await base.Include_collection_with_outer_apply_with_filter_non_equality(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t`.`OrderID`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN LATERAL ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + WHERE (`o`.`CustomerID` <> `c`.`CustomerID`) OR `o`.`CustomerID` IS NULL + ORDER BY `c`.`CustomerID` + LIMIT 5 +) AS `t` ON TRUE +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `t`.`OrderID` +"""); + } + + public override async Task Include_in_let_followed_by_FirstOrDefault(bool async) + { + await base.Include_in_let_followed_by_FirstOrDefault(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` +FROM `Customers` AS `c` +LEFT JOIN ( + SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate` + FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, ROW_NUMBER() OVER(PARTITION BY `o`.`CustomerID` ORDER BY `o`.`OrderDate`) AS `row` + FROM `Orders` AS `o` + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `c`.`CustomerID` = `t0`.`CustomerID` +LEFT JOIN `Order Details` AS `o0` ON `t0`.`OrderID` = `o0`.`OrderID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `t0`.`OrderID`, `o0`.`OrderID` +"""); + } + + public override async Task Include_references_multi_level(bool async) + { + await base.Include_references_multi_level(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +WHERE (`o`.`OrderID` % 23) = 13 +"""); + } + + public override async Task Include_collection_then_include_collection(bool async) + { + await base.Include_collection_then_include_collection(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `t`.`OrderID0`, `t`.`ProductID`, `t`.`Discount`, `t`.`Quantity`, `t`.`UnitPrice` +FROM `Customers` AS `c` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID` AS `OrderID0`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Orders` AS `o` + LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +) AS `t` ON `c`.`CustomerID` = `t`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `t`.`OrderID`, `t`.`OrderID0` +"""); + } + + public override async Task Include_collection_with_multiple_conditional_order_by(bool async) + { + // The order of `Orders` can be different, because it is not explicitly sorted. + // This is the case on MariaDB. + await AssertQuery( + async, + ss => ss.Set() + .Include(c => c.OrderDetails) + .OrderBy(o => o.OrderID > 0) + .ThenBy(o => o.Customer != null ? o.Customer.City : string.Empty) + .ThenBy(o => o.OrderID) // Needs to be explicitly ordered by EmployeeID as well + .Take(5), + elementAsserter: (e, a) => AssertInclude(e, a, new ExpectedInclude(o => o.OrderDetails)), + entryCount: 14); + + AssertSql( +""" +@__p_0='5' + +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `t`.`CustomerID0`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` +FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `o`.`OrderID` > 0 AS `c`, CASE + WHEN `c`.`CustomerID` IS NOT NULL THEN `c`.`City` + ELSE '' + END AS `c0` + FROM `Orders` AS `o` + LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` + ORDER BY `o`.`OrderID` > 0, CASE + WHEN `c`.`CustomerID` IS NOT NULL THEN `c`.`City` + ELSE '' + END, `o`.`OrderID` + LIMIT @__p_0 +) AS `t` +LEFT JOIN `Order Details` AS `o0` ON `t`.`OrderID` = `o0`.`OrderID` +ORDER BY `t`.`c`, `t`.`c0`, `t`.`OrderID`, `t`.`CustomerID0`, `o0`.`OrderID` +"""); + } + + public override async Task Include_reference_when_entity_in_projection(bool async) + { + await base.Include_reference_when_entity_in_projection(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +WHERE `o`.`CustomerID` IS NOT NULL AND (`o`.`CustomerID` LIKE 'F%') +"""); + } + + public override async Task Include_reference_single_or_default_when_no_result(bool async) + { + await base.Include_reference_single_or_default_when_no_result(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +WHERE `o`.`OrderID` = -1 +LIMIT 2 +"""); + } + + public override async Task Include_reference_alias_generation(bool async) + { + await base.Include_reference_alias_generation(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE (`o`.`OrderID` % 23) = 13 +"""); + } + + public override async Task Include_with_cycle_does_not_throw_when_AsNoTrackingWithIdentityResolution(bool async) + { + await base.Include_with_cycle_does_not_throw_when_AsNoTrackingWithIdentityResolution(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `o`.`OrderID` < 10800 +ORDER BY `o`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Include_references_then_include_collection_multi_level(bool async) + { + await base.Include_references_then_include_collection_multi_level(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o1` ON `c`.`CustomerID` = `o1`.`CustomerID` +WHERE ((`o`.`ProductID` % 23) = 17) AND (`o`.`Quantity` < 10) +ORDER BY `o`.`OrderID`, `o`.`ProductID`, `o0`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Include_reference_Join_GroupBy_Select(bool async) + { + await base.Include_reference_Join_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`CustomerID0`, `t0`.`Address`, `t0`.`City`, `t0`.`CompanyName`, `t0`.`ContactName`, `t0`.`ContactTitle`, `t0`.`Country`, `t0`.`Fax`, `t0`.`Phone`, `t0`.`PostalCode`, `t0`.`Region` +FROM ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + INNER JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`CustomerID0`, `t1`.`Address`, `t1`.`City`, `t1`.`CompanyName`, `t1`.`ContactName`, `t1`.`ContactTitle`, `t1`.`Country`, `t1`.`Fax`, `t1`.`Phone`, `t1`.`PostalCode`, `t1`.`Region` + FROM ( + SELECT `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, ROW_NUMBER() OVER(PARTITION BY `o1`.`OrderID` ORDER BY `o1`.`OrderID`) AS `row` + FROM `Orders` AS `o1` + INNER JOIN `Order Details` AS `o2` ON `o1`.`OrderID` = `o2`.`OrderID` + LEFT JOIN `Customers` AS `c` ON `o1`.`CustomerID` = `c`.`CustomerID` + WHERE `o1`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +"""); + } + + public override async Task Include_collection_when_projection(bool async) + { + await base.Include_collection_when_projection(async); + + AssertSql( +""" +SELECT `c`.`CustomerID` +FROM `Customers` AS `c` +"""); + } + + public override async Task Include_reference_SelectMany_GroupBy_Select(bool async) + { + await base.Include_reference_SelectMany_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`CustomerID0`, `t0`.`Address`, `t0`.`City`, `t0`.`CompanyName`, `t0`.`ContactName`, `t0`.`ContactTitle`, `t0`.`Country`, `t0`.`Fax`, `t0`.`Phone`, `t0`.`PostalCode`, `t0`.`Region` +FROM ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + CROSS JOIN `Order Details` AS `o0` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`CustomerID0`, `t1`.`Address`, `t1`.`City`, `t1`.`CompanyName`, `t1`.`ContactName`, `t1`.`ContactTitle`, `t1`.`Country`, `t1`.`Fax`, `t1`.`Phone`, `t1`.`PostalCode`, `t1`.`Region` + FROM ( + SELECT `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, ROW_NUMBER() OVER(PARTITION BY `o1`.`OrderID` ORDER BY `o1`.`OrderID`) AS `row` + FROM `Orders` AS `o1` + CROSS JOIN `Order Details` AS `o2` + LEFT JOIN `Customers` AS `c` ON `o1`.`CustomerID` = `c`.`CustomerID` + WHERE `o1`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +"""); + } + + public override async Task Include_multiple_references_then_include_collection_multi_level(bool async) + { + await base.Include_multiple_references_then_include_collection_multi_level(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `p`.`ProductID`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +LEFT JOIN `Orders` AS `o1` ON `c`.`CustomerID` = `o1`.`CustomerID` +WHERE (`o`.`OrderID` % 23) = 13 +ORDER BY `o`.`OrderID`, `o`.`ProductID`, `o0`.`OrderID`, `c`.`CustomerID`, `p`.`ProductID` +"""); + } + + public override async Task Outer_idenfier_correctly_determined_when_doing_include_on_right_side_of_left_join(bool async) + { + await base.Outer_idenfier_correctly_determined_when_doing_include_on_right_side_of_left_join(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` +FROM `Customers` AS `c` +LEFT JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE `c`.`City` = 'Seattle' +ORDER BY `c`.`CustomerID`, `o`.`OrderID`, `o0`.`OrderID` +"""); + } + + public override async Task SelectMany_Include_reference_GroupBy_Select(bool async) + { + await base.SelectMany_Include_reference_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`CustomerID0`, `t0`.`Address`, `t0`.`City`, `t0`.`CompanyName`, `t0`.`ContactName`, `t0`.`ContactTitle`, `t0`.`Country`, `t0`.`Fax`, `t0`.`Phone`, `t0`.`PostalCode`, `t0`.`Region` +FROM ( + SELECT `o0`.`OrderID` + FROM `Order Details` AS `o` + CROSS JOIN `Orders` AS `o0` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o0`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`CustomerID0`, `t1`.`Address`, `t1`.`City`, `t1`.`CompanyName`, `t1`.`ContactName`, `t1`.`ContactTitle`, `t1`.`Country`, `t1`.`Fax`, `t1`.`Phone`, `t1`.`PostalCode`, `t1`.`Region` + FROM ( + SELECT `o2`.`OrderID`, `o2`.`CustomerID`, `o2`.`EmployeeID`, `o2`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, ROW_NUMBER() OVER(PARTITION BY `o2`.`OrderID` ORDER BY `o2`.`OrderID`) AS `row` + FROM `Order Details` AS `o1` + CROSS JOIN `Orders` AS `o2` + LEFT JOIN `Customers` AS `c` ON `o2`.`CustomerID` = `c`.`CustomerID` + WHERE `o1`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +"""); + } + + public override async Task Include_collection_SelectMany_GroupBy_Select(bool async) + { + await base.Include_collection_SelectMany_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID`, `o3`.`OrderID`, `o3`.`ProductID`, `o3`.`Discount`, `o3`.`Quantity`, `o3`.`UnitPrice` +FROM ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + CROSS JOIN `Order Details` AS `o0` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`OrderID0`, `t1`.`ProductID` + FROM ( + SELECT `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate`, `o2`.`OrderID` AS `OrderID0`, `o2`.`ProductID`, ROW_NUMBER() OVER(PARTITION BY `o1`.`OrderID` ORDER BY `o1`.`OrderID`) AS `row` + FROM `Orders` AS `o1` + CROSS JOIN `Order Details` AS `o2` + WHERE `o1`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +LEFT JOIN `Order Details` AS `o3` ON `t0`.`OrderID` = `o3`.`OrderID` +ORDER BY `t`.`OrderID`, `t0`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID`, `o3`.`OrderID` +"""); + } + + public override async Task Include_collection_OrderBy_list_contains(bool async) + { + await base.Include_collection_OrderBy_list_contains(async); + + AssertSql( +""" +@__p_1='1' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `c`.`CustomerID` = 'ALFKI' AS `c` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'A%' + ORDER BY `c`.`CustomerID` = 'ALFKI' + LIMIT 18446744073709551610 OFFSET @__p_1 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`c`, `t`.`CustomerID` +"""); + } + + public override async Task Multi_level_includes_are_applied_with_skip(bool async) + { + await base.Multi_level_includes_are_applied_with_skip(async); + + AssertSql( +""" +@__p_0='1' + +SELECT `t`.`CustomerID`, `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`OrderID0`, `t0`.`ProductID`, `t0`.`Discount`, `t0`.`Quantity`, `t0`.`UnitPrice` +FROM ( + SELECT `c`.`CustomerID` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'A%' + ORDER BY `c`.`CustomerID` + LIMIT 1 OFFSET @__p_0 +) AS `t` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `o0`.`OrderID` AS `OrderID0`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` + FROM `Orders` AS `o` + LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +) AS `t0` ON `t`.`CustomerID` = `t0`.`CustomerID` +ORDER BY `t`.`CustomerID`, `t0`.`OrderID`, `t0`.`OrderID0` +"""); + } + + public override async Task Include_collection_on_additional_from_clause(bool async) + { + await base.Include_collection_on_additional_from_clause(async); + + AssertSql( +""" +@__p_0='5' + +SELECT `t0`.`CustomerID`, `t0`.`Address`, `t0`.`City`, `t0`.`CompanyName`, `t0`.`ContactName`, `t0`.`ContactTitle`, `t0`.`Country`, `t0`.`Fax`, `t0`.`Phone`, `t0`.`PostalCode`, `t0`.`Region`, `t`.`CustomerID`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID` + FROM `Customers` AS `c` + ORDER BY `c`.`CustomerID` + LIMIT @__p_0 +) AS `t` +CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + WHERE `c0`.`CustomerID` LIKE 'F%' +) AS `t0` +LEFT JOIN `Orders` AS `o` ON `t0`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID`, `t0`.`CustomerID` +"""); + } + + public override async Task Include_reference_distinct_is_server_evaluated(bool async) + { + await base.Include_reference_distinct_is_server_evaluated(async); + + AssertSql( +""" +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM ( + SELECT DISTINCT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` < 10250 +) AS `t` +LEFT JOIN `Customers` AS `c` ON `t`.`CustomerID` = `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_distinct_is_server_evaluated(bool async) + { + await base.Include_collection_distinct_is_server_evaluated(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT DISTINCT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'A%' +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Include_reference_when_projection(bool async) + { + await base.Include_reference_when_projection(async); + + AssertSql( +""" +SELECT `o`.`CustomerID` +FROM `Orders` AS `o` +"""); + } + + public override async Task Include_duplicate_collection_result_operator(bool async) + { + // The order of `Orders` can be different, because it is not explicitly sorted. + // The order of the end result can be different as well. + // This is the case on MariaDB. + await AssertQuery( + async, + ss => (from c1 in ss.Set().Include(c => c.Orders).OrderBy(c => c.CustomerID).ThenBy(c => c.Orders.FirstOrDefault() != null ? c.Orders.FirstOrDefault().CustomerID : null).Take(2) + from c2 in ss.Set().Include(c => c.Orders).OrderBy(c => c.CustomerID).Skip(2).Take(2) + select new { c1, c2 }).OrderBy(t => t.c1.CustomerID).ThenBy(t => t.c2.CustomerID).Take(1), + elementSorter: e => (e.c1.CustomerID, e.c2.CustomerID), + elementAsserter: (e, a) => + { + AssertInclude(e.c1, a.c1, new ExpectedInclude(c => c.Orders)); + AssertInclude(e.c2, a.c2, new ExpectedInclude(c => c.Orders)); + }, + entryCount: 15); + + AssertSql( +""" +@__p_0='2' +@__p_1='1' + +SELECT `t1`.`CustomerID`, `t1`.`Address`, `t1`.`City`, `t1`.`CompanyName`, `t1`.`ContactName`, `t1`.`ContactTitle`, `t1`.`Country`, `t1`.`Fax`, `t1`.`Phone`, `t1`.`PostalCode`, `t1`.`Region`, `t1`.`CustomerID0`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `t1`.`Address0`, `t1`.`City0`, `t1`.`CompanyName0`, `t1`.`ContactName0`, `t1`.`ContactTitle0`, `t1`.`Country0`, `t1`.`Fax0`, `t1`.`Phone0`, `t1`.`PostalCode0`, `t1`.`Region0`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate` +FROM ( + SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `t0`.`CustomerID` AS `CustomerID0`, `t0`.`Address` AS `Address0`, `t0`.`City` AS `City0`, `t0`.`CompanyName` AS `CompanyName0`, `t0`.`ContactName` AS `ContactName0`, `t0`.`ContactTitle` AS `ContactTitle0`, `t0`.`Country` AS `Country0`, `t0`.`Fax` AS `Fax0`, `t0`.`Phone` AS `Phone0`, `t0`.`PostalCode` AS `PostalCode0`, `t0`.`Region` AS `Region0` + FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`CustomerID`, ( + SELECT `o`.`CustomerID` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + LIMIT 1) + LIMIT @__p_0 + ) AS `t` + CROSS JOIN ( + SELECT `c0`.`CustomerID`, `c0`.`Address`, `c0`.`City`, `c0`.`CompanyName`, `c0`.`ContactName`, `c0`.`ContactTitle`, `c0`.`Country`, `c0`.`Fax`, `c0`.`Phone`, `c0`.`PostalCode`, `c0`.`Region` + FROM `Customers` AS `c0` + ORDER BY `c0`.`CustomerID` + LIMIT 2 OFFSET 2 + ) AS `t0` + ORDER BY `t`.`CustomerID`, `t0`.`CustomerID` + LIMIT @__p_1 +) AS `t1` +LEFT JOIN `Orders` AS `o0` ON `t1`.`CustomerID` = `o0`.`CustomerID` +LEFT JOIN `Orders` AS `o1` ON `t1`.`CustomerID0` = `o1`.`CustomerID` +ORDER BY `t1`.`CustomerID`, `t1`.`CustomerID0`, `o0`.`OrderID` +"""); + } + + public override async Task Include_reference(bool async) + { + await base.Include_reference(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +WHERE `o`.`CustomerID` IS NOT NULL AND (`o`.`CustomerID` LIKE 'F%') +"""); + } + + public override async Task Include_multiple_references_and_collection_multi_level_reverse(bool async) + { + await base.Include_multiple_references_and_collection_multi_level_reverse(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate` +FROM `Order Details` AS `o` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o1` ON `c`.`CustomerID` = `o1`.`CustomerID` +WHERE (`o`.`OrderID` % 23) = 13 +ORDER BY `o`.`OrderID`, `o`.`ProductID`, `p`.`ProductID`, `o0`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Include_closes_reader(bool async) + { + await base.Include_closes_reader(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + LIMIT 1 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +""", + // + """ +SELECT `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock` +FROM `Products` AS `p` +"""); + } + + public override async Task Include_with_skip(bool async) + { + await base.Include_with_skip(async); + + AssertSql( +""" +@__p_0='80' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`ContactName` + LIMIT 18446744073709551610 OFFSET @__p_0 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`ContactName`, `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_Join_GroupBy_Select(bool async) + { + await base.Include_collection_Join_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID`, `o3`.`OrderID`, `o3`.`ProductID`, `o3`.`Discount`, `o3`.`Quantity`, `o3`.`UnitPrice` +FROM ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + INNER JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`OrderID0`, `t1`.`ProductID` + FROM ( + SELECT `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate`, `o2`.`OrderID` AS `OrderID0`, `o2`.`ProductID`, ROW_NUMBER() OVER(PARTITION BY `o1`.`OrderID` ORDER BY `o1`.`OrderID`) AS `row` + FROM `Orders` AS `o1` + INNER JOIN `Order Details` AS `o2` ON `o1`.`OrderID` = `o2`.`OrderID` + WHERE `o1`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +LEFT JOIN `Order Details` AS `o3` ON `t0`.`OrderID` = `o3`.`OrderID` +ORDER BY `t`.`OrderID`, `t0`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID`, `o3`.`OrderID` +"""); + } + + public override async Task Include_collection_GroupBy_Select(bool async) + { + await base.Include_collection_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t`.`OrderID`, `o1`.`OrderID`, `o1`.`ProductID`, `o1`.`Discount`, `o1`.`Quantity`, `o1`.`UnitPrice` +FROM ( + SELECT `o`.`OrderID` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate` + FROM ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, ROW_NUMBER() OVER(PARTITION BY `o0`.`OrderID` ORDER BY `o0`.`OrderID`) AS `row` + FROM `Orders` AS `o0` + WHERE `o0`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +LEFT JOIN `Order Details` AS `o1` ON `t0`.`OrderID` = `o1`.`OrderID` +ORDER BY `t`.`OrderID`, `t0`.`OrderID`, `o1`.`OrderID` +"""); + } + + public override async Task Include_collection_orderby_take(bool async) + { + await base.Include_collection_orderby_take(async); + + AssertSql( +""" +@__p_0='5' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`CustomerID` + LIMIT @__p_0 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Join_Include_collection_GroupBy_Select(bool async) + { + await base.Join_Include_collection_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID`, `o3`.`OrderID`, `o3`.`ProductID`, `o3`.`Discount`, `o3`.`Quantity`, `o3`.`UnitPrice` +FROM ( + SELECT `o0`.`OrderID` + FROM `Order Details` AS `o` + INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o0`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`OrderID0`, `t1`.`ProductID` + FROM ( + SELECT `o2`.`OrderID`, `o2`.`CustomerID`, `o2`.`EmployeeID`, `o2`.`OrderDate`, `o1`.`OrderID` AS `OrderID0`, `o1`.`ProductID`, ROW_NUMBER() OVER(PARTITION BY `o2`.`OrderID` ORDER BY `o2`.`OrderID`) AS `row` + FROM `Order Details` AS `o1` + INNER JOIN `Orders` AS `o2` ON `o1`.`OrderID` = `o2`.`OrderID` + WHERE `o1`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +LEFT JOIN `Order Details` AS `o3` ON `t0`.`OrderID` = `o3`.`OrderID` +ORDER BY `t`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID`, `t0`.`OrderID`, `o3`.`OrderID` +"""); + } + + public override async Task Include_collection_order_by_non_key(bool async) + { + await base.Include_collection_order_by_non_key(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`PostalCode`, `c`.`CustomerID` +"""); + } + + public override async Task Include_when_result_operator(bool async) + { + await base.Include_when_result_operator(async); + + AssertSql( +""" +SELECT EXISTS ( + SELECT 1 + FROM `Customers` AS `c`) +"""); + } + + public override async Task Include_duplicate_reference2(bool async) + { + await base.Include_duplicate_reference2(async); + + AssertSql( +""" +@__p_0='2' + +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate` +FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + ORDER BY `o`.`OrderID` + LIMIT @__p_0 +) AS `t` +CROSS JOIN ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Orders` AS `o0` + ORDER BY `o0`.`OrderID` + LIMIT 2 OFFSET 2 +) AS `t0` +LEFT JOIN `Customers` AS `c` ON `t`.`CustomerID` = `c`.`CustomerID` +ORDER BY `t`.`OrderID` +"""); + } + + public override async Task Include_collection_and_reference(bool async) + { + await base.Include_collection_and_reference(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE `o`.`CustomerID` IS NOT NULL AND (`o`.`CustomerID` LIKE 'F%') +ORDER BY `o`.`OrderID`, `c`.`CustomerID`, `o0`.`OrderID` +"""); + } + + public override async Task Include_multiple_references_multi_level(bool async) + { + await base.Include_multiple_references_multi_level(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +WHERE (`o`.`OrderID` % 23) = 13 +"""); + } + + public override async Task Include_references_and_collection_multi_level_predicate(bool async) + { + await base.Include_references_and_collection_multi_level_predicate(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o1` ON `c`.`CustomerID` = `o1`.`CustomerID` +WHERE `o`.`OrderID` = 10248 +ORDER BY `o`.`OrderID`, `o`.`ProductID`, `o0`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task SelectMany_Include_collection_GroupBy_Select(bool async) + { + await base.SelectMany_Include_collection_GroupBy_Select(async); + + AssertSql( +""" +SELECT `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID`, `o3`.`OrderID`, `o3`.`ProductID`, `o3`.`Discount`, `o3`.`Quantity`, `o3`.`UnitPrice` +FROM ( + SELECT `o0`.`OrderID` + FROM `Order Details` AS `o` + CROSS JOIN `Orders` AS `o0` + WHERE `o`.`OrderID` = 10248 + GROUP BY `o0`.`OrderID` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`OrderID`, `t1`.`CustomerID`, `t1`.`EmployeeID`, `t1`.`OrderDate`, `t1`.`OrderID0`, `t1`.`ProductID` + FROM ( + SELECT `o2`.`OrderID`, `o2`.`CustomerID`, `o2`.`EmployeeID`, `o2`.`OrderDate`, `o1`.`OrderID` AS `OrderID0`, `o1`.`ProductID`, ROW_NUMBER() OVER(PARTITION BY `o2`.`OrderID` ORDER BY `o2`.`OrderID`) AS `row` + FROM `Order Details` AS `o1` + CROSS JOIN `Orders` AS `o2` + WHERE `o1`.`OrderID` = 10248 + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` +LEFT JOIN `Order Details` AS `o3` ON `t0`.`OrderID` = `o3`.`OrderID` +ORDER BY `t`.`OrderID`, `t0`.`OrderID0`, `t0`.`ProductID`, `t0`.`OrderID`, `o3`.`OrderID` +"""); + } + + public override async Task Include_collection_with_last(bool async) + { + await base.Include_collection_with_last(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`CompanyName` DESC + LIMIT 1 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CompanyName` DESC, `t`.`CustomerID` +"""); + } + + public override async Task Include_collection_OrderBy_empty_list_does_not_contains(bool async) + { + await base.Include_collection_OrderBy_empty_list_does_not_contains(async); + + AssertSql( +""" +@__p_1='1' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, TRUE AS `c` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'A%' + ORDER BY (SELECT 1) + LIMIT 18446744073709551610 OFFSET @__p_1 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`c`, `t`.`CustomerID` +"""); + } + + public override async Task Include_multiple_references_then_include_multi_level_reverse(bool async) + { + await base.Include_multiple_references_then_include_multi_level_reverse(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Order Details` AS `o` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +WHERE (`o`.`OrderID` % 23) = 13 +"""); + } + + public override async Task Include_reference_and_collection(bool async) + { + await base.Include_reference_and_collection(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o0`.`OrderID`, `o0`.`ProductID`, `o0`.`Discount`, `o0`.`Quantity`, `o0`.`UnitPrice` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Order Details` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +WHERE `o`.`CustomerID` IS NOT NULL AND (`o`.`CustomerID` LIKE 'F%') +ORDER BY `o`.`OrderID`, `c`.`CustomerID`, `o0`.`OrderID` +"""); + } + + public override async Task Include_is_not_ignored_when_projection_contains_client_method_and_complex_expression(bool async) + { + await base.Include_is_not_ignored_when_projection_contains_client_method_and_complex_expression(async); + + AssertSql( +""" +SELECT `e0`.`EmployeeID` IS NOT NULL, `e`.`EmployeeID`, `e`.`City`, `e`.`Country`, `e`.`FirstName`, `e`.`ReportsTo`, `e`.`Title`, `e0`.`EmployeeID`, `e0`.`City`, `e0`.`Country`, `e0`.`FirstName`, `e0`.`ReportsTo`, `e0`.`Title` +FROM `Employees` AS `e` +LEFT JOIN `Employees` AS `e0` ON `e`.`ReportsTo` = `e0`.`EmployeeID` +WHERE `e`.`EmployeeID` IN (1, 2) +ORDER BY `e`.`EmployeeID` +"""); + } + + public override async Task Include_reference_with_filter_reordered(bool async) + { + await base.Include_reference_with_filter_reordered(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +WHERE `o`.`CustomerID` = 'ALFKI' +"""); + } + + public override async Task Include_collection_order_by_subquery(bool async) + { + await base.Include_collection_order_by_subquery(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, ( + SELECT `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`EmployeeID` + LIMIT 1) AS `c` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` = 'ALFKI' + ORDER BY ( + SELECT `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`EmployeeID` + LIMIT 1) + LIMIT 1 +) AS `t` +LEFT JOIN `Orders` AS `o0` ON `t`.`CustomerID` = `o0`.`CustomerID` +ORDER BY `t`.`c`, `t`.`CustomerID` +"""); + } + + public override async Task Include_reference_and_collection_order_by(bool async) + { + await base.Include_reference_and_collection_order_by(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM `Orders` AS `o` +LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o0` ON `c`.`CustomerID` = `o0`.`CustomerID` +WHERE `o`.`CustomerID` IS NOT NULL AND (`o`.`CustomerID` LIKE 'F%') +ORDER BY `o`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Then_include_collection_order_by_collection_column(bool async) + { + await base.Then_include_collection_order_by_collection_column(async); + + AssertSql( +""" +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `t0`.`OrderID`, `t0`.`CustomerID`, `t0`.`EmployeeID`, `t0`.`OrderDate`, `t0`.`OrderID0`, `t0`.`ProductID`, `t0`.`Discount`, `t0`.`Quantity`, `t0`.`UnitPrice` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, ( + SELECT `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`OrderDate` DESC + LIMIT 1) AS `c` + FROM `Customers` AS `c` + WHERE `c`.`CustomerID` LIKE 'W%' + ORDER BY ( + SELECT `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`OrderDate` DESC + LIMIT 1) DESC + LIMIT 1 +) AS `t` +LEFT JOIN ( + SELECT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `o1`.`OrderID` AS `OrderID0`, `o1`.`ProductID`, `o1`.`Discount`, `o1`.`Quantity`, `o1`.`UnitPrice` + FROM `Orders` AS `o0` + LEFT JOIN `Order Details` AS `o1` ON `o0`.`OrderID` = `o1`.`OrderID` +) AS `t0` ON `t`.`CustomerID` = `t0`.`CustomerID` +ORDER BY `t`.`c` DESC, `t`.`CustomerID`, `t0`.`OrderID`, `t0`.`OrderID0` +"""); + } + + public override async Task Include_multiple_references_then_include_multi_level(bool async) + { + await base.Include_multiple_references_then_include_multi_level(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +WHERE (`o`.`OrderID` % 23) = 13 +"""); + } + + public override async Task Include_collection_skip_no_order_by(bool async) + { + await base.Include_collection_skip_no_order_by(async); + + AssertSql( +""" +@__p_0='10' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + LIMIT 18446744073709551610 OFFSET @__p_0 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`CustomerID` +"""); + } + + public override async Task Include_multi_level_reference_then_include_collection_predicate(bool async) + { + await base.Include_multi_level_reference_then_include_collection_predicate(async); + + AssertSql( +""" +SELECT `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate`, `t`.`CustomerID0`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, `c`.`CustomerID` AS `CustomerID0`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Orders` AS `o` + LEFT JOIN `Customers` AS `c` ON `o`.`CustomerID` = `c`.`CustomerID` + WHERE `o`.`OrderID` = 10248 + LIMIT 2 +) AS `t` +LEFT JOIN `Orders` AS `o0` ON `t`.`CustomerID0` = `o0`.`CustomerID` +ORDER BY `t`.`OrderID`, `t`.`CustomerID0` +"""); + } + + public override async Task Include_multiple_references_and_collection_multi_level(bool async) + { + await base.Include_multiple_references_and_collection_multi_level(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `p`.`ProductID`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +LEFT JOIN `Orders` AS `o1` ON `c`.`CustomerID` = `o1`.`CustomerID` +WHERE (`o`.`OrderID` % 23) = 13 +ORDER BY `o`.`OrderID`, `o`.`ProductID`, `o0`.`OrderID`, `c`.`CustomerID`, `p`.`ProductID` +"""); + } + + public override async Task Include_where_skip_take_projection(bool async) + { + await base.Include_where_skip_take_projection(async); + + AssertSql( +""" +@__p_1='2' +@__p_0='1' + +SELECT `o0`.`CustomerID` +FROM ( + SELECT `o`.`OrderID`, `o`.`ProductID` + FROM `Order Details` AS `o` + WHERE `o`.`Quantity` = 10 + ORDER BY `o`.`OrderID`, `o`.`ProductID` + LIMIT @__p_1 OFFSET @__p_0 +) AS `t` +INNER JOIN `Orders` AS `o0` ON `t`.`OrderID` = `o0`.`OrderID` +ORDER BY `t`.`OrderID`, `t`.`ProductID` +"""); + } + + public override async Task Include_with_take(bool async) + { + await base.Include_with_take(async); + + AssertSql( +""" +@__p_0='10' + +SELECT `t`.`CustomerID`, `t`.`Address`, `t`.`City`, `t`.`CompanyName`, `t`.`ContactName`, `t`.`ContactTitle`, `t`.`Country`, `t`.`Fax`, `t`.`Phone`, `t`.`PostalCode`, `t`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM ( + SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` + FROM `Customers` AS `c` + ORDER BY `c`.`ContactName` DESC + LIMIT @__p_0 +) AS `t` +LEFT JOIN `Orders` AS `o` ON `t`.`CustomerID` = `o`.`CustomerID` +ORDER BY `t`.`ContactName` DESC, `t`.`CustomerID` +"""); + } + + public override async Task Include_multiple_references(bool async) + { + await base.Include_multiple_references(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +INNER JOIN `Products` AS `p` ON `o`.`ProductID` = `p`.`ProductID` +WHERE (`o`.`OrderID` % 23) = 13 +"""); + } + + public override async Task Include_list(bool async) + { + await base.Include_list(async); + + AssertSql( +""" +SELECT `p`.`ProductID`, `p`.`Discontinued`, `p`.`ProductName`, `p`.`SupplierID`, `p`.`UnitPrice`, `p`.`UnitsInStock`, `t`.`OrderID`, `t`.`ProductID`, `t`.`Discount`, `t`.`Quantity`, `t`.`UnitPrice`, `t`.`OrderID0`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate` +FROM `Products` AS `p` +LEFT JOIN ( + SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID` AS `OrderID0`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` + FROM `Order Details` AS `o` + INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +) AS `t` ON `p`.`ProductID` = `t`.`ProductID` +WHERE ((`p`.`ProductID` % 17) = 5) AND (`p`.`UnitPrice` < 20.0) +ORDER BY `p`.`ProductID`, `t`.`OrderID`, `t`.`ProductID` +"""); + } + + public override async Task Include_empty_reference_sets_IsLoaded(bool async) + { + await base.Include_empty_reference_sets_IsLoaded(async); + + AssertSql( +""" +SELECT `e`.`EmployeeID`, `e`.`City`, `e`.`Country`, `e`.`FirstName`, `e`.`ReportsTo`, `e`.`Title`, `e0`.`EmployeeID`, `e0`.`City`, `e0`.`Country`, `e0`.`FirstName`, `e0`.`ReportsTo`, `e0`.`Title` +FROM `Employees` AS `e` +LEFT JOIN `Employees` AS `e0` ON `e`.`ReportsTo` = `e0`.`EmployeeID` +WHERE `e0`.`EmployeeID` IS NULL +LIMIT 1 +"""); + } + + public override async Task Include_references_then_include_collection_multi_level_predicate(bool async) + { + await base.Include_references_then_include_collection_multi_level_predicate(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate`, `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o1`.`OrderID`, `o1`.`CustomerID`, `o1`.`EmployeeID`, `o1`.`OrderDate` +FROM `Order Details` AS `o` +INNER JOIN `Orders` AS `o0` ON `o`.`OrderID` = `o0`.`OrderID` +LEFT JOIN `Customers` AS `c` ON `o0`.`CustomerID` = `c`.`CustomerID` +LEFT JOIN `Orders` AS `o1` ON `c`.`CustomerID` = `o1`.`CustomerID` +WHERE `o`.`OrderID` = 10248 +ORDER BY `o`.`OrderID`, `o`.`ProductID`, `o0`.`OrderID`, `c`.`CustomerID` +"""); + } + + public override async Task Include_collection_with_conditional_order_by(bool async) + { + await base.Include_collection_with_conditional_order_by(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN `Orders` AS `o` ON `c`.`CustomerID` = `o`.`CustomerID` +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY CASE + WHEN `c`.`CustomerID` LIKE 'S%' THEN 1 + ELSE 2 +END, `c`.`CustomerID` +"""); + } + + public override async Task Include_non_existing_navigation(bool async) + { + await base.Include_non_existing_navigation(async); + + AssertSql(); + } + + public override async Task Include_property(bool async) + { + await base.Include_property(async); + + AssertSql(); + } + + public override async Task Include_property_after_navigation(bool async) + { + await base.Include_property_after_navigation(async); + + AssertSql(); + } + + public override async Task Include_property_expression_invalid(bool async) + { + await base.Include_property_expression_invalid(async); + + AssertSql(); + } + + public override async Task Then_include_property_expression_invalid(bool async) + { + await base.Then_include_property_expression_invalid(async); + + AssertSql(); + } + + public override async Task Filtered_include_with_multiple_ordering(bool async) + { + await base.Filtered_include_with_multiple_ordering(async); + + AssertSql( +""" +SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region`, `t`.`OrderID`, `t`.`CustomerID`, `t`.`EmployeeID`, `t`.`OrderDate` +FROM `Customers` AS `c` +LEFT JOIN LATERAL ( + SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID` + ORDER BY `o`.`OrderID` + LIMIT 18446744073709551610 OFFSET 1 +) AS `t` ON TRUE +WHERE `c`.`CustomerID` LIKE 'F%' +ORDER BY `c`.`CustomerID`, `t`.`OrderDate` DESC +"""); + } + + public override async Task Include_specified_on_non_entity_not_supported(bool async) + { + await base.Include_specified_on_non_entity_not_supported(async); + + AssertSql(); + } + + public override async Task Include_collection_with_client_filter(bool async) + { + await base.Include_collection_with_client_filter(async); + + AssertSql(); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindFunctionsQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindFunctionsQueryMySqlTest.cs index f3bbe9be0..ba6779ac2 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindFunctionsQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindFunctionsQueryMySqlTest.cs @@ -173,9 +173,9 @@ public override async Task Indexof_with_emptystring(bool async) await base.Indexof_with_emptystring(async); AssertSql( - $@"SELECT LOCATE('', `c`.`ContactName`) - 1 + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE `c`.`CustomerID` = 'ALFKI'"); +WHERE (LOCATE('', `c`.`ContactName`) - 1) = 0"); } [ConditionalTheory] @@ -184,9 +184,9 @@ public override async Task Replace_with_emptystring(bool async) await base.Replace_with_emptystring(async); AssertSql( - $@"SELECT REPLACE(`c`.`ContactName`, 'ari', '') + @"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE `c`.`CustomerID` = 'ALFKI'"); +WHERE REPLACE(`c`.`ContactName`, 'ia', '') = 'Mar Anders'"); } [ConditionalTheory] @@ -342,7 +342,7 @@ public override async Task Select_math_round_int(bool async) await base.Select_math_round_int(async); AssertSql( - $@"SELECT ROUND({CastAsDouble("`o`.`OrderID`")}) AS `A` + $@"SELECT ROUND({MySqlTestHelpers.CastAsDouble("`o`.`OrderID`")}) AS `A` FROM `Orders` AS `o` WHERE `o`.`OrderID` < 10250"); } @@ -543,7 +543,7 @@ public override async Task Where_math_ceiling1(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`UnitPrice` < 7.0) AND (CEILING({CastAsDouble("`o`.`Discount`")}) > 0.0)"); +WHERE (`o`.`UnitPrice` < 7.0) AND (CEILING({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 0.0)"); } public override async Task Where_math_ceiling2(bool async) @@ -573,7 +573,7 @@ public override async Task Where_math_power(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE POWER({CastAsDouble("`o`.`Discount`")}, 3.0) > 0.004999999888241291"); +WHERE POWER({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}, 3.0) > 0.004999999888241291"); } public override async Task Where_math_round(bool async) @@ -591,7 +591,7 @@ public override async Task Select_math_truncate_int(bool async) await base.Select_math_truncate_int(async); AssertSql( - $@"SELECT TRUNCATE({CastAsDouble("`o`.`OrderID`")}, 0) AS `A` + $@"SELECT TRUNCATE({MySqlTestHelpers.CastAsDouble("`o`.`OrderID`")}, 0) AS `A` FROM `Orders` AS `o` WHERE `o`.`OrderID` < 10250"); } @@ -623,7 +623,7 @@ public override async Task Where_math_exp(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (EXP({CastAsDouble("`o`.`Discount`")}) > 1.0)"); +WHERE (`o`.`OrderID` = 11077) AND (EXP({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 1.0)"); } public override async Task Where_math_log10(bool async) @@ -633,7 +633,7 @@ public override async Task Where_math_log10(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE ((`o`.`OrderID` = 11077) AND (`o`.`Discount` > 0)) AND (LOG10({CastAsDouble("`o`.`Discount`")}) < 0.0)"); +WHERE ((`o`.`OrderID` = 11077) AND (`o`.`Discount` > 0)) AND (LOG10({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) < 0.0)"); } public override async Task Where_math_log(bool async) @@ -643,7 +643,7 @@ public override async Task Where_math_log(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE ((`o`.`OrderID` = 11077) AND (`o`.`Discount` > 0)) AND (LOG({CastAsDouble("`o`.`Discount`")}) < 0.0)"); +WHERE ((`o`.`OrderID` = 11077) AND (`o`.`Discount` > 0)) AND (LOG({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) < 0.0)"); } public override async Task Where_math_log_new_base(bool async) @@ -653,7 +653,7 @@ public override async Task Where_math_log_new_base(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE ((`o`.`OrderID` = 11077) AND (`o`.`Discount` > 0)) AND (LOG({CastAsDouble("`o`.`Discount`")}, 7.0) < 0.0)"); +WHERE ((`o`.`OrderID` = 11077) AND (`o`.`Discount` > 0)) AND (LOG({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}, 7.0) < 0.0)"); } public override async Task Where_math_sqrt(bool async) @@ -663,7 +663,7 @@ public override async Task Where_math_sqrt(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (SQRT({CastAsDouble("`o`.`Discount`")}) > 0.0)"); +WHERE (`o`.`OrderID` = 11077) AND (SQRT({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 0.0)"); } public override async Task Where_math_acos(bool async) @@ -673,7 +673,7 @@ public override async Task Where_math_acos(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (ACOS({CastAsDouble("`o`.`Discount`")}) > 1.0)"); +WHERE (`o`.`OrderID` = 11077) AND (ACOS({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 1.0)"); } public override async Task Where_math_asin(bool async) @@ -683,7 +683,7 @@ public override async Task Where_math_asin(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (ASIN({CastAsDouble("`o`.`Discount`")}) > 0.0)"); +WHERE (`o`.`OrderID` = 11077) AND (ASIN({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 0.0)"); } public override async Task Where_math_atan(bool async) @@ -693,7 +693,7 @@ public override async Task Where_math_atan(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (ATAN({CastAsDouble("`o`.`Discount`")}) > 0.0)"); +WHERE (`o`.`OrderID` = 11077) AND (ATAN({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 0.0)"); } public override async Task Where_math_atan2(bool async) @@ -703,7 +703,7 @@ public override async Task Where_math_atan2(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (ATAN2({CastAsDouble("`o`.`Discount`")}, 1.0) > 0.0)"); +WHERE (`o`.`OrderID` = 11077) AND (ATAN2({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}, 1.0) > 0.0)"); } public override async Task Where_math_cos(bool async) @@ -713,7 +713,7 @@ public override async Task Where_math_cos(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (COS({CastAsDouble("`o`.`Discount`")}) > 0.0)"); +WHERE (`o`.`OrderID` = 11077) AND (COS({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 0.0)"); } public override async Task Where_math_sin(bool async) @@ -723,7 +723,7 @@ public override async Task Where_math_sin(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (SIN({CastAsDouble("`o`.`Discount`")}) > 0.0)"); +WHERE (`o`.`OrderID` = 11077) AND (SIN({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 0.0)"); } public override async Task Where_math_tan(bool async) @@ -733,7 +733,7 @@ public override async Task Where_math_tan(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`ProductID`, `o`.`Discount`, `o`.`Quantity`, `o`.`UnitPrice` FROM `Order Details` AS `o` -WHERE (`o`.`OrderID` = 11077) AND (TAN({CastAsDouble("`o`.`Discount`")}) > 0.0)"); +WHERE (`o`.`OrderID` = 11077) AND (TAN({MySqlTestHelpers.CastAsDouble("`o`.`Discount`")}) > 0.0)"); } public override async Task Where_math_sign(bool async) @@ -763,7 +763,7 @@ public override async Task Where_functions_nested(bool async) AssertSql( $@"SELECT `c`.`CustomerID`, `c`.`Address`, `c`.`City`, `c`.`CompanyName`, `c`.`ContactName`, `c`.`ContactTitle`, `c`.`Country`, `c`.`Fax`, `c`.`Phone`, `c`.`PostalCode`, `c`.`Region` FROM `Customers` AS `c` -WHERE POWER({CastAsDouble("CHAR_LENGTH(`c`.`CustomerID`)")}, 2.0) = 25.0"); +WHERE POWER({MySqlTestHelpers.CastAsDouble("CHAR_LENGTH(`c`.`CustomerID`)")}, 2.0) = 25.0"); } public override async Task IsNullOrEmpty_in_predicate(bool async) @@ -854,10 +854,10 @@ public override async Task Projecting_Math_Truncate_and_ordering_by_it_twice(boo await base.Projecting_Math_Truncate_and_ordering_by_it_twice(async); AssertSql( - $@"SELECT TRUNCATE({CastAsDouble("`o`.`OrderID`")}, 0) AS `A` + $@"SELECT TRUNCATE({MySqlTestHelpers.CastAsDouble("`o`.`OrderID`")}, 0) AS `A` FROM `Orders` AS `o` WHERE `o`.`OrderID` < 10250 -ORDER BY TRUNCATE({CastAsDouble("`o`.`OrderID`")}, 0)"); +ORDER BY TRUNCATE({MySqlTestHelpers.CastAsDouble("`o`.`OrderID`")}, 0)"); } public override async Task Projecting_Math_Truncate_and_ordering_by_it_twice2(bool async) @@ -865,10 +865,10 @@ public override async Task Projecting_Math_Truncate_and_ordering_by_it_twice2(bo await base.Projecting_Math_Truncate_and_ordering_by_it_twice2(async); AssertSql( - $@"SELECT TRUNCATE({CastAsDouble("`o`.`OrderID`")}, 0) AS `A` + $@"SELECT TRUNCATE({MySqlTestHelpers.CastAsDouble("`o`.`OrderID`")}, 0) AS `A` FROM `Orders` AS `o` WHERE `o`.`OrderID` < 10250 -ORDER BY TRUNCATE({CastAsDouble("`o`.`OrderID`")}, 0) DESC"); +ORDER BY TRUNCATE({MySqlTestHelpers.CastAsDouble("`o`.`OrderID`")}, 0) DESC"); } public override async Task Projecting_Math_Truncate_and_ordering_by_it_twice3(bool async) @@ -876,10 +876,10 @@ public override async Task Projecting_Math_Truncate_and_ordering_by_it_twice3(bo await base.Projecting_Math_Truncate_and_ordering_by_it_twice3(async); AssertSql( - $@"SELECT TRUNCATE({CastAsDouble("`o`.`OrderID`")}, 0) AS `A` + $@"SELECT TRUNCATE({MySqlTestHelpers.CastAsDouble("`o`.`OrderID`")}, 0) AS `A` FROM `Orders` AS `o` WHERE `o`.`OrderID` < 10250 -ORDER BY TRUNCATE({CastAsDouble("`o`.`OrderID`")}, 0) DESC"); +ORDER BY TRUNCATE({MySqlTestHelpers.CastAsDouble("`o`.`OrderID`")}, 0) DESC"); } public override async Task String_Compare_simple_zero(bool async) @@ -1379,11 +1379,11 @@ public override async Task Convert_ToBoolean(bool async) // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND CAST({CastAsDouble("`o`.`OrderID` % 3")} AS signed)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 3")} AS signed)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND CAST({CastAsDouble("`o`.`OrderID` % 3")} AS signed)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 3")} AS signed)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` @@ -1417,11 +1417,11 @@ public override async Task Convert_ToByte(bool async) // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS unsigned) >= 0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS unsigned) >= 0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS unsigned) >= 0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS unsigned) >= 0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` @@ -1459,11 +1459,11 @@ public override async Task Convert_ToDecimal(bool async) // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS decimal(65,30)) >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS decimal(65,30)) >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS decimal(65,30)) >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS decimal(65,30)) >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` @@ -1489,39 +1489,39 @@ public override async Task Convert_ToDouble(bool async) AssertSql( $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("CAST(`o`.`OrderID` % 1 AS signed)")} >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("CAST(`o`.`OrderID` % 1 AS signed)")} >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("CAST(`o`.`OrderID` % 1 AS unsigned)")} >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("CAST(`o`.`OrderID` % 1 AS unsigned)")} >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("CAST(`o`.`OrderID` % 1 AS decimal(65,30))")} >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("CAST(`o`.`OrderID` % 1 AS decimal(65,30))")} >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("`o`.`OrderID` % 1")} >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("`o`.`OrderID` % 1")} >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("CAST(`o`.`OrderID` % 1 AS signed)")} >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("CAST(`o`.`OrderID` % 1 AS signed)")} >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("CAST(`o`.`OrderID` % 1 AS signed)")} >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("CAST(`o`.`OrderID` % 1 AS signed)")} >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("CAST(`o`.`OrderID` % 1 AS signed)")} >= 0.0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("CAST(`o`.`OrderID` % 1 AS signed)")} >= 0.0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND ({CastAsDouble("CAST(`o`.`OrderID` % 1 AS char)")} >= 0.0)"); +WHERE (`o`.`CustomerID` = 'ALFKI') AND ({MySqlTestHelpers.CastAsDouble("CAST(`o`.`OrderID` % 1 AS char)")} >= 0.0)"); } public override async Task Convert_ToInt16(bool async) @@ -1543,11 +1543,11 @@ public override async Task Convert_ToInt16(bool async) // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` @@ -1585,11 +1585,11 @@ public override async Task Convert_ToInt32(bool async) // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` @@ -1627,11 +1627,11 @@ public override async Task Convert_ToInt64(bool async) // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS signed) >= 0)", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` @@ -1669,11 +1669,11 @@ public override async Task Convert_ToString(bool async) // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS char) <> '10')", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS char) <> '10')", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({CastAsDouble("`o`.`OrderID` % 1")} AS char) <> '10')", +WHERE (`o`.`CustomerID` = 'ALFKI') AND (CAST({MySqlTestHelpers.CastAsDouble("`o`.`OrderID` % 1")} AS char) <> '10')", // $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` @@ -1699,11 +1699,6 @@ public override async Task Convert_ToString(bool async) public override Task Datetime_subtraction_TotalDays(bool async) => AssertTranslationFailed(() => base.Datetime_subtraction_TotalDays(async)); - private string CastAsDouble(string innerSql) - => AppConfig.ServerVersion.Supports.DoubleCast - ? $@"CAST({innerSql} AS double)" - : $@"(CAST({innerSql} AS decimal(65,30)) + 0e0)"; - private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindGroupByQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindGroupByQueryMySqlTest.cs index f749ad2d8..637ae56eb 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindGroupByQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindGroupByQueryMySqlTest.cs @@ -125,13 +125,7 @@ public override async Task GroupBy_group_Distinct_Select_Distinct_aggregate(bool await base.GroupBy_group_Distinct_Select_Distinct_aggregate(async); AssertSql( - @"SELECT `o`.`CustomerID` AS `Key`, ( - SELECT DISTINCT MAX(DISTINCT (`t`.`OrderDate`)) - FROM ( - SELECT DISTINCT `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` - FROM `Orders` AS `o0` - WHERE (`o`.`CustomerID` = `o0`.`CustomerID`) OR (`o`.`CustomerID` IS NULL AND (`o0`.`CustomerID` IS NULL)) - ) AS `t`) AS `Max` + @"SELECT `o`.`CustomerID` AS `Key`, MAX(DISTINCT (`o`.`OrderDate`)) AS `Max` FROM `Orders` AS `o` GROUP BY `o`.`CustomerID`"); } diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindIncludeNoTrackingQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindIncludeNoTrackingQueryMySqlTest.cs index 0d6078d69..6472d1d1f 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindIncludeNoTrackingQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindIncludeNoTrackingQueryMySqlTest.cs @@ -27,7 +27,7 @@ public override async Task Include_collection_with_last_no_orderby(bool async) public override Task Include_duplicate_collection_result_operator2(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // The order of the end result can be different as well. // This is the case on MariaDB. return AssertQuery( @@ -59,7 +59,7 @@ public override Task Repro9735(bool async) public override Task Include_duplicate_collection_result_operator(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // The order of the end result can be different as well. // This is the case on MariaDB. return AssertQuery( diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindIncludeQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindIncludeQueryMySqlTest.cs index af49fb1dd..f7e302dcc 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindIncludeQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindIncludeQueryMySqlTest.cs @@ -33,7 +33,7 @@ public override Task Include_duplicate_collection(bool async) public override Task Include_collection_with_multiple_conditional_order_by(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // This is the case on MariaDB. return AssertQuery( async, @@ -49,7 +49,7 @@ public override Task Include_collection_with_multiple_conditional_order_by(bool public override Task Include_duplicate_collection_result_operator(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // This is the case on MariaDB. return AssertQuery( async, @@ -67,7 +67,7 @@ from c2 in ss.Set().Include(c => c.Orders).OrderBy(c => c.CustomerID). public override Task Include_duplicate_collection_result_operator2(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // This is the case on MariaDB. return AssertQuery( async, diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindKeylessEntitiesQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindKeylessEntitiesQueryMySqlTest.cs index 955c46ec4..5df5f6f22 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindKeylessEntitiesQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindKeylessEntitiesQueryMySqlTest.cs @@ -1,5 +1,7 @@ -using Microsoft.EntityFrameworkCore.Query; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; +using MySqlConnector; using Xunit; using Xunit.Abstractions; @@ -17,8 +19,18 @@ public NorthwindKeylessEntitiesQueryMySqlTest(NorthwindQueryMySqlFixture true; - [ConditionalFact(Skip = "https://github.com/dotnet/efcore/issues/21627")] - public override void KeylessEntity_with_nav_defining_query() - => base.KeylessEntity_with_nav_defining_query(); + public override async Task KeylessEntity_with_nav_defining_query(bool async) + { + // FromSql mapping. Issue #21627. + await Assert.ThrowsAsync(() => base.KeylessEntity_with_nav_defining_query(async)); + + AssertSql( + @"SELECT `c`.`CompanyName`, `c`.`OrderCount`, `c`.`SearchTerm` +FROM `CustomerQueryWithQueryFilter` AS `c` +WHERE `c`.`OrderCount` > 0"); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindMiscellaneousQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindMiscellaneousQueryMySqlTest.cs index 27c9b8b90..2f8859516 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindMiscellaneousQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindMiscellaneousQueryMySqlTest.cs @@ -1,6 +1,8 @@ using System; using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.Northwind; @@ -12,6 +14,7 @@ using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; using Xunit; using Xunit.Abstractions; +using Xunit.Sdk; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query { @@ -248,7 +251,7 @@ await AssertQuery( AssertSql( @"@__p_0='5' -SELECT `t`.`OrderID`, `t0`.`ProductID`, `t0`.`OrderID` +SELECT `t`.`OrderID`, `o0`.`ProductID`, `o0`.`OrderID` FROM ( SELECT `o`.`OrderID` FROM `Orders` AS `o` @@ -256,11 +259,8 @@ await AssertQuery( ORDER BY `o`.`OrderID` LIMIT 18446744073709551610 OFFSET @__p_0 ) AS `t` -LEFT JOIN ( - SELECT `o0`.`ProductID`, `o0`.`OrderID` - FROM `Order Details` AS `o0` -) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` -ORDER BY `t`.`OrderID`, `t0`.`ProductID`"); +LEFT JOIN `Order Details` AS `o0` ON `t`.`OrderID` = `o0`.`OrderID` +ORDER BY `t`.`OrderID`, `o0`.`ProductID`"); } /// @@ -289,7 +289,7 @@ await AssertQuery( @"@__p_1='10' @__p_0='5' -SELECT `t`.`OrderID`, `t0`.`ProductID`, `t0`.`OrderID` +SELECT `t`.`OrderID`, `o0`.`ProductID`, `o0`.`OrderID` FROM ( SELECT `o`.`OrderID` FROM `Orders` AS `o` @@ -297,11 +297,8 @@ await AssertQuery( ORDER BY `o`.`OrderID` LIMIT @__p_1 OFFSET @__p_0 ) AS `t` -LEFT JOIN ( - SELECT `o0`.`ProductID`, `o0`.`OrderID` - FROM `Order Details` AS `o0` -) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` -ORDER BY `t`.`OrderID`, `t0`.`ProductID`"); +LEFT JOIN `Order Details` AS `o0` ON `t`.`OrderID` = `o0`.`OrderID` +ORDER BY `t`.`OrderID`, `o0`.`ProductID`"); } /// @@ -328,7 +325,7 @@ await AssertQuery( AssertSql( @"@__p_0='10' -SELECT `t`.`OrderID`, `t0`.`ProductID`, `t0`.`OrderID` +SELECT `t`.`OrderID`, `o0`.`ProductID`, `o0`.`OrderID` FROM ( SELECT `o`.`OrderID` FROM `Orders` AS `o` @@ -336,11 +333,8 @@ await AssertQuery( ORDER BY `o`.`OrderID` LIMIT @__p_0 ) AS `t` -LEFT JOIN ( - SELECT `o0`.`ProductID`, `o0`.`OrderID` - FROM `Order Details` AS `o0` -) AS `t0` ON `t`.`OrderID` = `t0`.`OrderID` -ORDER BY `t`.`OrderID`, `t0`.`ProductID`"); +LEFT JOIN `Order Details` AS `o0` ON `t`.`OrderID` = `o0`.`OrderID` +ORDER BY `t`.`OrderID`, `o0`.`ProductID`"); } public override Task Complex_nested_query_doesnt_try_binding_to_grandparent_when_parent_returns_complex_result(bool async) @@ -359,6 +353,121 @@ public override Task Complex_nested_query_doesnt_try_binding_to_grandparent_when } } + public override async Task Client_code_using_instance_method_throws(bool async) + { + Assert.Equal( + CoreStrings.ClientProjectionCapturingConstantInMethodInstance( + "Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query.NorthwindMiscellaneousQueryMySqlTest", + "InstanceMethod"), + (await Assert.ThrowsAsync( + () => base.Client_code_using_instance_method_throws(async))).Message); + + AssertSql(); + } + + public override async Task Client_code_using_instance_in_static_method(bool async) + { + Assert.Equal( + CoreStrings.ClientProjectionCapturingConstantInMethodArgument( + "Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query.NorthwindMiscellaneousQueryMySqlTest", + "StaticMethod"), + (await Assert.ThrowsAsync( + () => base.Client_code_using_instance_in_static_method(async))).Message); + + AssertSql(); + } + + public override async Task Client_code_using_instance_in_anonymous_type(bool async) + { + Assert.Equal( + CoreStrings.ClientProjectionCapturingConstantInTree( + "Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query.NorthwindMiscellaneousQueryMySqlTest"), + (await Assert.ThrowsAsync( + () => base.Client_code_using_instance_in_anonymous_type(async))).Message); + + AssertSql(); + } + + public override async Task Client_code_unknown_method(bool async) + { + await AssertTranslationFailedWithDetails( + () => base.Client_code_unknown_method(async), + CoreStrings.QueryUnableToTranslateMethod( + "Microsoft.EntityFrameworkCore.Query.NorthwindMiscellaneousQueryTestBase>", + nameof(UnknownMethod))); + + AssertSql(); + } + + public override async Task Entity_equality_through_subquery_composite_key(bool async) + { + var message = (await Assert.ThrowsAsync( + () => base.Entity_equality_through_subquery_composite_key(async))).Message; + + Assert.Equal( + CoreStrings.EntityEqualityOnCompositeKeyEntitySubqueryNotSupported("==", nameof(OrderDetail)), + message); + + AssertSql(); + } + + public override async Task Max_on_empty_sequence_throws(bool async) + { + await Assert.ThrowsAsync(() => base.Max_on_empty_sequence_throws(async)); + + AssertSql( + @"SELECT ( + SELECT MAX(`o`.`OrderID`) + FROM `Orders` AS `o` + WHERE `c`.`CustomerID` = `o`.`CustomerID`) AS `Max` +FROM `Customers` AS `c`"); + } + + public override async Task + Select_DTO_constructor_distinct_with_collection_projection_translated_to_server_with_binding_after_client_eval(bool async) + { + using var context = CreateContext(); + var actualQuery = context.Set() + .Where(o => o.OrderID < 10300) + .Select(o => new { A = new OrderCountDTO(o.CustomerID), o.CustomerID }) + .Distinct() + .Select(e => new { e.A, Orders = context.Set().Where(o => o.CustomerID == e.CustomerID) + .OrderBy(o => o.OrderID) // <-- added + .ToList() }); + + var actual = async + ? (await actualQuery.ToListAsync()).OrderBy(e => e.A.Id).ToList() + : actualQuery.ToList().OrderBy(e => e.A.Id).ToList(); + + var expected = Fixture.GetExpectedData().Set() + .Where(o => o.OrderID < 10300) + .Select(o => new { A = new OrderCountDTO(o.CustomerID), o.CustomerID }) + .Distinct() + .Select(e => new { e.A, Orders = Fixture.GetExpectedData().Set().Where(o => o.CustomerID == e.CustomerID) + .OrderBy(o => o.OrderID) // <-- added + .ToList() }) + .ToList().OrderBy(e => e.A.Id).ToList(); + + Assert.Equal(expected.Count, actual.Count); + for (var i = 0; i < expected.Count; i++) + { + Assert.Equal(expected[i].A.Id, actual[i].A.Id); + Assert.True(expected[i].Orders?.SequenceEqual(actual[i].Orders) ?? true); + } + + AssertSql( +""" +SELECT `t`.`CustomerID`, `o0`.`OrderID`, `o0`.`CustomerID`, `o0`.`EmployeeID`, `o0`.`OrderDate` +FROM ( + SELECT DISTINCT `o`.`CustomerID` + FROM `Orders` AS `o` + WHERE `o`.`OrderID` < 10300 +) AS `t` +LEFT JOIN `Orders` AS `o0` ON `t`.`CustomerID` = `o0`.`CustomerID` +ORDER BY `t`.`CustomerID`, `o0`.`OrderID` +"""); + } + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] public override Task DefaultIfEmpty_Sum_over_collection_navigation(bool async) { @@ -370,5 +479,37 @@ private void AssertSql(params string[] expected) protected override void ClearLog() => Fixture.TestSqlLoggerFactory.Clear(); + + private class OrderCountDTO + { + public string Id { get; set; } + public int Count { get; set; } + + public OrderCountDTO() + { + } + + public OrderCountDTO(string id) + { + Id = id; + Count = 0; + } + + public override bool Equals(object obj) + { + if (obj is null) + { + return false; + } + + return ReferenceEquals(this, obj) ? true : obj.GetType() == GetType() && Equals((OrderCountDTO)obj); + } + + private bool Equals(OrderCountDTO other) + => string.Equals(Id, other.Id) && Count == other.Count; + + public override int GetHashCode() + => HashCode.Combine(Id, Count); + } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSelectQueryMySqlTest.MySql.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSelectQueryMySqlTest.MySql.cs index 1744d239e..f9a2b1a2a 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSelectQueryMySqlTest.MySql.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSelectQueryMySqlTest.MySql.cs @@ -42,10 +42,13 @@ await AssertQuery( AssertSql( @"SELECT `t`.`Year`, `t`.`Count` FROM ( - SELECT EXTRACT(year FROM `o`.`OrderDate`) AS `Year`, COUNT(*) AS `Count`, `o`.`CustomerID`, EXTRACT(year FROM `o`.`OrderDate`) = 1995 AS `c` - FROM `Orders` AS `o` - WHERE (`o`.`CustomerID` = 'ALFKI') AND `o`.`OrderDate` IS NOT NULL - GROUP BY `o`.`CustomerID`, EXTRACT(year FROM `o`.`OrderDate`), `c` + SELECT `t`.`Year`, COUNT(*) AS `Count`, `t`.`CustomerID`, `t`.`Year` = 1995 AS `c` + FROM ( + SELECT `o`.`CustomerID`, EXTRACT(year FROM `o`.`OrderDate`) AS `Year` + FROM `Orders` AS `o` + WHERE (`o`.`CustomerID` = 'ALFKI') AND `o`.`OrderDate` IS NOT NULL + ) AS `t` + GROUP BY `t`.`CustomerID`, `t`.`Year`, `c` HAVING `c` ) AS `t` ORDER BY `t`.`Year`"); @@ -73,19 +76,25 @@ await AssertQueryScalar( assertOrder: true); AssertSql( - @"SELECT `t`.`c` + @"SELECT `t`.`Year` FROM ( - SELECT EXTRACT(year FROM `o`.`OrderDate`) AS `c`, `o`.`CustomerID`, EXTRACT(year FROM `o`.`OrderDate`) = 1995 AS `c0` - FROM `Orders` AS `o` - WHERE (`o`.`CustomerID` = 'ALFKI') AND `o`.`OrderDate` IS NOT NULL - GROUP BY `o`.`CustomerID`, EXTRACT(year FROM `o`.`OrderDate`), `c0` - HAVING `c0` + SELECT `t`.`Year`, `t`.`CustomerID`, `t`.`Year` = 1995 AS `c` + FROM ( + SELECT `o`.`CustomerID`, EXTRACT(year FROM `o`.`OrderDate`) AS `Year` + FROM `Orders` AS `o` + WHERE (`o`.`CustomerID` = 'ALFKI') AND `o`.`OrderDate` IS NOT NULL + ) AS `t` + GROUP BY `t`.`CustomerID`, `t`.`Year`, `c` + HAVING `c` ) AS `t` UNION ALL -SELECT EXTRACT(year FROM `o0`.`OrderDate`) AS `c` -FROM `Orders` AS `o0` -WHERE `o0`.`OrderDate` IS NOT NULL -GROUP BY EXTRACT(year FROM `o0`.`OrderDate`) +SELECT `t1`.`Key` AS `Year` +FROM ( + SELECT EXTRACT(year FROM `o0`.`OrderDate`) AS `Key` + FROM `Orders` AS `o0` + WHERE `o0`.`OrderDate` IS NOT NULL +) AS `t1` +GROUP BY `t1`.`Key` HAVING COUNT(*) > 0"); } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSelectQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSelectQueryMySqlTest.cs index 672447e21..ae81fb104 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSelectQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSelectQueryMySqlTest.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; @@ -103,6 +105,28 @@ public override async Task Select_datetime_millisecond_component(bool async) FROM `Orders` AS `o`"); } + public override async Task Correlated_collection_after_distinct_with_complex_projection_not_containing_original_identifier(bool async) + { + // Identifier set for Distinct. Issue #24440. + Assert.Equal( + RelationalStrings.InsufficientInformationToIdentifyElementOfCollectionJoin, + (await Assert.ThrowsAsync( + () => base.Correlated_collection_after_distinct_with_complex_projection_not_containing_original_identifier(async))) + .Message); + + AssertSql(); + } + + public override async Task SelectMany_with_collection_being_correlated_subquery_which_references_non_mapped_properties_from_inner_and_outer_entity(bool async) + { + await AssertUnableToTranslateEFProperty( + () => base + .SelectMany_with_collection_being_correlated_subquery_which_references_non_mapped_properties_from_inner_and_outer_entity( + async)); + + AssertSql(); + } + [ConditionalTheory(Skip = "issue #573")] public override Task Project_single_element_from_collection_with_OrderBy_Take_and_FirstOrDefault(bool async) { diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSetOperationsQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSetOperationsQueryMySqlTest.cs index 43a6df327..a20bc48b5 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSetOperationsQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSetOperationsQueryMySqlTest.cs @@ -1,9 +1,9 @@ -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; +using System; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; -using Pomelo.EntityFrameworkCore.MySql.Storage; using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; using Xunit; using Xunit.Abstractions; @@ -25,6 +25,17 @@ public NorthwindSetOperationsQueryMySqlTest( protected override bool CanExecuteQueryString => true; + public override async Task Client_eval_Union_FirstOrDefault(bool async) + { + // Client evaluation in projection. Issue #16243. + Assert.Equal( + RelationalStrings.SetOperationsNotAllowedAfterClientEvaluation, + (await Assert.ThrowsAsync( + () => base.Client_eval_Union_FirstOrDefault(async))).Message); + + AssertSql(); + } + [SupportedServerVersionCondition(nameof(ServerVersionSupport.ExceptIntercept))] public override async Task Intersect(bool async) { diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQueryMySqlTest.cs index 0bf3160d1..2e6fe75d5 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQueryMySqlTest.cs @@ -19,7 +19,7 @@ public NorthwindSplitIncludeNoTrackingQueryMySqlTest(NorthwindQueryMySqlFixture< public override Task Include_duplicate_collection_result_operator2(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // The order of the end result can be different as well. // This is the case on MariaDB. return AssertQuery( diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSplitIncludeQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSplitIncludeQueryMySqlTest.cs index b899b46e6..8dddf1814 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSplitIncludeQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSplitIncludeQueryMySqlTest.cs @@ -22,7 +22,7 @@ public NorthwindSplitIncludeQueryMySqlTest(NorthwindQueryMySqlFixture().Include(o => o.OrderDetails) select o) public override Task Include_duplicate_collection_result_operator(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // This is the case on MariaDB. return AssertQuery( async, @@ -113,7 +113,7 @@ from c2 in ss.Set().Include(c => c.Orders).OrderBy(c => c.CustomerID). public override Task Include_duplicate_collection_result_operator2(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // The order of the end result can be different as well. // This is the case on MariaDB. return AssertQuery( diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindSqlQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSqlQueryMySqlTest.cs new file mode 100644 index 000000000..2d76c98dd --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindSqlQueryMySqlTest.cs @@ -0,0 +1,81 @@ +using System.Data.Common; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using MySqlConnector; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class NorthwindSqlQueryMySqlTest : NorthwindSqlQueryTestBase> +{ + public NorthwindSqlQueryMySqlTest(NorthwindQueryMySqlFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task SqlQueryRaw_over_int(bool async) + { + await base.SqlQueryRaw_over_int(async); + + AssertSql( +""" +SELECT `ProductID` FROM `Products` +"""); + } + + public override async Task SqlQuery_composed_Contains(bool async) + { + await base.SqlQuery_composed_Contains(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` +FROM `Orders` AS `o` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `ProductID` AS `Value` FROM `Products` + ) AS `t` + WHERE CAST(`t`.`Value` AS signed) = `o`.`OrderID`) +"""); + } + + public override async Task SqlQuery_composed_Join(bool async) + { + await base.SqlQuery_composed_Join(async); + + AssertSql( +""" +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate`, CAST(`t`.`Value` AS signed) AS `p` +FROM `Orders` AS `o` +INNER JOIN ( + SELECT `ProductID` AS `Value` FROM `Products` +) AS `t` ON `o`.`OrderID` = CAST(`t`.`Value` AS signed) +"""); + } + + public override async Task SqlQuery_over_int_with_parameter(bool async) + { + await base.SqlQuery_over_int_with_parameter(async); + + AssertSql( +""" +p0='10' + +SELECT `ProductID` FROM `Products` WHERE `ProductID` = @p0 +"""); + } + + protected override DbParameter CreateDbParameter(string name, object value) + => new MySqlParameter { ParameterName = name, Value = value }; + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindStringIncludeQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindStringIncludeQueryMySqlTest.cs index 18bc0604a..326270bcf 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindStringIncludeQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindStringIncludeQueryMySqlTest.cs @@ -27,7 +27,7 @@ public override async Task Include_collection_with_last_no_orderby(bool async) public override Task Include_collection_with_multiple_conditional_order_by(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // This is the case on MariaDB. return AssertQuery( async, @@ -43,7 +43,7 @@ public override Task Include_collection_with_multiple_conditional_order_by(bool public override Task Include_duplicate_collection_result_operator(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // This is the case on MariaDB. return AssertQuery( async, @@ -61,7 +61,7 @@ from c2 in ss.Set().Include(c => c.Orders).OrderBy(c => c.CustomerID). public override Task Include_duplicate_collection_result_operator2(bool async) { - // The order of `Orders` can be different, becaues it is not explicitly sorted. + // The order of `Orders` can be different, because it is not explicitly sorted. // The order of the end result can be different as well. // This is the case on MariaDB. return AssertQuery( diff --git a/test/EFCore.MySql.FunctionalTests/Query/NorthwindWhereQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/NorthwindWhereQueryMySqlTest.cs index 2afe7a27a..a0992358e 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/NorthwindWhereQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/NorthwindWhereQueryMySqlTest.cs @@ -570,6 +570,86 @@ await AssertQuery( WHERE @__Concat_0 = `c`.`CompanyName`"); } + public override async Task Where_bitwise_xor(bool async) + { + // Cannot eval 'where (([c].CustomerID == \"ALFKI\") ^ True)'. Issue #16645. + await AssertTranslationFailed(() => base.Where_bitwise_xor(async)); + + AssertSql(); + } + + public override async Task Where_compare_constructed_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_constructed_equal(async)); + + AssertSql(); + } + + public override async Task Where_compare_constructed_multi_value_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_constructed_multi_value_equal(async)); + + AssertSql(); + } + + public override async Task Where_compare_constructed_multi_value_not_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_constructed_multi_value_not_equal(async)); + + AssertSql(); + } + + public override async Task Where_compare_tuple_create_constructed_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_tuple_create_constructed_equal(async)); + + AssertSql(); + } + + public override async Task Where_compare_tuple_create_constructed_multi_value_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_tuple_create_constructed_multi_value_equal(async)); + + AssertSql(); + } + + public override async Task Where_compare_tuple_create_constructed_multi_value_not_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_tuple_create_constructed_multi_value_not_equal(async)); + + AssertSql(); + } + + public override async Task Where_compare_tuple_constructed_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_tuple_constructed_equal(async)); + + AssertSql(); + } + + public override async Task Where_compare_tuple_constructed_multi_value_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_tuple_constructed_multi_value_equal(async)); + + AssertSql(); + } + + public override async Task Where_compare_tuple_constructed_multi_value_not_equal(bool async) + { + // Anonymous type to constant comparison. Issue #14672. + await AssertTranslationFailed(() => base.Where_compare_tuple_constructed_multi_value_not_equal(async)); + + AssertSql(); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.MySql.FunctionalTests/Query/QueryNavigationsMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/QueryNavigationsMySqlTest.cs index b0364acff..f160d6714 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/QueryNavigationsMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/QueryNavigationsMySqlTest.cs @@ -1,6 +1,8 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure; +using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; using Xunit; using Xunit.Abstractions; @@ -33,10 +35,10 @@ public override Task Where_subquery_on_navigation2(bool async) return base.Where_subquery_on_navigation2(async); } - [ConditionalFact(Skip = "Issue #573")] - public override void Navigation_in_subquery_referencing_outer_query_with_client_side_result_operator_and_count() + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override Task Navigation_in_subquery_referencing_outer_query_with_client_side_result_operator_and_count(bool async) { - base.Navigation_in_subquery_referencing_outer_query_with_client_side_result_operator_and_count(); + return base.Navigation_in_subquery_referencing_outer_query_with_client_side_result_operator_and_count(async); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.cs index ece993fc2..5c8f5b440 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/SimpleQueryMySqlTest.cs @@ -4,6 +4,8 @@ using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure; +using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; // ReSharper disable InconsistentNaming namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query @@ -41,5 +43,17 @@ public override async Task Multiple_different_entity_type_from_different_namespa using var context = contextFactory.CreateContext(); var bad = context.Set().FromSqlRaw(@"SELECT cast(null as signed) AS MyValue").ToList(); // <-- MySQL uses `signed` instead of `int` in CAST() expressions } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override Task Group_by_multiple_aggregate_joining_different_tables(bool async) + { + return base.Group_by_multiple_aggregate_joining_different_tables(async); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override Task Group_by_multiple_aggregate_joining_different_tables_with_query_filter(bool async) + { + return base.Group_by_multiple_aggregate_joining_different_tables_with_query_filter(async); + } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/SpatialGeographyQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/SpatialGeographyQueryMySqlTest.cs index 7de267403..cbce16518 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/SpatialGeographyQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/SpatialGeographyQueryMySqlTest.cs @@ -16,6 +16,7 @@ namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query { + // TODO: Inherit from SpatialQueryRelationalTestBase. public class SpatialGeographyQueryMySqlTest : QueryTestBase { public SpatialGeographyQueryMySqlTest(SpatialGeographyQueryMySqlFixture fixture, ITestOutputHelper testOutputHelper) @@ -200,6 +201,7 @@ public virtual IQueryable Set() } } + // TODO: Inherit from SpatialQueryRelationalFixture. public class SpatialGeographyQueryMySqlFixture : SharedStoreFixtureBase, IQueryFixtureBase { private GeometryFactory _geometryFactory; @@ -256,14 +258,14 @@ public ISetSource GetExpectedData() => new SpatialGeographyData(_geometryFactory); // CHECK: Unused? - public IReadOnlyDictionary GetEntitySorters() + public IReadOnlyDictionary EntitySorters => new Dictionary> { { typeof(SpatialGeographyContext.City), e => ((SpatialGeographyContext.City)e)?.CityId }, }.ToDictionary(e => e.Key, e => (object)e.Value); // CHECK: Unused? - public IReadOnlyDictionary GetEntityAsserters() + public IReadOnlyDictionary EntityAsserters => new Dictionary> { { diff --git a/test/EFCore.MySql.FunctionalTests/Query/SpatialQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/SpatialQueryMySqlTest.cs index 338ebfc77..530286547 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/SpatialQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/SpatialQueryMySqlTest.cs @@ -1,10 +1,10 @@ using System.Linq; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.SpatialModel; +using NetTopologySuite.Geometries; +using NetTopologySuite.Geometries.Utilities; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; -using Pomelo.EntityFrameworkCore.MySql.Storage; using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; using Xunit; using Xunit.Abstractions; @@ -56,6 +56,28 @@ public override Task Relate(bool async) public override Task ConvexHull(bool async) => base.ConvexHull(async); + public override Task Combine_aggregate(bool async) + => AssertQuery( + async, + ss => ss.Set() + .Where(e => e.Point != null) + .GroupBy(e => e.Group) + .Select(g => new { Id = g.Key, Combined = GeometryCombiner.Combine(g.Select(e => e.Point) + .OrderBy(p => p.X).ThenBy(p => p.Y)) }), // <-- needs to be explicitly ordered to be deterministic + elementSorter: x => x.Id, + elementAsserter: (e, a) => + { + Assert.Equal(e.Id, a.Id); + + // Note that NTS returns a MultiPoint (which is a subclass of GeometryCollection), whereas SQL Server returns a + // GeometryCollection. + var eCollection = (GeometryCollection)e.Combined; + var aCollection = (GeometryCollection)a.Combined; + + Assert.Equal(eCollection.Geometries, aCollection.Geometries); + }); + + #region Not supported by MySQL and MariaDB public override Task Buffer_quadrantSegments(bool async) => Task.CompletedTask; diff --git a/test/EFCore.MySql.FunctionalTests/Query/SqlExecutorMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/SqlExecutorMySqlTest.cs index d92e846c0..1f145220b 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/SqlExecutorMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/SqlExecutorMySqlTest.cs @@ -15,7 +15,91 @@ public SqlExecutorMySqlTest(NorthwindQueryMySqlFixture fixt { } - [ConditionalFact] + protected virtual int DefaultStoredProcedureResult + => 0; + + protected virtual int DefaultSqlResult + => -1; + + public override void Executes_stored_procedure() + { + using var context = CreateContext(); + Assert.Equal(DefaultStoredProcedureResult, context.Database.ExecuteSqlRaw(TenMostExpensiveProductsSproc)); + } + + public override void Executes_stored_procedure_with_parameter() + { + using var context = CreateContext(); + var parameter = CreateDbParameter("@CustomerID", "ALFKI"); + + Assert.Equal(DefaultStoredProcedureResult, context.Database.ExecuteSqlRaw(CustomerOrderHistorySproc, parameter)); + } + + public override void Executes_stored_procedure_with_generated_parameter() + { + using var context = CreateContext(); + Assert.Equal(DefaultStoredProcedureResult, context.Database.ExecuteSqlRaw(CustomerOrderHistoryWithGeneratedParameterSproc, "ALFKI")); + } + + public override void Query_with_parameters_interpolated_2() + { + var city = "London"; + var contactTitle = "Sales Representative"; + + using var context = CreateContext(); + var actual = context.Database + .ExecuteSql( + $@"SELECT COUNT(*) FROM `Customers` WHERE `City` = {city} AND `ContactTitle` = {contactTitle}"); + + Assert.Equal(DefaultSqlResult, actual); + } + + public override void Query_with_DbParameters_interpolated_2() + { + var city = CreateDbParameter("city", "London"); + var contactTitle = CreateDbParameter("contactTitle", "Sales Representative"); + + using var context = CreateContext(); + var actual = context.Database + .ExecuteSql( + $@"SELECT COUNT(*) FROM `Customers` WHERE `City` = {city} AND `ContactTitle` = {contactTitle}"); + + Assert.Equal(DefaultSqlResult, actual); + } + + public override async Task Executes_stored_procedure_async() + { + using var context = CreateContext(); + Assert.Equal(DefaultStoredProcedureResult, await context.Database.ExecuteSqlRawAsync(TenMostExpensiveProductsSproc)); + } + + public override async Task Executes_stored_procedure_with_parameter_async() + { + using var context = CreateContext(); + var parameter = CreateDbParameter("@CustomerID", "ALFKI"); + + Assert.Equal(DefaultStoredProcedureResult, await context.Database.ExecuteSqlRawAsync(CustomerOrderHistorySproc, parameter)); + } + + public override async Task Executes_stored_procedure_with_generated_parameter_async() + { + using var context = CreateContext(); + Assert.Equal(DefaultStoredProcedureResult, await context.Database.ExecuteSqlRawAsync(CustomerOrderHistoryWithGeneratedParameterSproc, "ALFKI")); + } + + public override async Task Query_with_parameters_interpolated_async_2() + { + var city = "London"; + var contactTitle = "Sales Representative"; + + using var context = CreateContext(); + var actual = await context.Database + .ExecuteSqlAsync( + $@"SELECT COUNT(*) FROM `Customers` WHERE `City` = {city} AND `ContactTitle` = {contactTitle}"); + + Assert.Equal(DefaultSqlResult, actual); + } + public override void Query_with_parameters() { var city = "London"; @@ -27,11 +111,10 @@ public override void Query_with_parameters() .ExecuteSqlRaw( @"SELECT COUNT(*) FROM `Customers` WHERE `City` = {0} AND `ContactTitle` = {1}", city, contactTitle); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } } - [Fact] public override void Query_with_dbParameter_with_name() { var city = CreateDbParameter("@city", "London"); @@ -42,11 +125,10 @@ public override void Query_with_dbParameter_with_name() .ExecuteSqlRaw( @"SELECT COUNT(*) FROM `Customers` WHERE `City` = @city", city); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } } - [Fact] public override void Query_with_positional_dbParameter_with_name() { var city = CreateDbParameter("@city", "London"); @@ -57,11 +139,10 @@ public override void Query_with_positional_dbParameter_with_name() .ExecuteSqlRaw( @"SELECT COUNT(*) FROM `Customers` WHERE `City` = {0}", city); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } } - [Fact] public override void Query_with_positional_dbParameter_without_name() { var city = CreateDbParameter(name: null, value: "London"); @@ -72,11 +153,10 @@ public override void Query_with_positional_dbParameter_without_name() .ExecuteSqlRaw( @"SELECT COUNT(*) FROM `Customers` WHERE `City` = {0}", city); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } } - [Fact] public override void Query_with_dbParameters_mixed() { var city = "London"; @@ -91,17 +171,16 @@ public override void Query_with_dbParameters_mixed() .ExecuteSqlRaw( @"SELECT COUNT(*) FROM `Customers` WHERE `City` = {0} AND `ContactTitle` = @contactTitle", city, contactTitleParameter); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); actual = context.Database .ExecuteSqlRaw( @"SELECT COUNT(*) FROM `Customers` WHERE `City` = @city AND `ContactTitle` = {1}", cityParameter, contactTitle); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } } - [Fact] public override void Query_with_parameters_interpolated() { var city = "London"; @@ -113,11 +192,10 @@ public override void Query_with_parameters_interpolated() .ExecuteSqlInterpolated( $@"SELECT COUNT(*) FROM `Customers` WHERE `City` = {city} AND `ContactTitle` = {contactTitle}"); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } } - [ConditionalFact] public override async Task Query_with_parameters_async() { var city = "London"; @@ -129,11 +207,10 @@ public override async Task Query_with_parameters_async() .ExecuteSqlRawAsync( @"SELECT COUNT(*) FROM `Customers` WHERE `City` = {0} AND `ContactTitle` = {1}", city, contactTitle); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } } - [Fact] public override async Task Query_with_parameters_interpolated_async() { var city = "London"; @@ -145,7 +222,7 @@ public override async Task Query_with_parameters_interpolated_async() .ExecuteSqlInterpolatedAsync( $@"SELECT COUNT(*) FROM `Customers` WHERE `City` = {city} AND `ContactTitle` = {contactTitle}"); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } } @@ -159,7 +236,7 @@ public override void Query_with_DbParameters_interpolated() .ExecuteSqlInterpolated( $@"SELECT COUNT(*) FROM `Customers` WHERE `City` = {city} AND `ContactTitle` = {contactTitle}"); - Assert.Equal(-1, actual); + Assert.Equal(DefaultSqlResult, actual); } protected override DbParameter CreateDbParameter(string name, object value) diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCFiltersInheritanceQueryMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCFiltersInheritanceQueryMySqlFixture.cs new file mode 100644 index 000000000..d8a26b14a --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCFiltersInheritanceQueryMySqlFixture.cs @@ -0,0 +1,7 @@ +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCFiltersInheritanceQueryMySqlFixture : TPCInheritanceQueryMySqlFixture +{ + protected override bool EnableFilters + => true; +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCFiltersInheritanceQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCFiltersInheritanceQueryMySqlTest.cs new file mode 100644 index 000000000..2f2aa5f92 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCFiltersInheritanceQueryMySqlTest.cs @@ -0,0 +1,220 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCFiltersInheritanceQueryMySqlTest : TPCFiltersInheritanceQueryTestBase +{ + public TPCFiltersInheritanceQueryMySqlTest( + TPCFiltersInheritanceQueryMySqlFixture fixture, + ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Can_use_of_type_animal(bool async) + { + await base.Can_use_of_type_animal(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CountryId`, `t`.`Name`, `t`.`Species`, `t`.`EagleId`, `t`.`IsFlightless`, `t`.`Group`, `t`.`FoundOn`, `t`.`Discriminator` +FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` +) AS `t` +WHERE `t`.`CountryId` = 1 +ORDER BY `t`.`Species` +"""); + } + + public override async Task Can_use_is_kiwi(bool async) + { + await base.Can_use_is_kiwi(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CountryId`, `t`.`Name`, `t`.`Species`, `t`.`EagleId`, `t`.`IsFlightless`, `t`.`Group`, `t`.`FoundOn`, `t`.`Discriminator` +FROM ( + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` +) AS `t` +WHERE `t`.`CountryId` = 1 +"""); + } + + public override async Task Can_use_is_kiwi_with_other_predicate(bool async) + { + await base.Can_use_is_kiwi_with_other_predicate(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CountryId`, `t`.`Name`, `t`.`Species`, `t`.`EagleId`, `t`.`IsFlightless`, `t`.`Group`, `t`.`FoundOn`, `t`.`Discriminator` +FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` +) AS `t` +WHERE (`t`.`CountryId` = 1) AND ((`t`.`Discriminator` = 'Kiwi') AND (`t`.`CountryId` = 1)) +"""); + } + + public override async Task Can_use_is_kiwi_in_projection(bool async) + { + await base.Can_use_is_kiwi_in_projection(async); + + AssertSql( +""" +SELECT `t`.`Discriminator` = 'Kiwi' +FROM ( + SELECT `e`.`CountryId`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`CountryId`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` +) AS `t` +WHERE `t`.`CountryId` = 1 +"""); + } + + public override async Task Can_use_of_type_bird(bool async) + { + await base.Can_use_of_type_bird(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CountryId`, `t`.`Name`, `t`.`Species`, `t`.`EagleId`, `t`.`IsFlightless`, `t`.`Group`, `t`.`FoundOn`, `t`.`Discriminator` +FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` +) AS `t` +WHERE `t`.`CountryId` = 1 +ORDER BY `t`.`Species` +"""); + } + + public override async Task Can_use_of_type_bird_predicate(bool async) + { + await base.Can_use_of_type_bird_predicate(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CountryId`, `t`.`Name`, `t`.`Species`, `t`.`EagleId`, `t`.`IsFlightless`, `t`.`Group`, `t`.`FoundOn`, `t`.`Discriminator` +FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` +) AS `t` +WHERE (`t`.`CountryId` = 1) AND (`t`.`CountryId` = 1) +ORDER BY `t`.`Species` +"""); + } + + public override async Task Can_use_of_type_bird_with_projection(bool async) + { + await base.Can_use_of_type_bird_with_projection(async); + + AssertSql( +""" +SELECT `t`.`Name` +FROM ( + SELECT `e`.`CountryId`, `e`.`Name` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`CountryId`, `k`.`Name` + FROM `Kiwi` AS `k` +) AS `t` +WHERE `t`.`CountryId` = 1 +"""); + } + + public override async Task Can_use_of_type_bird_first(bool async) + { + await base.Can_use_of_type_bird_first(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CountryId`, `t`.`Name`, `t`.`Species`, `t`.`EagleId`, `t`.`IsFlightless`, `t`.`Group`, `t`.`FoundOn`, `t`.`Discriminator` +FROM ( + SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group`, NULL AS `FoundOn`, 'Eagle' AS `Discriminator` + FROM `Eagle` AS `e` + UNION ALL + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, NULL AS `Group`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` +) AS `t` +WHERE `t`.`CountryId` = 1 +ORDER BY `t`.`Species` +LIMIT 1 +"""); + } + + public override async Task Can_use_of_type_kiwi(bool async) + { + await base.Can_use_of_type_kiwi(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CountryId`, `t`.`Name`, `t`.`Species`, `t`.`EagleId`, `t`.`IsFlightless`, `t`.`FoundOn`, `t`.`Discriminator` +FROM ( + SELECT `k`.`Id`, `k`.`CountryId`, `k`.`Name`, `k`.`Species`, `k`.`EagleId`, `k`.`IsFlightless`, `k`.`FoundOn`, 'Kiwi' AS `Discriminator` + FROM `Kiwi` AS `k` +) AS `t` +WHERE `t`.`CountryId` = 1 +"""); + } + + public override async Task Can_use_derived_set(bool async) + { + await base.Can_use_derived_set(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group` +FROM `Eagle` AS `e` +WHERE `e`.`CountryId` = 1 +"""); + } + + public override async Task Can_use_IgnoreQueryFilters_and_GetDatabaseValues(bool async) + { + await base.Can_use_IgnoreQueryFilters_and_GetDatabaseValues(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group` +FROM `Eagle` AS `e` +LIMIT 2 +""", + // + """ +@__p_0='2' + +SELECT `e`.`Id`, `e`.`CountryId`, `e`.`Name`, `e`.`Species`, `e`.`EagleId`, `e`.`IsFlightless`, `e`.`Group` +FROM `Eagle` AS `e` +WHERE `e`.`Id` = @__p_0 +LIMIT 1 +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlFixture.cs new file mode 100644 index 000000000..a73e28a02 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlFixture.cs @@ -0,0 +1,43 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCGearsOfWarQueryMySqlFixture : TPCGearsOfWarQueryRelationalFixture, IQueryFixtureBase +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + { + var optionsBuilder = base.AddOptions(builder); + + new MySqlDbContextOptionsBuilder(optionsBuilder) + .EnableIndexOptimizedBooleanColumns(true); + + return optionsBuilder; + } + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity().HasIndex(e => e.IsAutomatic); + } + + public new ISetSource GetExpectedData() + { + var data = (GearsOfWarData)base.GetExpectedData(); + + foreach (var mission in data.Missions) + { + mission.Timeline = MySqlTestHelpers.GetExpectedValue(mission.Timeline); + } + + return data; + } +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlTest.cs new file mode 100644 index 000000000..508b7a734 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlTest.cs @@ -0,0 +1,13022 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure; +using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCGearsOfWarQueryMySqlTest : TPCGearsOfWarQueryRelationalTestBase +{ + public TPCGearsOfWarQueryMySqlTest(TPCGearsOfWarQueryMySqlFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + protected override bool CanExecuteQueryString + => true; + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Negate_on_binary_expression(bool async) + { + await base.Negate_on_binary_expression(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE `s`.`Id` = -(`s`.`Id` + `s`.`Id`) +"""); + } + + public override async Task Negate_on_column(bool async) + { + await base.Negate_on_column(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE `s`.`Id` = -`s`.`Id` +"""); + } + + public override async Task Double_negate_on_column(bool async) + { + await base.Double_negate_on_column(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE -(-`s`.`Id`) = `s`.`Id` +"""); + } + + public override async Task Negate_on_like_expression(bool async) + { + await base.Negate_on_like_expression(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE `s`.`Name` IS NOT NULL AND NOT (`s`.`Name` LIKE 'us%') +"""); + } + + public override async Task Entity_equality_empty(bool async) + { + await base.Entity_equality_empty(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE FALSE +"""); + } + + public override async Task Include_multiple_one_to_one_and_one_to_many(bool async) + { + await base.Include_multiple_one_to_one_and_one_to_many(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task Include_multiple_one_to_one_optional_and_one_to_one_required(bool async) + { + await base.Include_multiple_one_to_one_optional_and_one_to_one_required(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` +"""); + } + + public override async Task Include_multiple_circular(bool async) + { + await base.Include_multiple_circular(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `c`.`Name` = `t0`.`AssignedCityName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `c`.`Name`, `t0`.`Nickname` +"""); + } + + public override async Task Include_multiple_circular_with_filter(bool async) + { + await base.Include_multiple_circular_with_filter(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `c`.`Name` = `t0`.`AssignedCityName` +WHERE `t`.`Nickname` = 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `c`.`Name`, `t0`.`Nickname` +"""); + } + + public override async Task Include_using_alternate_key(bool async) + { + await base.Include_using_alternate_key(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +WHERE `t`.`Nickname` = 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Include_navigation_on_derived_type(bool async) + { + await base.Include_navigation_on_derived_type(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task String_based_Include_navigation_on_derived_type(bool async) + { + await base.String_based_Include_navigation_on_derived_type(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Select_Where_Navigation_Included(bool async) + { + await base.Select_Where_Navigation_Included(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE `t0`.`Nickname` = 'Marcus' +"""); + } + + public override async Task Include_with_join_reference1(bool async) + { + await base.Include_with_join_reference1(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Tags` AS `t0` ON (`t`.`SquadId` = `t0`.`GearSquadId`) AND (`t`.`Nickname` = `t0`.`GearNickName`) +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +"""); + } + + public override async Task Include_with_join_reference2(bool async) + { + await base.Include_with_join_reference2(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Tags` AS `t` +INNER JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearSquadId` = `t0`.`SquadId`) AND (`t`.`GearNickName` = `t0`.`Nickname`) +INNER JOIN `Cities` AS `c` ON `t0`.`CityOfBirthName` = `c`.`Name` +"""); + } + + public override async Task Include_with_join_collection1(bool async) + { + await base.Include_with_join_collection1(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Tags` AS `t0` ON (`t`.`SquadId` = `t0`.`GearSquadId`) AND (`t`.`Nickname` = `t0`.`GearNickName`) +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id` +"""); + } + + public override async Task Include_with_join_collection2(bool async) + { + await base.Include_with_join_collection2(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Id`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Tags` AS `t` +INNER JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearSquadId` = `t0`.`SquadId`) AND (`t`.`GearNickName` = `t0`.`Nickname`) +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task Include_where_list_contains_navigation(bool async) + { + await base.Include_where_list_contains_navigation(async); + + AssertSql( +""" +SELECT `t`.`Id` +FROM `Tags` AS `t` +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`GearNickName`, `t0`.`GearSquadId`, `t0`.`IssueDate`, `t0`.`Note` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE `t0`.`Id` IS NOT NULL AND `t0`.`Id` IN ('b39a6fba-9026-4d69-828e-fd7068673e57', '70534e05-782c-4052-8720-c2c54481ce5f', 'a8ad98f9-e023-4e2a-9a70-c2728455bd34', 'df36f493-463f-4123-83f9-6b135deeb7ba', '34c8d86e-a4ac-4be5-827f-584dda348a07', 'a7be028a-0cf2-448f-ab55-ce8bc5d8cf69') +"""); + } + + public override async Task Include_where_list_contains_navigation2(bool async) + { + await base.Include_where_list_contains_navigation2(async); + + AssertSql( +""" +SELECT `t`.`Id` +FROM `Tags` AS `t` +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`GearNickName`, `t0`.`GearSquadId`, `t0`.`IssueDate`, `t0`.`Note` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE `c`.`Location` IS NOT NULL AND `t0`.`Id` IN ('b39a6fba-9026-4d69-828e-fd7068673e57', '70534e05-782c-4052-8720-c2c54481ce5f', 'a8ad98f9-e023-4e2a-9a70-c2728455bd34', 'df36f493-463f-4123-83f9-6b135deeb7ba', '34c8d86e-a4ac-4be5-827f-584dda348a07', 'a7be028a-0cf2-448f-ab55-ce8bc5d8cf69') +"""); + } + + public override async Task Navigation_accessed_twice_outside_and_inside_subquery(bool async) + { + await base.Navigation_accessed_twice_outside_and_inside_subquery(async); + + AssertSql( +""" +SELECT `t`.`Id` +FROM `Tags` AS `t` +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE `t0`.`Id` IS NOT NULL AND `t0`.`Id` IN ('b39a6fba-9026-4d69-828e-fd7068673e57', '70534e05-782c-4052-8720-c2c54481ce5f', 'a8ad98f9-e023-4e2a-9a70-c2728455bd34', 'df36f493-463f-4123-83f9-6b135deeb7ba', '34c8d86e-a4ac-4be5-827f-584dda348a07', 'a7be028a-0cf2-448f-ab55-ce8bc5d8cf69') +"""); + } + + public override async Task Include_with_join_multi_level(bool async) + { + await base.Include_with_join_multi_level(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation`, `t0`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Tags` AS `t0` ON (`t`.`SquadId` = `t0`.`GearSquadId`) AND (`t`.`Nickname` = `t0`.`GearNickName`) +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t1` ON `c`.`Name` = `t1`.`AssignedCityName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `c`.`Name`, `t1`.`Nickname` +"""); + } + + public override async Task Include_with_join_and_inheritance1(bool async) + { + await base.Include_with_join_and_inheritance1(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Tags` AS `t` +INNER JOIN ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearSquadId` = `t0`.`SquadId`) AND (`t`.`GearNickName` = `t0`.`Nickname`) +INNER JOIN `Cities` AS `c` ON `t0`.`CityOfBirthName` = `c`.`Name` +"""); + } + + public override async Task Include_with_join_and_inheritance_with_orderby_before_and_after_include(bool async) + { + await base.Include_with_join_and_inheritance_with_orderby_before_and_after_include(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM `Tags` AS `t` +INNER JOIN ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearSquadId` = `t0`.`SquadId`) AND (`t`.`GearNickName` = `t0`.`Nickname`) +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t1` ON (`t0`.`Nickname` = `t1`.`LeaderNickname`) AND (`t0`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY `t0`.`HasSoulPatch`, `t0`.`Nickname` DESC, `t`.`Id`, `t0`.`SquadId`, `t1`.`Nickname` +"""); + } + + public override async Task Include_with_join_and_inheritance2(bool async) + { + await base.Include_with_join_and_inheritance2(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Tags` AS `t0` ON (`t`.`SquadId` = `t0`.`GearSquadId`) AND (`t`.`Nickname` = `t0`.`GearNickName`) +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id` +"""); + } + + public override async Task Include_with_join_and_inheritance3(bool async) + { + await base.Include_with_join_and_inheritance3(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM `Tags` AS `t` +INNER JOIN ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearSquadId` = `t0`.`SquadId`) AND (`t`.`GearNickName` = `t0`.`Nickname`) +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t1` ON (`t0`.`Nickname` = `t1`.`LeaderNickname`) AND (`t0`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Nickname` +"""); + } + + public override async Task Include_with_nested_navigation_in_order_by(bool async) + { + await base.Include_with_nested_navigation_in_order_by(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM `Weapons` AS `w` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` ON `w`.`OwnerFullName` = `t`.`FullName` +LEFT JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +WHERE (`t`.`Nickname` <> 'Paduk') OR `t`.`Nickname` IS NULL +ORDER BY `c`.`Name`, `w`.`Id` +"""); + } + + public override async Task Where_enum(bool async) + { + await base.Where_enum(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`Rank` = 4 +"""); + } + + public override async Task Where_nullable_enum_with_constant(bool async) + { + await base.Where_nullable_enum_with_constant(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` = 1 +"""); + } + + public override async Task Where_nullable_enum_with_null_constant(bool async) + { + await base.Where_nullable_enum_with_null_constant(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` IS NULL +"""); + } + + public override async Task Where_nullable_enum_with_non_nullable_parameter(bool async) + { + await base.Where_nullable_enum_with_non_nullable_parameter(async); + + AssertSql( +""" +@__ammunitionType_0='1' + +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` = @__ammunitionType_0 +"""); + } + + public override async Task Where_nullable_enum_with_nullable_parameter(bool async) + { + await base.Where_nullable_enum_with_nullable_parameter(async); + + AssertSql( +""" +@__ammunitionType_0='1' (Nullable = true) + +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` = @__ammunitionType_0 +""", + // + """ +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` IS NULL +"""); + } + + public override async Task Where_bitwise_and_enum(bool async) + { + await base.Where_bitwise_and_enum(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 2) > 0 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 2) = 2 +"""); + } + + public override async Task Where_bitwise_and_integral(bool async) + { + await base.Where_bitwise_and_integral(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 1) = 1 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (CAST(`t`.`Rank` AS signed) & 1) = 1 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (CAST(`t`.`Rank` AS signed) & 1) = 1 +"""); + } + + public override async Task Where_bitwise_and_nullable_enum_with_constant(bool async) + { + await base.Where_bitwise_and_nullable_enum_with_constant(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE (`w`.`AmmunitionType` & 1) > 0 +"""); + } + + public override async Task Where_bitwise_and_nullable_enum_with_null_constant(bool async) + { + await base.Where_bitwise_and_nullable_enum_with_null_constant(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE (`w`.`AmmunitionType` & NULL) > 0 +"""); + } + + public override async Task Where_bitwise_and_nullable_enum_with_non_nullable_parameter(bool async) + { + await base.Where_bitwise_and_nullable_enum_with_non_nullable_parameter(async); + + AssertSql( +""" +@__ammunitionType_0='1' + +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE (`w`.`AmmunitionType` & @__ammunitionType_0) > 0 +"""); + } + + public override async Task Where_bitwise_and_nullable_enum_with_nullable_parameter(bool async) + { + await base.Where_bitwise_and_nullable_enum_with_nullable_parameter(async); + + AssertSql( +""" +@__ammunitionType_0='1' (Nullable = true) + +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE (`w`.`AmmunitionType` & @__ammunitionType_0) > 0 +""", + // + """ +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE (`w`.`AmmunitionType` & NULL) > 0 +"""); + } + + public override async Task Where_bitwise_or_enum(bool async) + { + await base.Where_bitwise_or_enum(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` | 2) > 0 +"""); + } + + public override async Task Bitwise_projects_values_in_select(bool async) + { + await base.Bitwise_projects_values_in_select(async); + + AssertSql( +""" +SELECT (`t`.`Rank` & 2) = 2 AS `BitwiseTrue`, (`t`.`Rank` & 2) = 4 AS `BitwiseFalse`, `t`.`Rank` & 2 AS `BitwiseValue` +FROM ( + SELECT `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 2) = 2 +LIMIT 1 +"""); + } + + public override async Task Where_enum_has_flag(bool async) + { + await base.Where_enum_has_flag(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 2) = 2 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 18) = 18 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 1) = 1 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 1) = 1 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (2 & `t`.`Rank`) = `t`.`Rank` +"""); + } + + public override async Task Where_enum_has_flag_subquery(bool async) + { + await base.Where_enum_has_flag_subquery(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & COALESCE(( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1), 0)) = COALESCE(( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1), 0) +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (2 & COALESCE(( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1), 0)) = COALESCE(( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1), 0) +"""); + } + + public override async Task Where_enum_has_flag_subquery_with_pushdown(bool async) + { + await base.Where_enum_has_flag_subquery_with_pushdown(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE ((`t`.`Rank` & ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1)) = ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1)) OR ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1) IS NULL +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE ((2 & ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1)) = ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1)) OR ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1) IS NULL +"""); + } + + public override async Task Where_enum_has_flag_subquery_client_eval(bool async) + { + await base.Where_enum_has_flag_subquery_client_eval(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE ((`t`.`Rank` & ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1)) = ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1)) OR ( + SELECT `t0`.`Rank` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + ORDER BY `t0`.`Nickname`, `t0`.`SquadId` + LIMIT 1) IS NULL +"""); + } + + public override async Task Where_enum_has_flag_with_non_nullable_parameter(bool async) + { + await base.Where_enum_has_flag_with_non_nullable_parameter(async); + + AssertSql( +""" +@__parameter_0='2' + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & @__parameter_0) = @__parameter_0 +"""); + } + + public override async Task Where_has_flag_with_nullable_parameter(bool async) + { + await base.Where_has_flag_with_nullable_parameter(async); + + AssertSql( +""" +@__parameter_0='2' (Nullable = true) + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & @__parameter_0) = @__parameter_0 +"""); + } + + public override async Task Select_enum_has_flag(bool async) + { + await base.Select_enum_has_flag(async); + + AssertSql( +""" +SELECT (`t`.`Rank` & 2) = 2 AS `hasFlagTrue`, (`t`.`Rank` & 4) = 4 AS `hasFlagFalse` +FROM ( + SELECT `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & 2) = 2 +LIMIT 1 +"""); + } + + public override async Task Where_count_subquery_without_collision(bool async) + { + await base.Where_count_subquery_without_collision(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE ( + SELECT COUNT(*) + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`) = 2 +"""); + } + + public override async Task Where_any_subquery_without_collision(bool async) + { + await base.Where_any_subquery_without_collision(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE EXISTS ( + SELECT 1 + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`) +"""); + } + + public override async Task Select_inverted_boolean(bool async) + { + await base.Select_inverted_boolean(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`IsAutomatic` = FALSE AS `Manual` +FROM `Weapons` AS `w` +WHERE `w`.`IsAutomatic` = TRUE +"""); + } + + public override async Task Select_comparison_with_null(bool async) + { + await base.Select_comparison_with_null(async); + + AssertSql( +""" +@__ammunitionType_0='1' (Nullable = true) + +SELECT `w`.`Id`, (`w`.`AmmunitionType` = @__ammunitionType_0) AND `w`.`AmmunitionType` IS NOT NULL AS `Cartridge` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` = @__ammunitionType_0 +""", + // + """ +SELECT `w`.`Id`, `w`.`AmmunitionType` IS NULL AS `Cartridge` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` IS NULL +"""); + } + + public override async Task Select_null_parameter(bool async) + { + await base.Select_null_parameter(async); + + AssertSql( +""" +@__ammunitionType_0='1' (Nullable = true) + +SELECT `w`.`Id`, @__ammunitionType_0 AS `AmmoType` +FROM `Weapons` AS `w` +""", + // + """ +SELECT `w`.`Id`, NULL AS `AmmoType` +FROM `Weapons` AS `w` +""", + // + """ +@__ammunitionType_0='2' (Nullable = true) + +SELECT `w`.`Id`, @__ammunitionType_0 AS `AmmoType` +FROM `Weapons` AS `w` +""", + // + """ +SELECT `w`.`Id`, NULL AS `AmmoType` +FROM `Weapons` AS `w` +"""); + } + + public override async Task Select_ternary_operation_with_boolean(bool async) + { + await base.Select_ternary_operation_with_boolean(async); + + AssertSql( +""" +SELECT `w`.`Id`, CASE + WHEN `w`.`IsAutomatic` = TRUE THEN 1 + ELSE 0 +END AS `Num` +FROM `Weapons` AS `w` +"""); + } + + public override async Task Select_ternary_operation_with_inverted_boolean(bool async) + { + await base.Select_ternary_operation_with_inverted_boolean(async); + + AssertSql( +""" +SELECT `w`.`Id`, CASE + WHEN `w`.`IsAutomatic` = FALSE THEN 1 + ELSE 0 +END AS `Num` +FROM `Weapons` AS `w` +"""); + } + + public override async Task Select_ternary_operation_with_has_value_not_null(bool async) + { + await base.Select_ternary_operation_with_has_value_not_null(async); + + AssertSql( +""" +SELECT `w`.`Id`, CASE + WHEN `w`.`AmmunitionType` IS NOT NULL AND (`w`.`AmmunitionType` = 1) THEN 'Yes' + ELSE 'No' +END AS `IsCartridge` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` IS NOT NULL AND (`w`.`AmmunitionType` = 1) +"""); + } + + public override async Task Select_ternary_operation_multiple_conditions(bool async) + { + await base.Select_ternary_operation_multiple_conditions(async); + + AssertSql( +""" +SELECT `w`.`Id`, CASE + WHEN (`w`.`AmmunitionType` = 2) AND (`w`.`SynergyWithId` = 1) THEN 'Yes' + ELSE 'No' +END AS `IsCartridge` +FROM `Weapons` AS `w` +"""); + } + + public override async Task Select_ternary_operation_multiple_conditions_2(bool async) + { + await base.Select_ternary_operation_multiple_conditions_2(async); + + AssertSql( +""" +SELECT `w`.`Id`, CASE + WHEN (`w`.`IsAutomatic` = FALSE) AND (`w`.`SynergyWithId` = 1) THEN 'Yes' + ELSE 'No' +END AS `IsCartridge` +FROM `Weapons` AS `w` +"""); + } + + public override async Task Select_multiple_conditions(bool async) + { + await base.Select_multiple_conditions(async); + + AssertSql( +""" +SELECT `w`.`Id`, (`w`.`IsAutomatic` = FALSE) AND ((`w`.`SynergyWithId` = 1) AND `w`.`SynergyWithId` IS NOT NULL) AS `IsCartridge` +FROM `Weapons` AS `w` +"""); + } + + public override async Task Select_nested_ternary_operations(bool async) + { + await base.Select_nested_ternary_operations(async); + + AssertSql( +""" +SELECT `w`.`Id`, CASE + WHEN `w`.`IsAutomatic` = FALSE THEN CASE + WHEN `w`.`AmmunitionType` = 1 THEN 'ManualCartridge' + ELSE 'Manual' + END + ELSE 'Auto' +END AS `IsManualCartridge` +FROM `Weapons` AS `w` +"""); + } + + public override async Task Null_propagation_optimization1(bool async) + { + await base.Null_propagation_optimization1(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`LeaderNickname` = 'Marcus') AND `t`.`LeaderNickname` IS NOT NULL +"""); + } + + public override async Task Null_propagation_optimization2(bool async) + { + await base.Null_propagation_optimization2(async); + + // issue #16050 + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE CASE + WHEN `t`.`LeaderNickname` IS NULL THEN NULL + ELSE `t`.`LeaderNickname` IS NOT NULL AND (`t`.`LeaderNickname` LIKE '%us') +END = TRUE +"""); + } + + public override async Task Null_propagation_optimization3(bool async) + { + await base.Null_propagation_optimization3(async); + + // issue #16050 + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN `t`.`LeaderNickname` LIKE '%us' + ELSE NULL +END = TRUE +"""); + } + + public override async Task Null_propagation_optimization4(bool async) + { + await base.Null_propagation_optimization4(async); + + // issue #16050 + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (CASE + WHEN `t`.`LeaderNickname` IS NULL THEN NULL + ELSE CHAR_LENGTH(`t`.`LeaderNickname`) +END = 5) AND CASE + WHEN `t`.`LeaderNickname` IS NULL THEN NULL + ELSE CHAR_LENGTH(`t`.`LeaderNickname`) +END IS NOT NULL +"""); + } + + public override async Task Null_propagation_optimization5(bool async) + { + await base.Null_propagation_optimization5(async); + + // issue #16050 + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CHAR_LENGTH(`t`.`LeaderNickname`) + ELSE NULL +END = 5) AND CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CHAR_LENGTH(`t`.`LeaderNickname`) + ELSE NULL +END IS NOT NULL +"""); + } + + public override async Task Null_propagation_optimization6(bool async) + { + await base.Null_propagation_optimization6(async); + + // issue #16050 + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CHAR_LENGTH(`t`.`LeaderNickname`) + ELSE NULL +END = 5) AND CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CHAR_LENGTH(`t`.`LeaderNickname`) + ELSE NULL +END IS NOT NULL +"""); + } + + public override async Task Select_null_propagation_optimization7(bool async) + { + await base.Select_null_propagation_optimization7(async); + + // issue #16050 + AssertSql( +""" +SELECT CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CONCAT(`t`.`LeaderNickname`, `t`.`LeaderNickname`) + ELSE NULL +END +FROM ( + SELECT `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_null_propagation_optimization8(bool async) + { + await base.Select_null_propagation_optimization8(async); + + AssertSql( +""" +SELECT CONCAT(COALESCE(`t`.`LeaderNickname`, ''), COALESCE(`t`.`LeaderNickname`, '')) +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_null_propagation_optimization9(bool async) + { + await base.Select_null_propagation_optimization9(async); + + AssertSql( +""" +SELECT CHAR_LENGTH(`t`.`FullName`) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_null_propagation_negative1(bool async) + { + await base.Select_null_propagation_negative1(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CHAR_LENGTH(`t`.`Nickname`) = 5 + ELSE NULL +END +FROM ( + SELECT `g`.`Nickname`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_null_propagation_negative2(bool async) + { + await base.Select_null_propagation_negative2(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN `t0`.`LeaderNickname` + ELSE NULL +END +FROM ( + SELECT `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN ( + SELECT `g0`.`LeaderNickname` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`LeaderNickname` + FROM `Officers` AS `o0` +) AS `t0` +"""); + } + + public override async Task Select_null_propagation_negative3(bool async) + { + await base.Select_null_propagation_negative3(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, CASE + WHEN `t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL) THEN `t0`.`LeaderNickname` IS NOT NULL + ELSE NULL +END AS `Condition` +FROM ( + SELECT `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`LeaderNickname` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`LeaderNickname` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`HasSoulPatch` = TRUE +ORDER BY `t0`.`Nickname` +"""); + } + + public override async Task Select_null_propagation_negative4(bool async) + { + await base.Select_null_propagation_negative4(async); + + AssertSql( +""" +SELECT `t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL), `t0`.`Nickname` +FROM ( + SELECT `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`HasSoulPatch` = TRUE +ORDER BY `t0`.`Nickname` +"""); + } + + public override async Task Select_null_propagation_negative5(bool async) + { + await base.Select_null_propagation_negative5(async); + + AssertSql( +""" +SELECT `t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL), `t0`.`Nickname` +FROM ( + SELECT `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`HasSoulPatch` = TRUE +ORDER BY `t0`.`Nickname` +"""); + } + + public override async Task Select_null_propagation_negative6(bool async) + { + await base.Select_null_propagation_negative6(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CHAR_LENGTH(`t`.`LeaderNickname`) <> CHAR_LENGTH(`t`.`LeaderNickname`) + ELSE NULL +END +FROM ( + SELECT `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_null_propagation_negative7(bool async) + { + await base.Select_null_propagation_negative7(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN TRUE + ELSE NULL +END +FROM ( + SELECT `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_null_propagation_negative8(bool async) + { + await base.Select_null_propagation_negative8(async); + + AssertSql( +""" +SELECT CASE + WHEN `s`.`Id` IS NOT NULL THEN `c`.`Name` + ELSE NULL +END +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` +LEFT JOIN `Cities` AS `c` ON `t0`.`AssignedCityName` = `c`.`Name` +"""); + } + + public override async Task Select_null_propagation_negative9(bool async) + { + await base.Select_null_propagation_negative9(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN COALESCE(CHAR_LENGTH(`t`.`Nickname`) = 5, FALSE) + ELSE NULL +END +FROM ( + SELECT `g`.`Nickname`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_null_propagation_works_for_navigations_with_composite_keys(bool async) + { + await base.Select_null_propagation_works_for_navigations_with_composite_keys(async); + + AssertSql( +""" +SELECT `t0`.`Nickname` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Select_null_propagation_works_for_multiple_navigations_with_composite_keys(bool async) + { + await base.Select_null_propagation_works_for_multiple_navigations_with_composite_keys(async); + + AssertSql( +""" +SELECT CASE + WHEN `c`.`Name` IS NOT NULL THEN `c`.`Name` + ELSE NULL +END +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN `Tags` AS `t1` ON ((`t0`.`Nickname` = `t1`.`GearNickName`) OR (`t0`.`Nickname` IS NULL AND (`t1`.`GearNickName` IS NULL))) AND ((`t0`.`SquadId` = `t1`.`GearSquadId`) OR (`t0`.`SquadId` IS NULL AND (`t1`.`GearSquadId` IS NULL))) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName` + FROM `Officers` AS `o0` +) AS `t2` ON (`t1`.`GearNickName` = `t2`.`Nickname`) AND (`t1`.`GearSquadId` = `t2`.`SquadId`) +LEFT JOIN `Cities` AS `c` ON `t2`.`AssignedCityName` = `c`.`Name` +"""); + } + + public override async Task Select_conditional_with_anonymous_type_and_null_constant(bool async) + { + await base.Select_conditional_with_anonymous_type_and_null_constant(async); + + AssertSql( +""" +SELECT `t`.`LeaderNickname` IS NOT NULL, `t`.`HasSoulPatch` +FROM ( + SELECT `g`.`Nickname`, `g`.`HasSoulPatch`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`HasSoulPatch`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Select_conditional_with_anonymous_types(bool async) + { + await base.Select_conditional_with_anonymous_types(async); + + AssertSql( +""" +SELECT `t`.`LeaderNickname` IS NOT NULL, `t`.`Nickname`, `t`.`FullName` +FROM ( + SELECT `g`.`Nickname`, `g`.`FullName`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`FullName`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Where_conditional_equality_1(bool async) + { + await base.Where_conditional_equality_1(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname`, `g`.`HasSoulPatch`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`HasSoulPatch`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`LeaderNickname` IS NULL +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Where_conditional_equality_2(bool async) + { + await base.Where_conditional_equality_2(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname`, `g`.`HasSoulPatch`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`HasSoulPatch`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`LeaderNickname` IS NULL +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Where_conditional_equality_3(bool async) + { + await base.Where_conditional_equality_3(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Select_coalesce_with_anonymous_types(bool async) + { + await base.Select_coalesce_with_anonymous_types(async); + + AssertSql( +""" +SELECT `t`.`LeaderNickname`, `t`.`FullName` +FROM ( + SELECT `g`.`Nickname`, `g`.`FullName`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`FullName`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Where_compare_anonymous_types(bool async) + { + await base.Where_compare_anonymous_types(async); + + AssertSql(); + } + + public override async Task Where_member_access_on_anonymous_type(bool async) + { + await base.Where_member_access_on_anonymous_type(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`LeaderNickname` = 'Marcus' +"""); + } + + public override async Task Where_compare_anonymous_types_with_uncorrelated_members(bool async) + { + await base.Where_compare_anonymous_types_with_uncorrelated_members(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname` + FROM `Officers` AS `o` +) AS `t` +WHERE FALSE +"""); + } + + public override async Task Select_Where_Navigation_Scalar_Equals_Navigation_Scalar(bool async) + { + await base.Select_Where_Navigation_Scalar_Equals_Navigation_Scalar(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note`, `t0`.`Id`, `t0`.`GearNickName`, `t0`.`GearSquadId`, `t0`.`IssueDate`, `t0`.`Note` +FROM `Tags` AS `t` +CROSS JOIN `Tags` AS `t0` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t1` ON (`t`.`GearNickName` = `t1`.`Nickname`) AND (`t`.`GearSquadId` = `t1`.`SquadId`) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` +) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +WHERE (`t1`.`Nickname` = `t2`.`Nickname`) OR (`t1`.`Nickname` IS NULL AND (`t2`.`Nickname` IS NULL)) +"""); + } + + public override async Task Select_Singleton_Navigation_With_Member_Access(bool async) + { + await base.Select_Singleton_Navigation_With_Member_Access(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t0`.`Nickname` = 'Marcus') AND ((`t0`.`CityOfBirthName` <> 'Ephyra') OR `t0`.`CityOfBirthName` IS NULL) +"""); + } + + public override async Task Select_Where_Navigation(bool async) + { + await base.Select_Where_Navigation(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE `t0`.`Nickname` = 'Marcus' +"""); + } + + public override async Task Select_Where_Navigation_Equals_Navigation(bool async) + { + await base.Select_Where_Navigation_Equals_Navigation(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note`, `t0`.`Id`, `t0`.`GearNickName`, `t0`.`GearSquadId`, `t0`.`IssueDate`, `t0`.`Note` +FROM `Tags` AS `t` +CROSS JOIN `Tags` AS `t0` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t1` ON (`t`.`GearNickName` = `t1`.`Nickname`) AND (`t`.`GearSquadId` = `t1`.`SquadId`) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` +) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +WHERE ((`t1`.`Nickname` = `t2`.`Nickname`) OR (`t1`.`Nickname` IS NULL AND (`t2`.`Nickname` IS NULL))) AND ((`t1`.`SquadId` = `t2`.`SquadId`) OR (`t1`.`SquadId` IS NULL AND (`t2`.`SquadId` IS NULL))) +"""); + } + + public override async Task Select_Where_Navigation_Null(bool async) + { + await base.Select_Where_Navigation_Null(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE `t0`.`Nickname` IS NULL OR (`t0`.`SquadId` IS NULL) +"""); + } + + public override async Task Select_Where_Navigation_Null_Reverse(bool async) + { + await base.Select_Where_Navigation_Null_Reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE `t0`.`Nickname` IS NULL OR (`t0`.`SquadId` IS NULL) +"""); + } + + public override async Task Select_Where_Navigation_Scalar_Equals_Navigation_Scalar_Projected(bool async) + { + await base.Select_Where_Navigation_Scalar_Equals_Navigation_Scalar_Projected(async); + + AssertSql( +""" +SELECT `t`.`Id` AS `Id1`, `t0`.`Id` AS `Id2` +FROM `Tags` AS `t` +CROSS JOIN `Tags` AS `t0` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t1` ON (`t`.`GearNickName` = `t1`.`Nickname`) AND (`t`.`GearSquadId` = `t1`.`SquadId`) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` +) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +WHERE (`t1`.`Nickname` = `t2`.`Nickname`) OR (`t1`.`Nickname` IS NULL AND (`t2`.`Nickname` IS NULL)) +"""); + } + + public override async Task Optional_Navigation_Null_Coalesce_To_Clr_Type(bool async) + { + await base.Optional_Navigation_Null_Coalesce_To_Clr_Type(async); + + AssertSql( +""" +SELECT COALESCE(`w0`.`IsAutomatic`, FALSE) AS `IsAutomatic` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY `w`.`Id` +LIMIT 1 +"""); + } + + public override async Task Where_subquery_boolean(bool async) + { + await base.Where_subquery_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE COALESCE(( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1), FALSE) +"""); + } + + public override async Task Where_subquery_boolean_with_pushdown(bool async) + { + await base.Where_subquery_boolean_with_pushdown(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE ( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1) +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_firstordefault_boolean(bool async) + { + await base.Where_subquery_distinct_firstordefault_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND COALESCE(( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` + LIMIT 1), FALSE) +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_firstordefault_boolean_with_pushdown(bool async) + { + await base.Where_subquery_distinct_firstordefault_boolean_with_pushdown(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` + LIMIT 1) +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_first_boolean(bool async) + { + await base.Where_subquery_distinct_first_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` + LIMIT 1) +ORDER BY `t`.`Nickname` +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_singleordefault_boolean1(bool async) + { + await base.Where_subquery_distinct_singleordefault_boolean1(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND COALESCE(( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` LIKE '%Lancer%') + ) AS `t0` + LIMIT 1), FALSE) +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Where_subquery_distinct_singleordefault_boolean2(bool async) + { + await base.Where_subquery_distinct_singleordefault_boolean2(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND COALESCE(( + SELECT DISTINCT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` LIKE '%Lancer%') + LIMIT 1), FALSE) +ORDER BY `t`.`Nickname` +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_singleordefault_boolean_with_pushdown(bool async) + { + await base.Where_subquery_distinct_singleordefault_boolean_with_pushdown(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` LIKE '%Lancer%') + ) AS `t0` + LIMIT 1) +ORDER BY `t`.`Nickname` +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_lastordefault_boolean(bool async) + { + await base.Where_subquery_distinct_lastordefault_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE NOT (( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` DESC + LIMIT 1)) +ORDER BY `t`.`Nickname` +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_last_boolean(bool async) + { + await base.Where_subquery_distinct_last_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = FALSE) AND ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` DESC + LIMIT 1) +ORDER BY `t`.`Nickname` +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_orderby_firstordefault_boolean(bool async) + { + await base.Where_subquery_distinct_orderby_firstordefault_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND COALESCE(( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` + LIMIT 1), FALSE) +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_distinct_orderby_firstordefault_boolean_with_pushdown(bool async) + { + await base.Where_subquery_distinct_orderby_firstordefault_boolean_with_pushdown(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` + LIMIT 1) +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_union_firstordefault_boolean(bool async) + { + await base.Where_subquery_union_firstordefault_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + UNION + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `t`.`FullName` = `w0`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` + LIMIT 1) +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_join_firstordefault_boolean(bool async) + { + await base.Where_subquery_join_firstordefault_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND ( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + INNER JOIN ( + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `t`.`FullName` = `w0`.`OwnerFullName` + ) AS `t0` ON `w`.`Id` = `t0`.`Id` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1) +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_left_join_firstordefault_boolean(bool async) + { + await base.Where_subquery_left_join_firstordefault_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND ( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `t`.`FullName` = `w0`.`OwnerFullName` + ) AS `t0` ON `w`.`Id` = `t0`.`Id` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1) +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Where_subquery_concat_firstordefault_boolean(bool async) + { + await base.Where_subquery_concat_firstordefault_boolean(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + UNION ALL + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `t`.`FullName` = `w0`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` + LIMIT 1) +"""); + } + + public override async Task Concat_with_count(bool async) + { + await base.Concat_with_count(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + UNION ALL + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` +"""); + } + + public override async Task Concat_scalars_with_count(bool async) + { + await base.Concat_scalars_with_count(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + UNION ALL + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` +"""); + } + + public override async Task Concat_anonymous_with_count(bool async) + { + await base.Concat_anonymous_with_count(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t`.`Nickname` AS `Name` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + UNION ALL + SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator`, `t1`.`FullName` AS `Name` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` +) AS `t0` +"""); + } + + public override async Task Concat_with_scalar_projection(bool async) + { + await base.Concat_with_scalar_projection(async); + + AssertSql( +""" +SELECT `g`.`Nickname` +FROM `Gears` AS `g` +UNION ALL +SELECT `o`.`Nickname` +FROM `Officers` AS `o` +UNION ALL +SELECT `g0`.`Nickname` +FROM `Gears` AS `g0` +UNION ALL +SELECT `o0`.`Nickname` +FROM `Officers` AS `o0` +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Select_navigation_with_concat_and_count(bool async) + { + await base.Select_navigation_with_concat_and_count(async); + + AssertSql( +""" +SELECT ( + SELECT COUNT(*) + FROM ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + UNION ALL + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `t`.`FullName` = `w0`.`OwnerFullName` + ) AS `t0`) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = FALSE +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Concat_with_collection_navigations(bool async) + { + await base.Concat_with_collection_navigations(async); + + AssertSql( +""" +SELECT ( + SELECT COUNT(*) + FROM ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + UNION + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `t`.`FullName` = `w0`.`OwnerFullName` + ) AS `t0`) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Union_with_collection_navigations(bool async) + { + await base.Union_with_collection_navigations(async); + + AssertSql( +""" +SELECT ( + SELECT COUNT(*) + FROM ( + SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`) + UNION + SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`AssignedCityName`, `o1`.`CityOfBirthName`, `o1`.`FullName`, `o1`.`HasSoulPatch`, `o1`.`LeaderNickname`, `o1`.`LeaderSquadId`, `o1`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o1` + ) AS `t2` + WHERE (`t`.`Nickname` = `t2`.`LeaderNickname`) AND (`t`.`SquadId` = `t2`.`LeaderSquadId`) + ) AS `t0`) +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Select_subquery_distinct_firstordefault(bool async) + { + await base.Select_subquery_distinct_firstordefault(async); + + AssertSql( +""" +SELECT ( + SELECT `t0`.`Name` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ) AS `t0` + ORDER BY `t0`.`Id` + LIMIT 1) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +"""); + } + + public override async Task Singleton_Navigation_With_Member_Access(bool async) + { + await base.Singleton_Navigation_With_Member_Access(async); + + AssertSql( +""" +SELECT `t0`.`CityOfBirthName` AS `B` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`CityOfBirthName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`CityOfBirthName` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t0`.`Nickname` = 'Marcus') AND ((`t0`.`CityOfBirthName` <> 'Ephyra') OR `t0`.`CityOfBirthName` IS NULL) +"""); + } + + public override async Task GroupJoin_Composite_Key(bool async) + { + await base.GroupJoin_Composite_Key(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `Tags` AS `t` +INNER JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Join_navigation_translated_to_subquery_composite_key(bool async) + { + await base.Join_navigation_translated_to_subquery_composite_key(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t1`.`Note` +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN ( + SELECT `t0`.`Note`, `t2`.`FullName` + FROM `Tags` AS `t0` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +) AS `t1` ON `t`.`FullName` = `t1`.`FullName` +"""); + } + + public override async Task Join_with_order_by_on_inner_sequence_navigation_translated_to_subquery_composite_key(bool async) + { + await base.Join_with_order_by_on_inner_sequence_navigation_translated_to_subquery_composite_key(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t1`.`Note` +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN ( + SELECT `t0`.`Note`, `t2`.`FullName` + FROM `Tags` AS `t0` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +) AS `t1` ON `t`.`FullName` = `t1`.`FullName` +"""); + } + + public override async Task Join_with_order_by_without_skip_or_take(bool async) + { + await base.Join_with_order_by_without_skip_or_take(async); + + AssertSql( +""" +SELECT `w`.`Name`, `t`.`FullName` +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +"""); + } + + public override async Task Join_with_order_by_without_skip_or_take_nested(bool async) + { + await base.Join_with_order_by_without_skip_or_take_nested(async); + + AssertSql( +""" +SELECT `w`.`Name`, `t`.`FullName` +FROM `Squads` AS `s` +INNER JOIN ( + SELECT `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` ON `s`.`Id` = `t`.`SquadId` +INNER JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +"""); + } + + public override async Task Collection_with_inheritance_and_join_include_joined(bool async) + { + await base.Collection_with_inheritance_and_join_include_joined(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`GearNickName`, `t1`.`GearSquadId`, `t1`.`IssueDate`, `t1`.`Note` +FROM `Tags` AS `t` +INNER JOIN ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearSquadId` = `t0`.`SquadId`) AND (`t`.`GearNickName` = `t0`.`Nickname`) +LEFT JOIN `Tags` AS `t1` ON (`t0`.`Nickname` = `t1`.`GearNickName`) AND (`t0`.`SquadId` = `t1`.`GearSquadId`) +"""); + } + + public override async Task Collection_with_inheritance_and_join_include_source(bool async) + { + await base.Collection_with_inheritance_and_join_include_source(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t1`.`Id`, `t1`.`GearNickName`, `t1`.`GearSquadId`, `t1`.`IssueDate`, `t1`.`Note` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Tags` AS `t0` ON (`t`.`SquadId` = `t0`.`GearSquadId`) AND (`t`.`Nickname` = `t0`.`GearNickName`) +LEFT JOIN `Tags` AS `t1` ON (`t`.`Nickname` = `t1`.`GearNickName`) AND (`t`.`SquadId` = `t1`.`GearSquadId`) +"""); + } + + public override async Task Non_unicode_string_literal_is_used_for_non_unicode_column(bool async) + { + await base.Non_unicode_string_literal_is_used_for_non_unicode_column(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE `c`.`Location` = 'Unknown' +"""); + } + + public override async Task Non_unicode_string_literal_is_used_for_non_unicode_column_right(bool async) + { + await base.Non_unicode_string_literal_is_used_for_non_unicode_column_right(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE 'Unknown' = `c`.`Location` +"""); + } + + public override async Task Non_unicode_parameter_is_used_for_non_unicode_column(bool async) + { + await base.Non_unicode_parameter_is_used_for_non_unicode_column(async); + + AssertSql( +""" +@__value_0='Unknown' (Size = 4000) + +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE `c`.`Location` = @__value_0 +"""); + } + + public override async Task Non_unicode_string_literals_in_contains_is_used_for_non_unicode_column(bool async) + { + await base.Non_unicode_string_literals_in_contains_is_used_for_non_unicode_column(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE `c`.`Location` IN ('Unknown', 'Jacinto''s location', 'Ephyra''s location') +"""); + } + + public override async Task Non_unicode_string_literals_is_used_for_non_unicode_column_with_subquery(bool async) + { + await base.Non_unicode_string_literals_is_used_for_non_unicode_column_with_subquery(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE (`c`.`Location` = 'Unknown') AND (( + SELECT COUNT(*) + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`c`.`Name` = `t`.`CityOfBirthName`) AND (`t`.`Nickname` = 'Paduk')) = 1) +"""); + } + + public override async Task Non_unicode_string_literals_is_used_for_non_unicode_column_in_subquery(bool async) + { + await base.Non_unicode_string_literals_is_used_for_non_unicode_column_in_subquery(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +WHERE (`t`.`Nickname` = 'Marcus') AND (`c`.`Location` = 'Jacinto''s location') +"""); + } + + public override async Task Non_unicode_string_literals_is_used_for_non_unicode_column_with_contains(bool async) + { + await base.Non_unicode_string_literals_is_used_for_non_unicode_column_with_contains(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE `c`.`Location` LIKE '%Jacinto%' +"""); + } + + public override async Task Non_unicode_string_literals_is_used_for_non_unicode_column_with_concat(bool async) + { + await base.Non_unicode_string_literals_is_used_for_non_unicode_column_with_concat(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE CONCAT(COALESCE(`c`.`Location`, ''), 'Added') LIKE '%Add%' +"""); + } + + public override void Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result1() + { + base.Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result1(); + + // Issue#16897 + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override void Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result2() + { + base.Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result2(); + + // Issue#16897 + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result3(bool async) + { + await base.Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result3(async); + + // Issue#16897 + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w0` ON `t`.`FullName` = `w0`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id` +"""); + } + + public override async Task Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result4(bool async) + { + await base.Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_coalesce_result4(async); + + // Issue#16897 + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId`, `w1`.`Id`, `w1`.`AmmunitionType`, `w1`.`IsAutomatic`, `w1`.`Name`, `w1`.`OwnerFullName`, `w1`.`SynergyWithId`, `w2`.`Id`, `w2`.`AmmunitionType`, `w2`.`IsAutomatic`, `w2`.`Name`, `w2`.`OwnerFullName`, `w2`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w0` ON `t0`.`FullName` = `w0`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w1` ON `t0`.`FullName` = `w1`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w2` ON `t`.`FullName` = `w2`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id`, `w0`.`Id`, `w1`.`Id` +"""); + } + + public override async Task Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_inheritance_and_coalesce_result(bool async) + { + await base.Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_inheritance_and_coalesce_result(async); + + // Issue#16897 + AssertSql( +$""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w0` ON `t`.`FullName` = `w0`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id` +"""); + } + + public override async Task Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_conditional_result(bool async) + { + await base.Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_conditional_result(async); + + // Issue#16897 + AssertSql( +""" +SELECT `t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL), `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w0` ON `t`.`FullName` = `w0`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id` +"""); + } + + public override async Task Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_complex_projection_result(bool async) + { + await base.Include_on_GroupJoin_SelectMany_DefaultIfEmpty_with_complex_projection_result(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId`, `w1`.`Id`, `w1`.`AmmunitionType`, `w1`.`IsAutomatic`, `w1`.`Name`, `w1`.`OwnerFullName`, `w1`.`SynergyWithId`, `w2`.`Id`, `w2`.`AmmunitionType`, `w2`.`IsAutomatic`, `w2`.`Name`, `w2`.`OwnerFullName`, `w2`.`SynergyWithId`, `t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL), `w3`.`Id`, `w3`.`AmmunitionType`, `w3`.`IsAutomatic`, `w3`.`Name`, `w3`.`OwnerFullName`, `w3`.`SynergyWithId`, `w4`.`Id`, `w4`.`AmmunitionType`, `w4`.`IsAutomatic`, `w4`.`Name`, `w4`.`OwnerFullName`, `w4`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w0` ON `t0`.`FullName` = `w0`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w1` ON `t0`.`FullName` = `w1`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w2` ON `t`.`FullName` = `w2`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w3` ON `t0`.`FullName` = `w3`.`OwnerFullName` +LEFT JOIN `Weapons` AS `w4` ON `t`.`FullName` = `w4`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id`, `w0`.`Id`, `w1`.`Id`, `w2`.`Id`, `w3`.`Id` +"""); + } + + public override async Task Coalesce_operator_in_predicate(bool async) + { + await base.Coalesce_operator_in_predicate(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE COALESCE(`w`.`IsAutomatic`, FALSE) +"""); + } + + public override async Task Coalesce_operator_in_predicate_with_other_conditions(bool async) + { + await base.Coalesce_operator_in_predicate_with_other_conditions(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE (`w`.`AmmunitionType` = 1) AND COALESCE(`w`.`IsAutomatic`, FALSE) +"""); + } + + public override async Task Coalesce_operator_in_projection_with_other_conditions(bool async) + { + await base.Coalesce_operator_in_projection_with_other_conditions(async); + + AssertSql( +""" +SELECT ((`w`.`AmmunitionType` = 1) AND `w`.`AmmunitionType` IS NOT NULL) AND COALESCE(`w`.`IsAutomatic`, FALSE) +FROM `Weapons` AS `w` +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_predicate(bool async) + { + await base.Optional_navigation_type_compensation_works_with_predicate(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE ((`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL) AND (`t0`.`HasSoulPatch` = TRUE) +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_predicate2(bool async) + { + await base.Optional_navigation_type_compensation_works_with_predicate2(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE `t0`.`HasSoulPatch` = TRUE +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_predicate_negated(bool async) + { + await base.Optional_navigation_type_compensation_works_with_predicate_negated(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE `t0`.`HasSoulPatch` = FALSE +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_predicate_negated_complex1(bool async) + { + await base.Optional_navigation_type_compensation_works_with_predicate_negated_complex1(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE NOT (CASE + WHEN `t0`.`HasSoulPatch` = TRUE THEN TRUE + ELSE `t0`.`HasSoulPatch` +END) +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_predicate_negated_complex2(bool async) + { + await base.Optional_navigation_type_compensation_works_with_predicate_negated_complex2(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE NOT (CASE + WHEN `t0`.`HasSoulPatch` = FALSE THEN FALSE + ELSE `t0`.`HasSoulPatch` +END) +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_conditional_expression(bool async) + { + await base.Optional_navigation_type_compensation_works_with_conditional_expression(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t0`.`HasSoulPatch` = TRUE THEN TRUE + ELSE FALSE +END +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_binary_expression(bool async) + { + await base.Optional_navigation_type_compensation_works_with_binary_expression(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t0`.`HasSoulPatch` = TRUE) OR (`t`.`Note` LIKE '%Cole%') +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_binary_and_expression(bool async) + { + await base.Optional_navigation_type_compensation_works_with_binary_and_expression(async); + + AssertSql( +""" +SELECT (`t0`.`HasSoulPatch` = TRUE) AND (`t`.`Note` LIKE '%Cole%') +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_projection(bool async) + { + await base.Optional_navigation_type_compensation_works_with_projection(async); + + AssertSql( +""" +SELECT `t0`.`SquadId` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_projection_into_anonymous_type(bool async) + { + await base.Optional_navigation_type_compensation_works_with_projection_into_anonymous_type(async); + + AssertSql( +""" +SELECT `t0`.`SquadId` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_DTOs(bool async) + { + await base.Optional_navigation_type_compensation_works_with_DTOs(async); + + AssertSql( +""" +SELECT `t0`.`SquadId` AS `Id` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_list_initializers(bool async) + { + await base.Optional_navigation_type_compensation_works_with_list_initializers(async); + + AssertSql( +""" +SELECT `t0`.`SquadId`, `t0`.`SquadId` + 1 +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL +ORDER BY `t`.`Note` +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_array_initializers(bool async) + { + await base.Optional_navigation_type_compensation_works_with_array_initializers(async); + + AssertSql( +""" +SELECT `t0`.`SquadId` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_orderby(bool async) + { + await base.Optional_navigation_type_compensation_works_with_orderby(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL +ORDER BY `t0`.`SquadId` +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_all(bool async) + { + await base.Optional_navigation_type_compensation_works_with_all(async); + + AssertSql( +""" +SELECT NOT EXISTS ( + SELECT 1 + FROM `Tags` AS `t` + LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) + WHERE ((`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL) AND (`t0`.`HasSoulPatch` = FALSE)) +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_negated_predicate(bool async) + { + await base.Optional_navigation_type_compensation_works_with_negated_predicate(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE ((`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL) AND (`t0`.`HasSoulPatch` = FALSE) +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_contains(bool async) + { + await base.Optional_navigation_type_compensation_works_with_contains(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE ((`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL) AND EXISTS ( + SELECT 1 + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE `t1`.`SquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Optional_navigation_type_compensation_works_with_skip(bool async) + { + await base.Optional_navigation_type_compensation_works_with_skip(async); + + AssertSql(); + } + + public override async Task Optional_navigation_type_compensation_works_with_take(bool async) + { + await base.Optional_navigation_type_compensation_works_with_take(async); + + AssertSql(); + } + + public override async Task Select_correlated_filtered_collection(bool async) + { + await base.Select_correlated_filtered_collection(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `c`.`Name`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`CityOfBirthName`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`CityOfBirthName`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`w`.`Name` <> 'Lancer') OR `w`.`Name` IS NULL +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +WHERE `c`.`Name` IN ('Ephyra', 'Hanover') +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `c`.`Name` +"""); + } + + public override async Task Select_correlated_filtered_collection_with_composite_key(bool async) + { + await base.Select_correlated_filtered_collection_with_composite_key(async); + + AssertSql( +$""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE `t1`.`Nickname` <> 'Dom' +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Select_correlated_filtered_collection_works_with_caching(bool async) + { + await base.Select_correlated_filtered_collection_works_with_caching(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON `t`.`GearNickName` = `t0`.`Nickname` +ORDER BY `t`.`Note`, `t`.`Id`, `t0`.`Nickname` +"""); + } + + public override async Task Join_predicate_value_equals_condition(bool async) + { + await base.Join_predicate_value_equals_condition(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Weapons` AS `w` ON `w`.`SynergyWithId` IS NOT NULL +"""); + } + + public override async Task Join_predicate_value(bool async) + { + await base.Join_predicate_value(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Weapons` AS `w` ON `t`.`HasSoulPatch` = TRUE +"""); + } + + public override async Task Join_predicate_condition_equals_condition(bool async) + { + await base.Join_predicate_condition_equals_condition(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Weapons` AS `w` ON `w`.`SynergyWithId` IS NOT NULL +"""); + } + + public override async Task Left_join_predicate_value_equals_condition(bool async) + { + await base.Left_join_predicate_value_equals_condition(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `w`.`SynergyWithId` IS NOT NULL +"""); + } + + public override async Task Left_join_predicate_value(bool async) + { + await base.Left_join_predicate_value(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `t`.`HasSoulPatch` = TRUE +"""); + } + + public override async Task Left_join_predicate_condition_equals_condition(bool async) + { + await base.Left_join_predicate_condition_equals_condition(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `w`.`SynergyWithId` IS NOT NULL +"""); + } + + public override async Task Where_datetimeoffset_now(bool async) + { + await base.Where_datetimeoffset_now(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE `m`.`Timeline` <> UTC_TIMESTAMP() +"""); + } + + public override async Task Where_datetimeoffset_utcnow(bool async) + { + await base.Where_datetimeoffset_utcnow(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE `m`.`Timeline` <> UTC_TIMESTAMP() +"""); + } + + public override async Task Where_datetimeoffset_date_component(bool async) + { + await base.Where_datetimeoffset_date_component(async); + + AssertSql( +""" +@__Date_0='0001-01-01T00:00:00.0000000' (DbType = DateTime) + +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE CONVERT(`m`.`Timeline`, date) > @__Date_0 +"""); + } + + public override async Task Where_datetimeoffset_year_component(bool async) + { + await base.Where_datetimeoffset_year_component(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(year FROM `m`.`Timeline`) = 2 +"""); + } + + public override async Task Where_datetimeoffset_month_component(bool async) + { + await base.Where_datetimeoffset_month_component(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(month FROM `m`.`Timeline`) = 1 +"""); + } + + public override async Task Where_datetimeoffset_dayofyear_component(bool async) + { + await base.Where_datetimeoffset_dayofyear_component(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE DAYOFYEAR(`m`.`Timeline`) = 2 +"""); + } + + public override async Task Where_datetimeoffset_day_component(bool async) + { + await base.Where_datetimeoffset_day_component(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(day FROM `m`.`Timeline`) = 2 +"""); + } + + public override async Task Where_datetimeoffset_hour_component(bool async) + { + await base.Where_datetimeoffset_hour_component(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(hour FROM `m`.`Timeline`) = 10 +"""); + } + + public override async Task Where_datetimeoffset_minute_component(bool async) + { + await base.Where_datetimeoffset_minute_component(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(minute FROM `m`.`Timeline`) = 0 +"""); + } + + public override async Task Where_datetimeoffset_second_component(bool async) + { + await base.Where_datetimeoffset_second_component(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(second FROM `m`.`Timeline`) = 0 +"""); + } + + public override async Task Where_datetimeoffset_millisecond_component(bool async) + { + await base.Where_datetimeoffset_millisecond_component(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE (EXTRACT(microsecond FROM `m`.`Timeline`)) DIV (1000) = 0 +"""); + } + + public override async Task DateTimeOffset_DateAdd_AddMonths(bool async) + { + await base.DateTimeOffset_DateAdd_AddMonths(async); + + AssertSql( +""" +SELECT DATE_ADD(`m`.`Timeline`, INTERVAL CAST(1 AS signed) month) +FROM `Missions` AS `m` +"""); + } + + public override async Task DateTimeOffset_DateAdd_AddDays(bool async) + { + await base.DateTimeOffset_DateAdd_AddDays(async); + + AssertSql( +""" +SELECT DATE_ADD(`m`.`Timeline`, INTERVAL CAST(1.0 AS signed) day) +FROM `Missions` AS `m` +"""); + } + + public override async Task DateTimeOffset_DateAdd_AddHours(bool async) + { + await base.DateTimeOffset_DateAdd_AddHours(async); + + AssertSql( +""" +SELECT DATE_ADD(`m`.`Timeline`, INTERVAL CAST(1.0 AS signed) hour) +FROM `Missions` AS `m` +"""); + } + + public override async Task DateTimeOffset_DateAdd_AddMinutes(bool async) + { + await base.DateTimeOffset_DateAdd_AddMinutes(async); + + AssertSql( +""" +SELECT DATE_ADD(`m`.`Timeline`, INTERVAL CAST(1.0 AS signed) minute) +FROM `Missions` AS `m` +"""); + } + + public override async Task DateTimeOffset_DateAdd_AddSeconds(bool async) + { + await base.DateTimeOffset_DateAdd_AddSeconds(async); + + AssertSql( +""" +SELECT DATE_ADD(`m`.`Timeline`, INTERVAL CAST(1.0 AS signed) second) +FROM `Missions` AS `m` +"""); + } + + public override async Task DateTimeOffset_DateAdd_AddMilliseconds(bool async) + { + await base.DateTimeOffset_DateAdd_AddMilliseconds(async); + + AssertSql( +""" +SELECT DATE_ADD(`m`.`Timeline`, INTERVAL 1000 * CAST(300.0 AS signed) microsecond) +FROM `Missions` AS `m` +"""); + } + + public override async Task Where_datetimeoffset_milliseconds_parameter_and_constant(bool async) + { + var dateTimeOffset = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); + + // Literal where clause + var p = Expression.Parameter(typeof(Mission), "i"); + var dynamicWhere = Expression.Lambda>( + Expression.Equal( + Expression.Property(p, "Timeline"), + Expression.Constant(dateTimeOffset) + ), p); + + await AssertCount( + async, + ss => ss.Set().Where(dynamicWhere), + ss => ss.Set().Where(m => m.Timeline == dateTimeOffset)); + + AssertSql( +""" +SELECT COUNT(*) +FROM `Missions` AS `m` +WHERE `m`.`Timeline` = TIMESTAMP '1902-01-02 08:30:00.123456' +"""); + } + + public override async Task Orderby_added_for_client_side_GroupJoin_composite_dependent_to_principal_LOJ_when_incomplete_key_is_used( + bool async) + { + await base.Orderby_added_for_client_side_GroupJoin_composite_dependent_to_principal_LOJ_when_incomplete_key_is_used(async); + + AssertSql(); + } + + public override async Task Complex_predicate_with_AndAlso_and_nullable_bool_property(bool async) + { + await base.Complex_predicate_with_AndAlso_and_nullable_bool_property(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` ON `w`.`OwnerFullName` = `t`.`FullName` +WHERE (`w`.`Id` <> 50) AND (`t`.`HasSoulPatch` = FALSE) +"""); + } + + public override async Task Distinct_with_optional_navigation_is_translated_to_sql(bool async) + { + await base.Distinct_with_optional_navigation_is_translated_to_sql(async); + + AssertSql( +""" +SELECT DISTINCT `t`.`HasSoulPatch` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE (`t0`.`Note` <> 'Foo') OR `t0`.`Note` IS NULL +"""); + } + + public override async Task Sum_with_optional_navigation_is_translated_to_sql(bool async) + { + await base.Sum_with_optional_navigation_is_translated_to_sql(async); + + AssertSql( +""" +SELECT COALESCE(SUM(`t`.`SquadId`), 0) +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE (`t0`.`Note` <> 'Foo') OR `t0`.`Note` IS NULL +"""); + } + + public override async Task Count_with_optional_navigation_is_translated_to_sql(bool async) + { + await base.Count_with_optional_navigation_is_translated_to_sql(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE (`t0`.`Note` <> 'Foo') OR `t0`.`Note` IS NULL +"""); + } + + public override async Task FirstOrDefault_with_manually_created_groupjoin_is_translated_to_sql(bool async) + { + await base.FirstOrDefault_with_manually_created_groupjoin_is_translated_to_sql(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` ON `s`.`Id` = `t`.`SquadId` +WHERE `s`.`Name` = 'Kilo' +LIMIT 1 +"""); + } + + public override async Task Any_with_optional_navigation_as_subquery_predicate_is_translated_to_sql(bool async) + { + await base.Any_with_optional_navigation_as_subquery_predicate_is_translated_to_sql(async); + + AssertSql( +""" +SELECT `s`.`Name` +FROM `Squads` AS `s` +WHERE NOT (EXISTS ( + SELECT 1 + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) + WHERE (`s`.`Id` = `t`.`SquadId`) AND (`t0`.`Note` = 'Dom''s Tag'))) +"""); + } + + public override async Task All_with_optional_navigation_is_translated_to_sql(bool async) + { + await base.All_with_optional_navigation_is_translated_to_sql(async); + + AssertSql( +""" +SELECT NOT EXISTS ( + SELECT 1 + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) + WHERE (`t0`.`Note` = 'Foo') AND `t0`.`Note` IS NOT NULL) +"""); + } + + public override async Task Contains_with_local_nullable_guid_list_closure(bool async) + { + await base.Contains_with_local_nullable_guid_list_closure(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +WHERE `t`.`Id` IN ('d2c26679-562b-44d1-ab96-23d1775e0926', '23cbcf9b-ce14-45cf-aafa-2c2667ebfdd3', 'ab1b82d7-88db-42bd-a132-7eef9aa68af4') +"""); + } + + public override async Task Unnecessary_include_doesnt_get_added_complex_when_projecting_EF_Property(bool async) + { + await base.Unnecessary_include_doesnt_get_added_complex_when_projecting_EF_Property(async); + + AssertSql( +""" +SELECT `t`.`FullName` +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +ORDER BY `t`.`Rank` +"""); + } + + public override async Task Multiple_order_bys_are_properly_lifted_from_subquery_created_by_include(bool async) + { + await base.Multiple_order_bys_are_properly_lifted_from_subquery_created_by_include(async); + + AssertSql( +""" +SELECT `t`.`FullName` +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = FALSE +ORDER BY `t`.`FullName` +"""); + } + + public override async Task Order_by_is_properly_lifted_from_subquery_with_same_order_by_in_the_outer_query(bool async) + { + await base.Order_by_is_properly_lifted_from_subquery_with_same_order_by_in_the_outer_query(async); + + AssertSql( +""" +SELECT `t`.`FullName` +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = FALSE +ORDER BY `t`.`FullName` +"""); + } + + public override async Task Where_is_properly_lifted_from_subquery_created_by_include(bool async) + { + await base.Where_is_properly_lifted_from_subquery_created_by_include(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`GearNickName`, `t0`.`GearSquadId`, `t0`.`IssueDate`, `t0`.`Note` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE (`t`.`FullName` <> 'Augustus Cole') AND (`t`.`HasSoulPatch` = FALSE) +ORDER BY `t`.`FullName` +"""); + } + + public override async Task Subquery_is_lifted_from_main_from_clause_of_SelectMany(bool async) + { + await base.Subquery_is_lifted_from_main_from_clause_of_SelectMany(async); + + AssertSql( +""" +SELECT `t`.`FullName` AS `Name1`, `t0`.`FullName` AS `Name2` +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN ( + SELECT `g0`.`FullName`, `g0`.`HasSoulPatch` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`FullName`, `o0`.`HasSoulPatch` + FROM `Officers` AS `o0` +) AS `t0` +WHERE (`t`.`HasSoulPatch` = TRUE) AND (`t0`.`HasSoulPatch` = FALSE) +ORDER BY `t`.`FullName` +"""); + } + + public override async Task Subquery_containing_SelectMany_projecting_main_from_clause_gets_lifted(bool async) + { + await base.Subquery_containing_SelectMany_projecting_main_from_clause_gets_lifted(async); + + AssertSql( +""" +SELECT `t`.`FullName` +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN `Tags` AS `t0` +WHERE `t`.`HasSoulPatch` = TRUE +ORDER BY `t`.`FullName` +"""); + } + + public override async Task Subquery_containing_join_projecting_main_from_clause_gets_lifted(bool async) + { + await base.Subquery_containing_join_projecting_main_from_clause_gets_lifted(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Tags` AS `t0` ON `t`.`Nickname` = `t0`.`GearNickName` +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Subquery_containing_left_join_projecting_main_from_clause_gets_lifted(bool async) + { + await base.Subquery_containing_left_join_projecting_main_from_clause_gets_lifted(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON `t`.`Nickname` = `t0`.`GearNickName` +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Subquery_containing_join_gets_lifted_clashing_names(bool async) + { + await base.Subquery_containing_join_gets_lifted_clashing_names(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Tags` AS `t0` ON `t`.`Nickname` = `t0`.`GearNickName` +INNER JOIN `Tags` AS `t1` ON `t`.`Nickname` = `t1`.`GearNickName` +WHERE (`t0`.`GearNickName` <> 'Cole Train') OR `t0`.`GearNickName` IS NULL +ORDER BY `t`.`Nickname`, `t1`.`Id` +"""); + } + + public override async Task Subquery_created_by_include_gets_lifted_nested(bool async) + { + await base.Subquery_created_by_include_gets_lifted_nested(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +WHERE EXISTS ( + SELECT 1 + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`) AND (`t`.`HasSoulPatch` = FALSE) +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Subquery_is_lifted_from_additional_from_clause(bool async) + { + await base.Subquery_is_lifted_from_additional_from_clause(async); + + AssertSql( +""" +SELECT `t`.`FullName` AS `Name1`, `t0`.`FullName` AS `Name2` +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN ( + SELECT `g0`.`FullName`, `g0`.`HasSoulPatch` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`FullName`, `o0`.`HasSoulPatch` + FROM `Officers` AS `o0` +) AS `t0` +WHERE (`t`.`HasSoulPatch` = TRUE) AND (`t0`.`HasSoulPatch` = FALSE) +ORDER BY `t`.`FullName` +"""); + } + + public override async Task Subquery_with_result_operator_is_not_lifted(bool async) + { + await base.Subquery_with_result_operator_is_not_lifted(async); + + AssertSql( +""" +@__p_0='2' + +SELECT `t0`.`FullName` +FROM ( + SELECT `t`.`FullName`, `t`.`Rank` + FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`Rank` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = FALSE + ORDER BY `t`.`FullName` + LIMIT @__p_0 +) AS `t0` +ORDER BY `t0`.`Rank` +"""); + } + + public override async Task Skip_with_orderby_followed_by_orderBy_is_pushed_down(bool async) + { + await base.Skip_with_orderby_followed_by_orderBy_is_pushed_down(async); + + AssertSql( +""" +@__p_0='1' + +SELECT `t0`.`FullName` +FROM ( + SELECT `t`.`FullName`, `t`.`Rank` + FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`Rank` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = FALSE + ORDER BY `t`.`FullName` + LIMIT 18446744073709551610 OFFSET @__p_0 +) AS `t0` +ORDER BY `t0`.`Rank` +"""); + } + + [ConditionalTheory(Skip = "MySQL does not support LIMIT with a parameterized argument, unless the statement was prepared. The argument needs to be a numeric constant.")] + public override async Task Take_without_orderby_followed_by_orderBy_is_pushed_down1(bool async) + { + await base.Take_without_orderby_followed_by_orderBy_is_pushed_down1(async); + + AssertSql( +""" +@__p_0='999' + +SELECT `t0`.`FullName` +FROM ( + SELECT `t`.`FullName`, `t`.`Rank` + FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`Rank` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = FALSE + LIMIT @__p_0 +) AS `t0` +ORDER BY `t0`.`Rank` +"""); + } + + [ConditionalTheory(Skip = "MySQL does not support LIMIT with a parameterized argument, unless the statement was prepared. The argument needs to be a numeric constant.")] + public override async Task Take_without_orderby_followed_by_orderBy_is_pushed_down2(bool async) + { + await base.Take_without_orderby_followed_by_orderBy_is_pushed_down2(async); + + AssertSql( +""" +@__p_0='999' + +SELECT `t0`.`FullName` +FROM ( + SELECT `t`.`FullName`, `t`.`Rank` + FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`Rank` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = FALSE + LIMIT @__p_0 +) AS `t0` +ORDER BY `t0`.`Rank` +"""); + } + + [ConditionalTheory(Skip = "MySQL does not support LIMIT with a parameterized argument, unless the statement was prepared. The argument needs to be a numeric constant.")] + public override async Task Take_without_orderby_followed_by_orderBy_is_pushed_down3(bool async) + { + await base.Take_without_orderby_followed_by_orderBy_is_pushed_down3(async); + + AssertSql( +""" +@__p_0='999' + +SELECT `t0`.`FullName` +FROM ( + SELECT `t`.`FullName`, `t`.`Rank` + FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`Rank` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = FALSE + LIMIT @__p_0 +) AS `t0` +ORDER BY `t0`.`FullName`, `t0`.`Rank` +"""); + } + + public override async Task Select_length_of_string_property(bool async) + { + await base.Select_length_of_string_property(async); + + AssertSql( +""" +SELECT `w`.`Name`, CHAR_LENGTH(`w`.`Name`) AS `Length` +FROM `Weapons` AS `w` +"""); + } + + public override async Task Client_method_on_collection_navigation_in_outer_join_key(bool async) + { + await base.Client_method_on_collection_navigation_in_outer_join_key(async); + + AssertSql(); + } + + public override async Task Member_access_on_derived_entity_using_cast(bool async) + { + await base.Member_access_on_derived_entity_using_cast(async); + + AssertSql( +""" +SELECT `l`.`Name`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Member_access_on_derived_materialized_entity_using_cast(bool async) + { + await base.Member_access_on_derived_materialized_entity_using_cast(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Member_access_on_derived_entity_using_cast_and_let(bool async) + { + await base.Member_access_on_derived_entity_using_cast_and_let(async); + + AssertSql( +""" +SELECT `l`.`Name`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Property_access_on_derived_entity_using_cast(bool async) + { + await base.Property_access_on_derived_entity_using_cast(async); + + AssertSql( +""" +SELECT `l`.`Name`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Navigation_access_on_derived_entity_using_cast(bool async) + { + await base.Navigation_access_on_derived_entity_using_cast(async); + + AssertSql( +""" +SELECT `l`.`Name`, `l0`.`ThreatLevel` AS `Threat` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Navigation_access_on_derived_materialized_entity_using_cast(bool async) + { + await base.Navigation_access_on_derived_materialized_entity_using_cast(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated`, `l0`.`ThreatLevel` AS `Threat` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Navigation_access_via_EFProperty_on_derived_entity_using_cast(bool async) + { + await base.Navigation_access_via_EFProperty_on_derived_entity_using_cast(async); + + AssertSql( +""" +SELECT `l`.`Name`, `l0`.`ThreatLevel` AS `Threat` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Navigation_access_fk_on_derived_entity_using_cast(bool async) + { + await base.Navigation_access_fk_on_derived_entity_using_cast(async); + + AssertSql( +""" +SELECT `l`.`Name`, `l0`.`Name` AS `CommanderName` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Collection_navigation_access_on_derived_entity_using_cast(bool async) + { + await base.Collection_navigation_access_on_derived_entity_using_cast(async); + + AssertSql( +""" +SELECT `l`.`Name`, ( + SELECT COUNT(*) + FROM ( + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l0` + UNION ALL + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, `l1`.`DefeatedByNickname`, `l1`.`DefeatedBySquadId`, `l1`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l1` + ) AS `t` + WHERE `l`.`Id` = `t`.`LocustHordeId`) AS `LeadersCount` +FROM `LocustHordes` AS `l` +ORDER BY `l`.`Name` +"""); + } + + public override async Task Collection_navigation_access_on_derived_entity_using_cast_in_SelectMany(bool async) + { + await base.Collection_navigation_access_on_derived_entity_using_cast_in_SelectMany(async); + + AssertSql( +""" +SELECT `l`.`Name`, `t`.`Name` AS `LeaderName` +FROM `LocustHordes` AS `l` +INNER JOIN ( + SELECT `l0`.`Name`, `l0`.`LocustHordeId` + FROM `LocustLeaders` AS `l0` + UNION ALL + SELECT `l1`.`Name`, `l1`.`LocustHordeId` + FROM `LocustCommanders` AS `l1` +) AS `t` ON `l`.`Id` = `t`.`LocustHordeId` +ORDER BY `t`.`Name` +"""); + } + + public override async Task Include_on_derived_entity_using_OfType(bool async) + { + await base.Include_on_derived_entity_using_OfType(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated`, `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +LEFT JOIN ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` +) AS `t` ON `l`.`Id` = `t`.`LocustHordeId` +ORDER BY `l`.`Name`, `l`.`Id`, `l0`.`Name` +"""); + } + + public override async Task Distinct_on_subquery_doesnt_get_lifted(bool async) + { + await base.Distinct_on_subquery_doesnt_get_lifted(async); + + AssertSql( +""" +SELECT `t0`.`HasSoulPatch` +FROM ( + SELECT DISTINCT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` +) AS `t0` +"""); + } + + public override async Task Cast_result_operator_on_subquery_is_properly_lifted_to_a_convert(bool async) + { + await base.Cast_result_operator_on_subquery_is_properly_lifted_to_a_convert(async); + + AssertSql( +""" +SELECT `l`.`Eradicated` +FROM `LocustHordes` AS `l` +"""); + } + + public override async Task Comparing_two_collection_navigations_composite_key(bool async) + { + await base.Comparing_two_collection_navigations_composite_key(async); + + AssertSql( +""" +SELECT `t`.`Nickname` AS `Nickname1`, `t0`.`Nickname` AS `Nickname2` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` +) AS `t0` +WHERE (`t`.`Nickname` = `t0`.`Nickname`) AND (`t`.`SquadId` = `t0`.`SquadId`) +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Comparing_two_collection_navigations_inheritance(bool async) + { + await base.Comparing_two_collection_navigations_inheritance(async); + + AssertSql( +""" +SELECT `l`.`Name`, `t`.`Nickname` +FROM `LocustHordes` AS `l` +CROSS JOIN ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` +) AS `t0` ON (`l0`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`l0`.`DefeatedBySquadId` = `t0`.`SquadId`) +WHERE (`t`.`HasSoulPatch` = TRUE) AND ((`t0`.`Nickname` = `t`.`Nickname`) AND (`t0`.`SquadId` = `t`.`SquadId`)) +"""); + } + + public override async Task Comparing_entities_using_Equals_inheritance(bool async) + { + await base.Comparing_entities_using_Equals_inheritance(async); + + AssertSql( +""" +SELECT `t`.`Nickname` AS `Nickname1`, `t0`.`Nickname` AS `Nickname2` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN ( + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` +) AS `t0` +WHERE (`t`.`Nickname` = `t0`.`Nickname`) AND (`t`.`SquadId` = `t0`.`SquadId`) +ORDER BY `t`.`Nickname`, `t0`.`Nickname` +"""); + } + + public override async Task Contains_on_nullable_array_produces_correct_sql(bool async) + { + await base.Contains_on_nullable_array_produces_correct_sql(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Cities` AS `c` ON `t`.`AssignedCityName` = `c`.`Name` +WHERE (`t`.`SquadId` < 2) AND ((`c`.`Name` = 'Ephyra') OR `c`.`Name` IS NULL) +"""); + } + + public override async Task Optional_navigation_with_collection_composite_key(bool async) + { + await base.Optional_navigation_with_collection_composite_key(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (`t0`.`Discriminator` = 'Officer') AND (( + SELECT COUNT(*) + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE ((`t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL)) AND ((`t0`.`Nickname` = `t1`.`LeaderNickname`) AND (`t0`.`SquadId` = `t1`.`LeaderSquadId`))) AND (`t1`.`Nickname` = 'Dom')) > 0) +"""); + } + + public override async Task Select_null_conditional_with_inheritance(bool async) + { + await base.Select_null_conditional_with_inheritance(async); + + AssertSql( +""" +SELECT CASE + WHEN `l`.`CommanderName` IS NOT NULL THEN `l`.`CommanderName` + ELSE NULL +END +FROM `LocustHordes` AS `l` +"""); + } + + public override async Task Select_null_conditional_with_inheritance_negative(bool async) + { + await base.Select_null_conditional_with_inheritance_negative(async); + + AssertSql( +""" +SELECT CASE + WHEN `l`.`CommanderName` IS NOT NULL THEN `l`.`Eradicated` + ELSE NULL +END +FROM `LocustHordes` AS `l` +"""); + } + + public override async Task Project_collection_navigation_with_inheritance1(bool async) + { + await base.Project_collection_navigation_with_inheritance1(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l0`.`Name`, `l1`.`Id`, `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +LEFT JOIN `LocustHordes` AS `l1` ON `l0`.`Name` = `l1`.`CommanderName` +LEFT JOIN ( + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l2` + UNION ALL + SELECT `l3`.`Name`, `l3`.`LocustHordeId`, `l3`.`ThreatLevel`, `l3`.`ThreatLevelByte`, `l3`.`ThreatLevelNullableByte`, `l3`.`DefeatedByNickname`, `l3`.`DefeatedBySquadId`, `l3`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l3` +) AS `t` ON `l1`.`Id` = `t`.`LocustHordeId` +ORDER BY `l`.`Id`, `l0`.`Name`, `l1`.`Id` +"""); + } + + public override async Task Project_collection_navigation_with_inheritance2(bool async) + { + await base.Project_collection_navigation_with_inheritance2(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l0`.`Name`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` ON (`l0`.`DefeatedByNickname` = `t`.`Nickname`) AND (`l0`.`DefeatedBySquadId` = `t`.`SquadId`) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON ((`t`.`Nickname` = `t0`.`LeaderNickname`) OR (`t`.`Nickname` IS NULL AND (`t0`.`LeaderNickname` IS NULL))) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `l`.`Id`, `l0`.`Name`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Project_collection_navigation_with_inheritance3(bool async) + { + await base.Project_collection_navigation_with_inheritance3(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l0`.`Name`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` ON (`l0`.`DefeatedByNickname` = `t`.`Nickname`) AND (`l0`.`DefeatedBySquadId` = `t`.`SquadId`) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON ((`t`.`Nickname` = `t0`.`LeaderNickname`) OR (`t`.`Nickname` IS NULL AND (`t0`.`LeaderNickname` IS NULL))) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `l`.`Id`, `l0`.`Name`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Include_reference_on_derived_type_using_string(bool async) + { + await base.Include_reference_on_derived_type_using_string(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Include_reference_on_derived_type_using_string_nested1(bool async) + { + await base.Include_reference_on_derived_type_using_string_nested1(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` +"""); + } + + public override async Task Include_reference_on_derived_type_using_string_nested2(bool async) + { + await base.Include_reference_on_derived_type_using_string_nested2(async); + + AssertSql( +$""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator`, `t1`.`Name`, `t1`.`Location`, `t1`.`Nation` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +LEFT JOIN ( + SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t2` + INNER JOIN `Cities` AS `c` ON `t2`.`CityOfBirthName` = `c`.`Name` +) AS `t1` ON ((`t0`.`Nickname` = `t1`.`LeaderNickname`) OR (`t0`.`Nickname` IS NULL AND (`t1`.`LeaderNickname` IS NULL))) AND (`t0`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY `t`.`Name`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Nickname`, `t1`.`SquadId` +"""); + } + + public override async Task Include_reference_on_derived_type_using_lambda(bool async) + { + await base.Include_reference_on_derived_type_using_lambda(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Include_reference_on_derived_type_using_lambda_with_soft_cast(bool async) + { + await base.Include_reference_on_derived_type_using_lambda_with_soft_cast(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Include_reference_on_derived_type_using_lambda_with_tracking(bool async) + { + await base.Include_reference_on_derived_type_using_lambda_with_tracking(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Include_collection_on_derived_type_using_string(bool async) + { + await base.Include_collection_on_derived_type_using_string(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Include_collection_on_derived_type_using_lambda(bool async) + { + await base.Include_collection_on_derived_type_using_lambda(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Include_collection_on_derived_type_using_lambda_with_soft_cast(bool async) + { + await base.Include_collection_on_derived_type_using_lambda_with_soft_cast(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Include_base_navigation_on_derived_entity(bool async) + { + await base.Include_base_navigation_on_derived_entity(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`GearNickName`, `t0`.`GearSquadId`, `t0`.`IssueDate`, `t0`.`Note`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id` +"""); + } + + public override async Task ThenInclude_collection_on_derived_after_base_reference(bool async) + { + await base.ThenInclude_collection_on_derived_after_base_reference(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task ThenInclude_collection_on_derived_after_derived_reference(bool async) + { + await base.ThenInclude_collection_on_derived_after_derived_reference(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated`, `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` ON (`l0`.`DefeatedByNickname` = `t`.`Nickname`) AND (`l0`.`DefeatedBySquadId` = `t`.`SquadId`) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON ((`t`.`Nickname` = `t0`.`LeaderNickname`) OR (`t`.`Nickname` IS NULL AND (`t0`.`LeaderNickname` IS NULL))) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `l`.`Id`, `l0`.`Name`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task ThenInclude_collection_on_derived_after_derived_collection(bool async) + { + await base.ThenInclude_collection_on_derived_after_derived_collection(async); + + AssertSql( +$""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator`, `t1`.`Nickname0`, `t1`.`SquadId0`, `t1`.`AssignedCityName0`, `t1`.`CityOfBirthName0`, `t1`.`FullName0`, `t1`.`HasSoulPatch0`, `t1`.`LeaderNickname0`, `t1`.`LeaderSquadId0`, `t1`.`Rank0`, `t1`.`Discriminator0` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t2`.`Nickname` AS `Nickname0`, `t2`.`SquadId` AS `SquadId0`, `t2`.`AssignedCityName` AS `AssignedCityName0`, `t2`.`CityOfBirthName` AS `CityOfBirthName0`, `t2`.`FullName` AS `FullName0`, `t2`.`HasSoulPatch` AS `HasSoulPatch0`, `t2`.`LeaderNickname` AS `LeaderNickname0`, `t2`.`LeaderSquadId` AS `LeaderSquadId0`, `t2`.`Rank` AS `Rank0`, `t2`.`Discriminator` AS `Discriminator0` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + LEFT JOIN ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`AssignedCityName`, `g1`.`CityOfBirthName`, `g1`.`FullName`, `g1`.`HasSoulPatch`, `g1`.`LeaderNickname`, `g1`.`LeaderSquadId`, `g1`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`AssignedCityName`, `o1`.`CityOfBirthName`, `o1`.`FullName`, `o1`.`HasSoulPatch`, `o1`.`LeaderNickname`, `o1`.`LeaderSquadId`, `o1`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o1` + ) AS `t2` ON (`t0`.`Nickname` = `t2`.`LeaderNickname`) AND (`t0`.`SquadId` = `t2`.`LeaderSquadId`) +) AS `t1` ON (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Nickname0` +"""); + } + + public override async Task ThenInclude_reference_on_derived_after_derived_collection(bool async) + { + await base.ThenInclude_reference_on_derived_after_derived_collection(async); + + AssertSql( +$""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated`, `t1`.`Name`, `t1`.`LocustHordeId`, `t1`.`ThreatLevel`, `t1`.`ThreatLevelByte`, `t1`.`ThreatLevelNullableByte`, `t1`.`DefeatedByNickname`, `t1`.`DefeatedBySquadId`, `t1`.`HighCommandId`, `t1`.`Discriminator`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator0` +FROM `LocustHordes` AS `l` +LEFT JOIN ( + SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` AS `Discriminator0` + FROM ( + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL")} AS `DefeatedByNickname`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `DefeatedBySquadId`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `HighCommandId`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'LocustLeader'")} AS `Discriminator` + FROM `LocustLeaders` AS `l0` + UNION ALL + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, `l1`.`DefeatedByNickname`, `l1`.`DefeatedBySquadId`, `l1`.`HighCommandId`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'LocustCommander'")} AS `Discriminator` + FROM `LocustCommanders` AS `l1` + ) AS `t` + LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +) AS `t1` ON `l`.`Id` = `t1`.`LocustHordeId` +ORDER BY `l`.`Id`, `t1`.`Name`, `t1`.`Nickname` +"""); + } + + public override async Task Multiple_derived_included_on_one_method(bool async) + { + await base.Multiple_derived_included_on_one_method(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated`, `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` ON (`l0`.`DefeatedByNickname` = `t`.`Nickname`) AND (`l0`.`DefeatedBySquadId` = `t`.`SquadId`) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON ((`t`.`Nickname` = `t0`.`LeaderNickname`) OR (`t`.`Nickname` IS NULL AND (`t0`.`LeaderNickname` IS NULL))) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `l`.`Id`, `l0`.`Name`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Include_on_derived_multi_level(bool async) + { + await base.Include_on_derived_multi_level(async); + + AssertSql( +$""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t0`.`Id`, `t0`.`Banner`, `t0`.`Banner5`, `t0`.`InternalNumber`, `t0`.`Name`, `t0`.`SquadId0`, `t0`.`MissionId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator`, `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name`, `s0`.`SquadId` AS `SquadId0`, `s0`.`MissionId` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` + INNER JOIN `Squads` AS `s` ON `t1`.`SquadId` = `s`.`Id` + LEFT JOIN `SquadMissions` AS `s0` ON `s`.`Id` = `s0`.`SquadId` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`Id`, `t0`.`SquadId0` +"""); + } + + public override async Task Projecting_nullable_bool_in_conditional_works(bool async) + { + await base.Projecting_nullable_bool_in_conditional_works(async); + + AssertSql( +""" +SELECT CASE + WHEN `t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL) THEN `t0`.`HasSoulPatch` + ELSE FALSE +END AS `Prop` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Enum_ToString_is_client_eval(bool async) + { + await base.Enum_ToString_is_client_eval(async); + + AssertSql( +""" +SELECT `t`.`Rank` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +ORDER BY `t`.`SquadId`, `t`.`Nickname` +"""); + } + + public override async Task Correlated_collections_naked_navigation_with_ToList(bool async) + { + await base.Correlated_collections_naked_navigation_with_ToList(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collections_naked_navigation_with_ToList_followed_by_projecting_count(bool async) + { + await base.Correlated_collections_naked_navigation_with_ToList_followed_by_projecting_count(async); + + AssertSql( +""" +SELECT ( + SELECT COUNT(*) + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`) +FROM ( + SELECT `g`.`Nickname`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Correlated_collections_naked_navigation_with_ToArray(bool async) + { + await base.Correlated_collections_naked_navigation_with_ToArray(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collections_basic_projection(bool async) + { + await base.Correlated_collections_basic_projection(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`w`.`IsAutomatic` = TRUE) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL) +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collections_basic_projection_explicit_to_list(bool async) + { + await base.Correlated_collections_basic_projection_explicit_to_list(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`w`.`IsAutomatic` = TRUE) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL) +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collections_basic_projection_explicit_to_array(bool async) + { + await base.Correlated_collections_basic_projection_explicit_to_array(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`w`.`IsAutomatic` = TRUE) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL) +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collections_basic_projection_ordered(bool async) + { + await base.Correlated_collections_basic_projection_ordered(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`w`.`IsAutomatic` = TRUE) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL) +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Name` DESC +"""); + } + + public override async Task Correlated_collections_basic_projection_composite_key(bool async) + { + await base.Correlated_collections_basic_projection_composite_key(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`FullName`, `t0`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Nickname`, `t1`.`FullName`, `t1`.`SquadId`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE `t1`.`HasSoulPatch` = FALSE +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +WHERE `t`.`Nickname` <> 'Foo' +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Correlated_collections_basic_projecting_single_property(bool async) + { + await base.Correlated_collections_basic_projecting_single_property(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Name`, `t0`.`Id` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Name`, `w`.`Id`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + WHERE (`w`.`IsAutomatic` = TRUE) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL) +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collections_basic_projecting_constant(bool async) + { + await base.Correlated_collections_basic_projecting_constant(async); + + AssertSql( +$""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`c`, `t0`.`Id` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT {MySqlTestHelpers.MySqlBug96947Workaround(@"'BFG'")} AS `c`, `w`.`Id`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + WHERE (`w`.`IsAutomatic` = TRUE) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL) +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collections_basic_projecting_constant_bool(bool async) + { + await base.Correlated_collections_basic_projecting_constant_bool(async); + + AssertSql( +$""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`c`, `t0`.`Id` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT {MySqlTestHelpers.MySqlBug96947Workaround(@"TRUE", "signed")} AS `c`, `w`.`Id`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + WHERE (`w`.`IsAutomatic` = TRUE) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL) +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collections_projection_of_collection_thru_navigation(bool async) + { + await base.Correlated_collections_projection_of_collection_thru_navigation(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `s`.`Id`, `t0`.`SquadId`, `t0`.`MissionId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` +LEFT JOIN ( + SELECT `s0`.`SquadId`, `s0`.`MissionId` + FROM `SquadMissions` AS `s0` + WHERE `s0`.`MissionId` <> 17 +) AS `t0` ON `s`.`Id` = `t0`.`SquadId` +WHERE `t`.`Nickname` <> 'Marcus' +ORDER BY `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `s`.`Id`, `t0`.`SquadId` +"""); + } + + public override async Task Correlated_collections_project_anonymous_collection_result(bool async) + { + await base.Correlated_collections_project_anonymous_collection_result(async); + + AssertSql( +""" +SELECT `s`.`Name`, `s`.`Id`, `t`.`FullName`, `t`.`Rank`, `t`.`Nickname`, `t`.`SquadId` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` ON `s`.`Id` = `t`.`SquadId` +WHERE `s`.`Id` < 20 +ORDER BY `s`.`Id`, `t`.`Nickname` +"""); + } + + public override async Task Correlated_collections_nested(bool async) + { + await base.Correlated_collections_nested(async); + + AssertSql( +""" +SELECT `s`.`Id`, `t0`.`SquadId`, `t0`.`MissionId`, `t0`.`Id`, `t0`.`SquadId0`, `t0`.`MissionId0` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `s0`.`SquadId`, `s0`.`MissionId`, `m`.`Id`, `t`.`SquadId` AS `SquadId0`, `t`.`MissionId` AS `MissionId0` + FROM `SquadMissions` AS `s0` + INNER JOIN `Missions` AS `m` ON `s0`.`MissionId` = `m`.`Id` + LEFT JOIN ( + SELECT `s1`.`SquadId`, `s1`.`MissionId` + FROM `SquadMissions` AS `s1` + WHERE `s1`.`SquadId` < 7 + ) AS `t` ON `m`.`Id` = `t`.`MissionId` + WHERE `s0`.`MissionId` < 42 +) AS `t0` ON `s`.`Id` = `t0`.`SquadId` +ORDER BY `s`.`Id`, `t0`.`SquadId`, `t0`.`MissionId`, `t0`.`Id`, `t0`.`SquadId0` +"""); + } + + public override async Task Correlated_collections_nested_mixed_streaming_with_buffer1(bool async) + { + await base.Correlated_collections_nested_mixed_streaming_with_buffer1(async); + + AssertSql( +""" +SELECT `s`.`Id`, `t0`.`SquadId`, `t0`.`MissionId`, `t0`.`Id`, `t0`.`SquadId0`, `t0`.`MissionId0` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `s0`.`SquadId`, `s0`.`MissionId`, `m`.`Id`, `t`.`SquadId` AS `SquadId0`, `t`.`MissionId` AS `MissionId0` + FROM `SquadMissions` AS `s0` + INNER JOIN `Missions` AS `m` ON `s0`.`MissionId` = `m`.`Id` + LEFT JOIN ( + SELECT `s1`.`SquadId`, `s1`.`MissionId` + FROM `SquadMissions` AS `s1` + WHERE `s1`.`SquadId` < 2 + ) AS `t` ON `m`.`Id` = `t`.`MissionId` + WHERE `s0`.`MissionId` < 3 +) AS `t0` ON `s`.`Id` = `t0`.`SquadId` +ORDER BY `s`.`Id`, `t0`.`SquadId`, `t0`.`MissionId`, `t0`.`Id`, `t0`.`SquadId0` +"""); + } + + public override async Task Correlated_collections_nested_mixed_streaming_with_buffer2(bool async) + { + await base.Correlated_collections_nested_mixed_streaming_with_buffer2(async); + + AssertSql( +""" +SELECT `s`.`Id`, `t0`.`SquadId`, `t0`.`MissionId`, `t0`.`Id`, `t0`.`SquadId0`, `t0`.`MissionId0` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `s0`.`SquadId`, `s0`.`MissionId`, `m`.`Id`, `t`.`SquadId` AS `SquadId0`, `t`.`MissionId` AS `MissionId0` + FROM `SquadMissions` AS `s0` + INNER JOIN `Missions` AS `m` ON `s0`.`MissionId` = `m`.`Id` + LEFT JOIN ( + SELECT `s1`.`SquadId`, `s1`.`MissionId` + FROM `SquadMissions` AS `s1` + WHERE `s1`.`SquadId` < 7 + ) AS `t` ON `m`.`Id` = `t`.`MissionId` + WHERE `s0`.`MissionId` < 42 +) AS `t0` ON `s`.`Id` = `t0`.`SquadId` +ORDER BY `s`.`Id`, `t0`.`SquadId`, `t0`.`MissionId`, `t0`.`Id`, `t0`.`SquadId0` +"""); + } + + public override async Task Correlated_collections_nested_with_custom_ordering(bool async) + { + await base.Correlated_collections_nested_with_custom_ordering(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t1`.`FullName`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t0`.`FullName`, `t0`.`Nickname`, `t0`.`SquadId`, `t2`.`Id`, `t2`.`AmmunitionType`, `t2`.`IsAutomatic`, `t2`.`Name`, `t2`.`OwnerFullName`, `t2`.`SynergyWithId`, `t0`.`Rank`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank` + FROM `Officers` AS `o0` + ) AS `t0` + LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`w`.`Name` <> 'Bar') OR `w`.`Name` IS NULL + ) AS `t2` ON `t0`.`FullName` = `t2`.`OwnerFullName` + WHERE `t0`.`FullName` <> 'Foo' +) AS `t1` ON (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY `t`.`HasSoulPatch` DESC, `t`.`Nickname`, `t`.`SquadId`, `t1`.`Rank`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`IsAutomatic` +"""); + } + + public override async Task Correlated_collections_same_collection_projected_multiple_times(bool async) + { + await base.Correlated_collections_same_collection_projected_multiple_times(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId`, `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `w`.`IsAutomatic` = TRUE +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +LEFT JOIN ( + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `w0`.`IsAutomatic` = TRUE +) AS `t1` ON `t`.`FullName` = `t1`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id` +"""); + } + + public override async Task Correlated_collections_similar_collection_projected_multiple_times(bool async) + { + await base.Correlated_collections_similar_collection_projected_multiple_times(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId`, `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `w`.`IsAutomatic` = TRUE +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +LEFT JOIN ( + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `w0`.`IsAutomatic` = FALSE +) AS `t1` ON `t`.`FullName` = `t1`.`OwnerFullName` +ORDER BY `t`.`Rank`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`OwnerFullName`, `t0`.`Id`, `t1`.`IsAutomatic` +"""); + } + + public override async Task Correlated_collections_different_collections_projected(bool async) + { + await base.Correlated_collections_different_collections_projected(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Name`, `t0`.`IsAutomatic`, `t0`.`Id`, `t1`.`Nickname`, `t1`.`Rank`, `t1`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Name`, `w`.`IsAutomatic`, `w`.`Id`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + WHERE `w`.`IsAutomatic` = TRUE +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank` + FROM `Officers` AS `o0` +) AS `t1` ON (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t1`.`FullName`, `t1`.`Nickname` +"""); + } + + public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys(bool async) + { + await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys(async); + + AssertSql( +$""" +SELECT `t`.`FullName` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`)) +ORDER BY `t`.`HasSoulPatch` DESC, `t0`.`Note` +"""); + } + + public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery(bool async) + { + await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`Id`, `t3`.`AmmunitionType`, `t3`.`IsAutomatic`, `t3`.`Name`, `t3`.`OwnerFullName`, `t3`.`SynergyWithId`, `t3`.`Nickname`, `t3`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` +) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t4`.`Nickname`, `t4`.`SquadId` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`FullName` + FROM `Officers` AS `o1` + ) AS `t4` ON `w`.`OwnerFullName` = `t4`.`FullName` +) AS `t3` ON `t2`.`FullName` = `t3`.`OwnerFullName` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`AssignedCityName`, `g1`.`CityOfBirthName`, `g1`.`FullName`, `g1`.`HasSoulPatch`, `g1`.`LeaderNickname`, `g1`.`LeaderSquadId`, `g1`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o2`.`Nickname`, `o2`.`SquadId`, `o2`.`AssignedCityName`, `o2`.`CityOfBirthName`, `o2`.`FullName`, `o2`.`HasSoulPatch`, `o2`.`LeaderNickname`, `o2`.`LeaderSquadId`, `o2`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o2` + ) AS `t1` + WHERE (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`)) +ORDER BY `t`.`HasSoulPatch` DESC, `t0`.`Note`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`IsAutomatic`, `t3`.`Nickname` DESC, `t3`.`Id` +"""); + } + + public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_duplicated_orderings( + bool async) + { + await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_duplicated_orderings(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`Id`, `t3`.`AmmunitionType`, `t3`.`IsAutomatic`, `t3`.`Name`, `t3`.`OwnerFullName`, `t3`.`SynergyWithId`, `t3`.`Nickname`, `t3`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` +) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t4`.`Nickname`, `t4`.`SquadId` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`FullName` + FROM `Officers` AS `o1` + ) AS `t4` ON `w`.`OwnerFullName` = `t4`.`FullName` +) AS `t3` ON `t2`.`FullName` = `t3`.`OwnerFullName` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`AssignedCityName`, `g1`.`CityOfBirthName`, `g1`.`FullName`, `g1`.`HasSoulPatch`, `g1`.`LeaderNickname`, `g1`.`LeaderSquadId`, `g1`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o2`.`Nickname`, `o2`.`SquadId`, `o2`.`AssignedCityName`, `o2`.`CityOfBirthName`, `o2`.`FullName`, `o2`.`HasSoulPatch`, `o2`.`LeaderNickname`, `o2`.`LeaderSquadId`, `o2`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o2` + ) AS `t1` + WHERE (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`)) +ORDER BY `t`.`HasSoulPatch` DESC, `t0`.`Note`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`IsAutomatic`, `t3`.`Nickname` DESC, `t3`.`Id` +"""); + } + + public override async Task Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings( + bool async) + { + await base.Multiple_orderby_with_navigation_expansion_on_one_of_the_order_bys_inside_subquery_complex_orderings(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`Id`, `t3`.`AmmunitionType`, `t3`.`IsAutomatic`, `t3`.`Name`, `t3`.`OwnerFullName`, `t3`.`SynergyWithId`, `t3`.`Nickname`, `t3`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` +) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t4`.`Nickname`, `t4`.`SquadId`, ( + SELECT COUNT(*) + FROM `Weapons` AS `w0` + WHERE `t4`.`FullName` IS NOT NULL AND (`t4`.`FullName` = `w0`.`OwnerFullName`)) AS `c` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`FullName` + FROM `Officers` AS `o1` + ) AS `t4` ON `w`.`OwnerFullName` = `t4`.`FullName` +) AS `t3` ON `t2`.`FullName` = `t3`.`OwnerFullName` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`AssignedCityName`, `g1`.`CityOfBirthName`, `g1`.`FullName`, `g1`.`HasSoulPatch`, `g1`.`LeaderNickname`, `g1`.`LeaderSquadId`, `g1`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o2`.`Nickname`, `o2`.`SquadId`, `o2`.`AssignedCityName`, `o2`.`CityOfBirthName`, `o2`.`FullName`, `o2`.`HasSoulPatch`, `o2`.`LeaderNickname`, `o2`.`LeaderSquadId`, `o2`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o2` + ) AS `t1` + WHERE (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`)) +ORDER BY `t`.`HasSoulPatch` DESC, `t0`.`Note`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`Id` DESC, `t3`.`c`, `t3`.`Nickname` +"""); + } + + public override async Task Correlated_collections_multiple_nested_complex_collections(bool async) + { + await base.Correlated_collections_multiple_nested_complex_collections(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`FullName`, `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`Id`, `t3`.`Nickname0`, `t3`.`SquadId0`, `t3`.`Id0`, `t3`.`Name`, `t3`.`IsAutomatic`, `t3`.`Id1`, `t3`.`Nickname00`, `t3`.`HasSoulPatch`, `t3`.`SquadId00`, `t8`.`Id`, `t8`.`AmmunitionType`, `t8`.`IsAutomatic`, `t8`.`Name`, `t8`.`OwnerFullName`, `t8`.`SynergyWithId`, `t8`.`Nickname`, `t8`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` +) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) +LEFT JOIN ( + SELECT `t4`.`FullName`, `t4`.`Nickname`, `t4`.`SquadId`, `t5`.`Id`, `t5`.`Nickname` AS `Nickname0`, `t5`.`SquadId` AS `SquadId0`, `t5`.`Id0`, `t5`.`Name`, `t5`.`IsAutomatic`, `t5`.`Id1`, `t5`.`Nickname0` AS `Nickname00`, `t5`.`HasSoulPatch`, `t5`.`SquadId0` AS `SquadId00`, `t4`.`Rank`, `t5`.`IsAutomatic0`, `t4`.`LeaderNickname`, `t4`.`LeaderSquadId` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`FullName`, `o1`.`LeaderNickname`, `o1`.`LeaderSquadId`, `o1`.`Rank` + FROM `Officers` AS `o1` + ) AS `t4` + LEFT JOIN ( + SELECT `w`.`Id`, `t6`.`Nickname`, `t6`.`SquadId`, `s`.`Id` AS `Id0`, `w0`.`Name`, `w0`.`IsAutomatic`, `w0`.`Id` AS `Id1`, `t7`.`Nickname` AS `Nickname0`, `t7`.`HasSoulPatch`, `t7`.`SquadId` AS `SquadId0`, `w`.`IsAutomatic` AS `IsAutomatic0`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`FullName` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o2`.`Nickname`, `o2`.`SquadId`, `o2`.`FullName` + FROM `Officers` AS `o2` + ) AS `t6` ON `w`.`OwnerFullName` = `t6`.`FullName` + LEFT JOIN `Squads` AS `s` ON `t6`.`SquadId` = `s`.`Id` + LEFT JOIN `Weapons` AS `w0` ON `t6`.`FullName` = `w0`.`OwnerFullName` + LEFT JOIN ( + SELECT `g2`.`Nickname`, `g2`.`SquadId`, `g2`.`HasSoulPatch` + FROM `Gears` AS `g2` + UNION ALL + SELECT `o3`.`Nickname`, `o3`.`SquadId`, `o3`.`HasSoulPatch` + FROM `Officers` AS `o3` + ) AS `t7` ON `s`.`Id` = `t7`.`SquadId` + WHERE (`w`.`Name` <> 'Bar') OR `w`.`Name` IS NULL + ) AS `t5` ON `t4`.`FullName` = `t5`.`OwnerFullName` + WHERE `t4`.`FullName` <> 'Foo' +) AS `t3` ON (`t`.`Nickname` = `t3`.`LeaderNickname`) AND (`t`.`SquadId` = `t3`.`LeaderSquadId`) +LEFT JOIN ( + SELECT `w1`.`Id`, `w1`.`AmmunitionType`, `w1`.`IsAutomatic`, `w1`.`Name`, `w1`.`OwnerFullName`, `w1`.`SynergyWithId`, `t9`.`Nickname`, `t9`.`SquadId` + FROM `Weapons` AS `w1` + LEFT JOIN ( + SELECT `g3`.`Nickname`, `g3`.`SquadId`, `g3`.`FullName` + FROM `Gears` AS `g3` + UNION ALL + SELECT `o4`.`Nickname`, `o4`.`SquadId`, `o4`.`FullName` + FROM `Officers` AS `o4` + ) AS `t9` ON `w1`.`OwnerFullName` = `t9`.`FullName` +) AS `t8` ON `t2`.`FullName` = `t8`.`OwnerFullName` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `g4`.`Nickname`, `g4`.`SquadId`, `g4`.`AssignedCityName`, `g4`.`CityOfBirthName`, `g4`.`FullName`, `g4`.`HasSoulPatch`, `g4`.`LeaderNickname`, `g4`.`LeaderSquadId`, `g4`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g4` + UNION ALL + SELECT `o5`.`Nickname`, `o5`.`SquadId`, `o5`.`AssignedCityName`, `o5`.`CityOfBirthName`, `o5`.`FullName`, `o5`.`HasSoulPatch`, `o5`.`LeaderNickname`, `o5`.`LeaderSquadId`, `o5`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o5` + ) AS `t1` + WHERE (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`)) +ORDER BY `t`.`HasSoulPatch` DESC, `t0`.`Note`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`Rank`, `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`IsAutomatic0`, `t3`.`Id`, `t3`.`Nickname0`, `t3`.`SquadId0`, `t3`.`Id0`, `t3`.`Id1`, `t3`.`Nickname00`, `t3`.`SquadId00`, `t8`.`IsAutomatic`, `t8`.`Nickname` DESC, `t8`.`Id` +"""); + } + + public override async Task Correlated_collections_inner_subquery_selector_references_outer_qsre(bool async) + { + await base.Correlated_collections_inner_subquery_selector_references_outer_qsre(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`ReportName`, `t0`.`OfficerName`, `t0`.`Nickname`, `t0`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `t1`.`FullName` AS `ReportName`, `t`.`FullName` AS `OfficerName`, `t1`.`Nickname`, `t1`.`SquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`) +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Correlated_collections_inner_subquery_predicate_references_outer_qsre(bool async) + { + await base.Correlated_collections_inner_subquery_predicate_references_outer_qsre(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`ReportName`, `t0`.`Nickname`, `t0`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `t1`.`FullName` AS `ReportName`, `t1`.`Nickname`, `t1`.`SquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE ((`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`)) AND (`t`.`FullName` <> 'Foo') +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Correlated_collections_nested_inner_subquery_references_outer_qsre_one_level_up(bool async) + { + await base.Correlated_collections_nested_inner_subquery_references_outer_qsre_one_level_up(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t1`.`FullName`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Name`, `t1`.`Nickname0`, `t1`.`Id` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t0`.`FullName`, `t0`.`Nickname`, `t0`.`SquadId`, `t2`.`Name`, `t2`.`Nickname` AS `Nickname0`, `t2`.`Id`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t0` + LEFT JOIN LATERAL ( + SELECT `w`.`Name`, `t0`.`Nickname`, `w`.`Id` + FROM `Weapons` AS `w` + WHERE (`t0`.`FullName` = `w`.`OwnerFullName`) AND ((`w`.`Name` <> 'Bar') OR `w`.`Name` IS NULL) + ) AS `t2` ON TRUE + WHERE `t0`.`FullName` <> 'Foo' +) AS `t1` ON (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t1`.`Nickname`, `t1`.`SquadId` +"""); + } + + public override async Task Correlated_collections_nested_inner_subquery_references_outer_qsre_two_levels_up(bool async) + { + await base.Correlated_collections_nested_inner_subquery_references_outer_qsre_two_levels_up(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t1`.`FullName`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Name`, `t1`.`Nickname0`, `t1`.`Id` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `t0`.`FullName`, `t0`.`Nickname`, `t0`.`SquadId`, `t2`.`Name`, `t2`.`Nickname` AS `Nickname0`, `t2`.`Id` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t0` + LEFT JOIN ( + SELECT `w`.`Name`, `t`.`Nickname`, `w`.`Id`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + WHERE (`w`.`Name` <> 'Bar') OR `w`.`Name` IS NULL + ) AS `t2` ON `t0`.`FullName` = `t2`.`OwnerFullName` + WHERE ((`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`)) AND (`t0`.`FullName` <> 'Foo') +) AS `t1` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t1`.`Nickname`, `t1`.`SquadId` +"""); + } + + public override async Task Correlated_collections_on_select_many(bool async) + { + await base.Correlated_collections_on_select_many(async); + + AssertSql( +$""" +SELECT `t`.`Nickname`, `s`.`Name`, `t`.`SquadId`, `s`.`Id`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN `Squads` AS `s` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`w`.`IsAutomatic` = TRUE) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL) +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +LEFT JOIN ( + SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t2` + WHERE `t2`.`HasSoulPatch` = FALSE +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +WHERE `t`.`HasSoulPatch` = TRUE +ORDER BY `t`.`Nickname`, `s`.`Id` DESC, `t`.`SquadId`, `t0`.`Id`, `t1`.`Nickname` +"""); + } + + public override async Task Correlated_collections_with_Skip(bool async) + { + await base.Correlated_collections_with_Skip(async); + + AssertSql( +""" +SELECT `s`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` + FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, ROW_NUMBER() OVER(PARTITION BY `t`.`SquadId` ORDER BY `t`.`Nickname`) AS `row` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + ) AS `t0` + WHERE 1 < `t0`.`row` +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +ORDER BY `s`.`Name`, `s`.`Id`, `t1`.`SquadId`, `t1`.`Nickname` +"""); + } + + public override async Task Correlated_collections_with_Take(bool async) + { + await base.Correlated_collections_with_Take(async); + + AssertSql( +""" +SELECT `s`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` + FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, ROW_NUMBER() OVER(PARTITION BY `t`.`SquadId` ORDER BY `t`.`Nickname`) AS `row` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + ) AS `t0` + WHERE `t0`.`row` <= 2 +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +ORDER BY `s`.`Name`, `s`.`Id`, `t1`.`SquadId`, `t1`.`Nickname` +"""); + } + + public override async Task Correlated_collections_with_Distinct(bool async) + { + await base.Correlated_collections_with_Distinct(async); + + AssertSql( +""" +SELECT `s`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM `Squads` AS `s` +LEFT JOIN LATERAL ( + SELECT DISTINCT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` + FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE `s`.`Id` = `t`.`SquadId` + ORDER BY `t`.`Nickname` + LIMIT 18446744073709551610 OFFSET 0 + ) AS `t0` +) AS `t1` ON TRUE +ORDER BY `s`.`Name`, `s`.`Id`, `t1`.`Nickname` +"""); + } + + public override async Task Correlated_collections_with_FirstOrDefault(bool async) + { + await base.Correlated_collections_with_FirstOrDefault(async); + + AssertSql( +""" +SELECT ( + SELECT `t`.`FullName` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE `s`.`Id` = `t`.`SquadId` + ORDER BY `t`.`Nickname` + LIMIT 1) +FROM `Squads` AS `s` +ORDER BY `s`.`Name` +"""); + } + + public override async Task Correlated_collections_on_left_join_with_predicate(bool async) + { + await base.Correlated_collections_on_left_join_with_predicate(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t`.`Id`, `t0`.`SquadId`, `w`.`Name`, `w`.`Id` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON `t`.`GearNickName` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +WHERE `t0`.`HasSoulPatch` = FALSE +ORDER BY `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task Correlated_collections_on_left_join_with_null_value(bool async) + { + await base.Correlated_collections_on_left_join_with_null_value(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Name`, `w`.`Id` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t0` ON `t`.`GearNickName` = `t0`.`Nickname` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Note`, `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task Correlated_collections_left_join_with_self_reference(bool async) + { + await base.Correlated_collections_left_join_with_self_reference(async); + + AssertSql( +""" +SELECT `t`.`Note`, `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`FullName`, `t1`.`Nickname`, `t1`.`SquadId` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON `t`.`GearNickName` = `t0`.`Nickname` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` +) AS `t1` ON ((`t0`.`Nickname` = `t1`.`LeaderNickname`) OR (`t0`.`Nickname` IS NULL AND (`t1`.`LeaderNickname` IS NULL))) AND (`t0`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Nickname` +"""); + } + + public override async Task Correlated_collections_deeply_nested_left_join(bool async) + { + await base.Correlated_collections_deeply_nested_left_join(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `s`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON `t`.`GearNickName` = `t0`.`Nickname` +LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` +LEFT JOIN ( + SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t3`.`Id`, `t3`.`AmmunitionType`, `t3`.`IsAutomatic`, `t3`.`Name`, `t3`.`OwnerFullName`, `t3`.`SynergyWithId` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName`, `g0`.`HasSoulPatch` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`HasSoulPatch` + FROM `Officers` AS `o0` + ) AS `t2` + LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `w`.`IsAutomatic` = TRUE + ) AS `t3` ON `t2`.`FullName` = `t3`.`OwnerFullName` + WHERE `t2`.`HasSoulPatch` = TRUE +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +ORDER BY `t`.`Note`, `t0`.`Nickname` DESC, `t`.`Id`, `t0`.`SquadId`, `s`.`Id`, `t1`.`Nickname`, `t1`.`SquadId` +"""); + } + + public override async Task Correlated_collections_from_left_join_with_additional_elements_projected_of_that_join(bool async) + { + await base.Correlated_collections_from_left_join_with_additional_elements_projected_of_that_join(async); + + AssertSql( +""" +SELECT `w`.`Id`, `t`.`Nickname`, `t`.`SquadId`, `s`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId`, `t1`.`Rank` +FROM `Weapons` AS `w` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` ON `w`.`OwnerFullName` = `t`.`FullName` +LEFT JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` +LEFT JOIN ( + SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t2`.`Id`, `t2`.`AmmunitionType`, `t2`.`IsAutomatic`, `t2`.`Name`, `t2`.`OwnerFullName`, `t2`.`SynergyWithId`, `t0`.`Rank`, `t0`.`FullName` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName`, `g0`.`Rank` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`Rank` + FROM `Officers` AS `o0` + ) AS `t0` + LEFT JOIN ( + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w0` + WHERE `w0`.`IsAutomatic` = FALSE + ) AS `t2` ON `t0`.`FullName` = `t2`.`OwnerFullName` +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +ORDER BY `w`.`Name`, `w`.`Id`, `t`.`Nickname`, `t`.`SquadId`, `s`.`Id`, `t1`.`FullName` DESC, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Id` +"""); + } + + public override async Task Correlated_collections_complex_scenario1(bool async) + { + await base.Correlated_collections_complex_scenario1(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t1`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Id0`, `t1`.`Nickname0`, `t1`.`HasSoulPatch`, `t1`.`SquadId0` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `s`.`Id` AS `Id0`, `t2`.`Nickname` AS `Nickname0`, `t2`.`HasSoulPatch`, `t2`.`SquadId` AS `SquadId0`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t0` ON `w`.`OwnerFullName` = `t0`.`FullName` + LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` + LEFT JOIN ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`HasSoulPatch` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`HasSoulPatch` + FROM `Officers` AS `o1` + ) AS `t2` ON `s`.`Id` = `t2`.`SquadId` +) AS `t1` ON `t`.`FullName` = `t1`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t1`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Id0`, `t1`.`Nickname0` +"""); + } + + public override async Task Correlated_collections_complex_scenario2(bool async) + { + await base.Correlated_collections_complex_scenario2(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t3`.`FullName`, `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`Id`, `t3`.`Nickname0`, `t3`.`SquadId0`, `t3`.`Id0`, `t3`.`Nickname00`, `t3`.`HasSoulPatch`, `t3`.`SquadId00` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t0`.`FullName`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Id`, `t1`.`Nickname` AS `Nickname0`, `t1`.`SquadId` AS `SquadId0`, `t1`.`Id0`, `t1`.`Nickname0` AS `Nickname00`, `t1`.`HasSoulPatch`, `t1`.`SquadId0` AS `SquadId00`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t0` + LEFT JOIN ( + SELECT `w`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `s`.`Id` AS `Id0`, `t4`.`Nickname` AS `Nickname0`, `t4`.`HasSoulPatch`, `t4`.`SquadId` AS `SquadId0`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`FullName` + FROM `Officers` AS `o1` + ) AS `t2` ON `w`.`OwnerFullName` = `t2`.`FullName` + LEFT JOIN `Squads` AS `s` ON `t2`.`SquadId` = `s`.`Id` + LEFT JOIN ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`HasSoulPatch` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o2`.`Nickname`, `o2`.`SquadId`, `o2`.`HasSoulPatch` + FROM `Officers` AS `o2` + ) AS `t4` ON `s`.`Id` = `t4`.`SquadId` + ) AS `t1` ON `t0`.`FullName` = `t1`.`OwnerFullName` +) AS `t3` ON (`t`.`Nickname` = `t3`.`LeaderNickname`) AND (`t`.`SquadId` = `t3`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`Id`, `t3`.`Nickname0`, `t3`.`SquadId0`, `t3`.`Id0`, `t3`.`Nickname00` +"""); + } + + public override async Task Correlated_collections_with_funky_orderby_complex_scenario1(bool async) + { + await base.Correlated_collections_with_funky_orderby_complex_scenario1(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t1`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Id0`, `t1`.`Nickname0`, `t1`.`HasSoulPatch`, `t1`.`SquadId0` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `s`.`Id` AS `Id0`, `t2`.`Nickname` AS `Nickname0`, `t2`.`HasSoulPatch`, `t2`.`SquadId` AS `SquadId0`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t0` ON `w`.`OwnerFullName` = `t0`.`FullName` + LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` + LEFT JOIN ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`HasSoulPatch` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`HasSoulPatch` + FROM `Officers` AS `o1` + ) AS `t2` ON `s`.`Id` = `t2`.`SquadId` +) AS `t1` ON `t`.`FullName` = `t1`.`OwnerFullName` +ORDER BY `t`.`FullName`, `t`.`Nickname` DESC, `t`.`SquadId`, `t1`.`Id`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`Id0`, `t1`.`Nickname0` +"""); + } + + public override async Task Correlated_collections_with_funky_orderby_complex_scenario2(bool async) + { + await base.Correlated_collections_with_funky_orderby_complex_scenario2(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t3`.`FullName`, `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`Id`, `t3`.`Nickname0`, `t3`.`SquadId0`, `t3`.`Id0`, `t3`.`Nickname00`, `t3`.`HasSoulPatch`, `t3`.`SquadId00` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t0`.`FullName`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Id`, `t1`.`Nickname` AS `Nickname0`, `t1`.`SquadId` AS `SquadId0`, `t1`.`Id0`, `t1`.`Nickname0` AS `Nickname00`, `t1`.`HasSoulPatch`, `t1`.`SquadId0` AS `SquadId00`, `t0`.`HasSoulPatch` AS `HasSoulPatch0`, `t1`.`IsAutomatic`, `t1`.`Name`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t0` + LEFT JOIN ( + SELECT `w`.`Id`, `t2`.`Nickname`, `t2`.`SquadId`, `s`.`Id` AS `Id0`, `t4`.`Nickname` AS `Nickname0`, `t4`.`HasSoulPatch`, `t4`.`SquadId` AS `SquadId0`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`FullName` + FROM `Officers` AS `o1` + ) AS `t2` ON `w`.`OwnerFullName` = `t2`.`FullName` + LEFT JOIN `Squads` AS `s` ON `t2`.`SquadId` = `s`.`Id` + LEFT JOIN ( + SELECT `g1`.`Nickname`, `g1`.`SquadId`, `g1`.`HasSoulPatch` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o2`.`Nickname`, `o2`.`SquadId`, `o2`.`HasSoulPatch` + FROM `Officers` AS `o2` + ) AS `t4` ON `s`.`Id` = `t4`.`SquadId` + ) AS `t1` ON `t0`.`FullName` = `t1`.`OwnerFullName` +) AS `t3` ON (`t`.`Nickname` = `t3`.`LeaderNickname`) AND (`t`.`SquadId` = `t3`.`LeaderSquadId`) +ORDER BY `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t3`.`FullName`, `t3`.`HasSoulPatch0` DESC, `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`IsAutomatic`, `t3`.`Name` DESC, `t3`.`Id`, `t3`.`Nickname0`, `t3`.`SquadId0`, `t3`.`Id0`, `t3`.`Nickname00` +"""); + } + + public override async Task Correlated_collection_with_top_level_FirstOrDefault(bool async) + { + await base.Correlated_collection_with_top_level_FirstOrDefault(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`FullName` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` + ORDER BY `t`.`Nickname` + LIMIT 1 +) AS `t0` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task Correlated_collection_with_top_level_Count(bool async) + { + await base.Correlated_collection_with_top_level_Count(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Correlated_collection_with_top_level_Last_with_orderby_on_outer(bool async) + { + await base.Correlated_collection_with_top_level_Last_with_orderby_on_outer(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`FullName` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` + ORDER BY `t`.`FullName` + LIMIT 1 +) AS `t0` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t0`.`FullName`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task Correlated_collection_with_top_level_Last_with_order_by_on_inner(bool async) + { + await base.Correlated_collection_with_top_level_Last_with_order_by_on_inner(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`FullName` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` + ORDER BY `t`.`FullName` DESC + LIMIT 1 +) AS `t0` +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t0`.`FullName` DESC, `t0`.`Nickname`, `t0`.`SquadId`, `w`.`Name` +"""); + } + + public override async Task Null_semantics_on_nullable_bool_from_inner_join_subquery_is_fully_applied(bool async) + { + await base.Null_semantics_on_nullable_bool_from_inner_join_subquery_is_fully_applied(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CapitalName`, `t0`.`Name`, `t0`.`ServerAddress`, `t0`.`CommanderName`, `t0`.`Eradicated` +FROM ( + SELECT `l0`.`Name` + FROM `LocustLeaders` AS `l0` + UNION ALL + SELECT `l1`.`Name` + FROM `LocustCommanders` AS `l1` +) AS `t` +INNER JOIN ( + SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` + FROM `LocustHordes` AS `l` + WHERE `l`.`Name` = 'Swarm' +) AS `t0` ON `t`.`Name` = `t0`.`CommanderName` +WHERE (`t0`.`Eradicated` <> TRUE) OR (`t0`.`Eradicated` IS NULL) +"""); + } + + public override async Task Null_semantics_on_nullable_bool_from_left_join_subquery_is_fully_applied(bool async) + { + await base.Null_semantics_on_nullable_bool_from_left_join_subquery_is_fully_applied(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CapitalName`, `t0`.`Name`, `t0`.`ServerAddress`, `t0`.`CommanderName`, `t0`.`Eradicated` +FROM ( + SELECT `l0`.`Name` + FROM `LocustLeaders` AS `l0` + UNION ALL + SELECT `l1`.`Name` + FROM `LocustCommanders` AS `l1` +) AS `t` +LEFT JOIN ( + SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` + FROM `LocustHordes` AS `l` + WHERE `l`.`Name` = 'Swarm' +) AS `t0` ON `t`.`Name` = `t0`.`CommanderName` +WHERE (`t0`.`Eradicated` <> TRUE) OR (`t0`.`Eradicated` IS NULL) +"""); + } + + public override async Task Include_on_derived_type_with_order_by_and_paging(bool async) + { + await base.Include_on_derived_type_with_order_by_and_paging(async); + + AssertSql( +""" +@__p_0='10' + +SELECT `t2`.`Name`, `t2`.`LocustHordeId`, `t2`.`ThreatLevel`, `t2`.`ThreatLevelByte`, `t2`.`ThreatLevelNullableByte`, `t2`.`DefeatedByNickname`, `t2`.`DefeatedBySquadId`, `t2`.`HighCommandId`, `t2`.`Discriminator`, `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator0` AS `Discriminator`, `t2`.`Id`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` AS `Discriminator0`, `t1`.`Id`, `t1`.`Note` + FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` + ) AS `t` + LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) + LEFT JOIN `Tags` AS `t1` ON ((`t0`.`Nickname` = `t1`.`GearNickName`) OR (`t0`.`Nickname` IS NULL AND (`t1`.`GearNickName` IS NULL))) AND ((`t0`.`SquadId` = `t1`.`GearSquadId`) OR (`t0`.`SquadId` IS NULL AND (`t1`.`GearSquadId` IS NULL))) + ORDER BY `t1`.`Note` + LIMIT @__p_0 +) AS `t2` +LEFT JOIN `Weapons` AS `w` ON `t2`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t2`.`Note`, `t2`.`Name`, `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`Id` +"""); + } + + public override async Task Select_required_navigation_on_derived_type(bool async) + { + await base.Select_required_navigation_on_derived_type(async); + + AssertSql( +""" +SELECT `l`.`Name` +FROM ( + SELECT NULL AS `HighCommandId` + FROM `LocustLeaders` AS `l0` + UNION ALL + SELECT `l1`.`HighCommandId` + FROM `LocustCommanders` AS `l1` +) AS `t` +LEFT JOIN `LocustHighCommands` AS `l` ON `t`.`HighCommandId` = `l`.`Id` +"""); + } + + public override async Task Select_required_navigation_on_the_same_type_with_cast(bool async) + { + await base.Select_required_navigation_on_the_same_type_with_cast(async); + + AssertSql( +""" +SELECT `c`.`Name` +FROM ( + SELECT `g`.`CityOfBirthName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`CityOfBirthName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +"""); + } + + public override async Task Where_required_navigation_on_derived_type(bool async) + { + await base.Where_required_navigation_on_derived_type(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l0` + UNION ALL + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, `l1`.`DefeatedByNickname`, `l1`.`DefeatedBySquadId`, `l1`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l1` +) AS `t` +LEFT JOIN `LocustHighCommands` AS `l` ON `t`.`HighCommandId` = `l`.`Id` +WHERE `l`.`IsOperational` = TRUE +"""); + } + + public override async Task Outer_parameter_in_join_key(bool async) + { + await base.Outer_parameter_in_join_key(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t1`.`Note`, `t1`.`Id`, `t1`.`Nickname`, `t1`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `t0`.`Note`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId` + FROM `Tags` AS `t0` + INNER JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t2` ON `t`.`FullName` = `t2`.`FullName` +) AS `t1` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t1`.`Id`, `t1`.`Nickname` +"""); + } + + public override async Task Outer_parameter_in_join_key_inner_and_outer(bool async) + { + await base.Outer_parameter_in_join_key_inner_and_outer(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t1`.`Note`, `t1`.`Id`, `t1`.`Nickname`, `t1`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `t0`.`Note`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId` + FROM `Tags` AS `t0` + INNER JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` + ) AS `t2` ON `t`.`FullName` = `t`.`Nickname` +) AS `t1` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t1`.`Id`, `t1`.`Nickname` +"""); + } + + public override async Task Outer_parameter_in_group_join_with_DefaultIfEmpty(bool async) + { + await base.Outer_parameter_in_group_join_with_DefaultIfEmpty(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t1`.`Note`, `t1`.`Id`, `t1`.`Nickname`, `t1`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `t0`.`Note`, `t0`.`Id`, `t2`.`Nickname`, `t2`.`SquadId` + FROM `Tags` AS `t0` + LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t2` ON `t`.`FullName` = `t2`.`FullName` +) AS `t1` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t1`.`Id`, `t1`.`Nickname` +"""); + } + + public override async Task Negated_bool_ternary_inside_anonymous_type_in_projection(bool async) + { + await base.Negated_bool_ternary_inside_anonymous_type_in_projection(async); + + AssertSql( +""" +SELECT NOT (CASE + WHEN `t0`.`HasSoulPatch` = TRUE THEN TRUE + ELSE COALESCE(`t0`.`HasSoulPatch`, TRUE) +END) AS `c` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Order_by_entity_qsre(bool async) + { + await base.Order_by_entity_qsre(async); + + AssertSql( +""" +SELECT `t`.`FullName` +FROM ( + SELECT `g`.`Nickname`, `g`.`AssignedCityName`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`AssignedCityName`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Cities` AS `c` ON `t`.`AssignedCityName` = `c`.`Name` +ORDER BY `c`.`Name`, `t`.`Nickname` DESC +"""); + } + + public override async Task Order_by_entity_qsre_with_inheritance(bool async) + { + await base.Order_by_entity_qsre_with_inheritance(async); + + AssertSql( +""" +SELECT `t`.`Name` +FROM ( + SELECT `l0`.`Name`, `l0`.`HighCommandId` + FROM `LocustCommanders` AS `l0` +) AS `t` +INNER JOIN `LocustHighCommands` AS `l` ON `t`.`HighCommandId` = `l`.`Id` +ORDER BY `l`.`Id`, `t`.`Name` +"""); + } + + public override async Task Order_by_entity_qsre_composite_key(bool async) + { + await base.Order_by_entity_qsre_composite_key(async); + + AssertSql( +""" +SELECT `w`.`Name` +FROM `Weapons` AS `w` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` ON `w`.`OwnerFullName` = `t`.`FullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `w`.`Id` +"""); + } + + public override async Task Order_by_entity_qsre_with_other_orderbys(bool async) + { + await base.Order_by_entity_qsre_with_other_orderbys(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` ON `w`.`OwnerFullName` = `t`.`FullName` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY `w`.`IsAutomatic`, `t`.`Nickname` DESC, `t`.`SquadId` DESC, `w0`.`Id`, `w`.`Name` +"""); + } + + public override async Task Join_on_entity_qsre_keys(bool async) + { + await base.Join_on_entity_qsre_keys(async); + + AssertSql( +""" +SELECT `w`.`Name` AS `Name1`, `w0`.`Name` AS `Name2` +FROM `Weapons` AS `w` +INNER JOIN `Weapons` AS `w0` ON `w`.`Id` = `w0`.`Id` +"""); + } + + public override async Task Join_on_entity_qsre_keys_composite_key(bool async) + { + await base.Join_on_entity_qsre_keys_composite_key(async); + + AssertSql( +""" +SELECT `t`.`FullName` AS `GearName1`, `t0`.`FullName` AS `GearName2` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`Nickname`) AND (`t`.`SquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Join_on_entity_qsre_keys_inheritance(bool async) + { + await base.Join_on_entity_qsre_keys_inheritance(async); + + AssertSql( +""" +SELECT `t`.`FullName` AS `GearName`, `t0`.`FullName` AS `OfficerName` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN ( + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`Nickname`) AND (`t`.`SquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Join_on_entity_qsre_keys_outer_key_is_navigation(bool async) + { + await base.Join_on_entity_qsre_keys_outer_key_is_navigation(async); + + AssertSql( +""" +SELECT `w`.`Name` AS `Name1`, `w1`.`Name` AS `Name2` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +INNER JOIN `Weapons` AS `w1` ON `w0`.`Id` = `w1`.`Id` +"""); + } + + public override async Task Join_on_entity_qsre_keys_inner_key_is_navigation(bool async) + { + await base.Join_on_entity_qsre_keys_inner_key_is_navigation(async); + + AssertSql( +""" +SELECT `c`.`Name` AS `CityName`, `t0`.`Nickname` AS `GearNickname` +FROM `Cities` AS `c` +INNER JOIN ( + SELECT `t`.`Nickname`, `c0`.`Name` + FROM ( + SELECT `g`.`Nickname`, `g`.`AssignedCityName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`AssignedCityName` + FROM `Officers` AS `o` + ) AS `t` + LEFT JOIN `Cities` AS `c0` ON `t`.`AssignedCityName` = `c0`.`Name` +) AS `t0` ON `c`.`Name` = `t0`.`Name` +"""); + } + + public override async Task Join_on_entity_qsre_keys_inner_key_is_navigation_composite_key(bool async) + { + await base.Join_on_entity_qsre_keys_inner_key_is_navigation_composite_key(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t1`.`Note` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN ( + SELECT `t0`.`Note`, `t2`.`Nickname`, `t2`.`SquadId` + FROM `Tags` AS `t0` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId` + FROM `Officers` AS `o0` + ) AS `t2` ON (`t0`.`GearNickName` = `t2`.`Nickname`) AND (`t0`.`GearSquadId` = `t2`.`SquadId`) + WHERE `t0`.`Note` IN ('Cole''s Tag', 'Dom''s Tag') +) AS `t1` ON (`t`.`Nickname` = `t1`.`Nickname`) AND (`t`.`SquadId` = `t1`.`SquadId`) +"""); + } + + public override async Task Join_on_entity_qsre_keys_inner_key_is_nested_navigation(bool async) + { + await base.Join_on_entity_qsre_keys_inner_key_is_nested_navigation(async); + + AssertSql( +""" +SELECT `s`.`Name` AS `SquadName`, `t0`.`Name` AS `WeaponName` +FROM `Squads` AS `s` +INNER JOIN ( + SELECT `w`.`Name`, `s0`.`Id` AS `Id0` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` ON `w`.`OwnerFullName` = `t`.`FullName` + LEFT JOIN `Squads` AS `s0` ON `t`.`SquadId` = `s0`.`Id` + WHERE `w`.`IsAutomatic` = TRUE +) AS `t0` ON `s`.`Id` = `t0`.`Id0` +"""); + } + + public override async Task GroupJoin_on_entity_qsre_keys_inner_key_is_nested_navigation(bool async) + { + await base.GroupJoin_on_entity_qsre_keys_inner_key_is_nested_navigation(async); + + AssertSql( +""" +SELECT `s`.`Name` AS `SquadName`, `t0`.`Name` AS `WeaponName` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `w`.`Name`, `s0`.`Id` AS `Id0` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` ON `w`.`OwnerFullName` = `t`.`FullName` + LEFT JOIN `Squads` AS `s0` ON `t`.`SquadId` = `s0`.`Id` +) AS `t0` ON `s`.`Id` = `t0`.`Id0` +"""); + } + + public override async Task Streaming_correlated_collection_issue_11403(bool async) + { + await base.Streaming_correlated_collection_issue_11403(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId` +FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`FullName` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` + ORDER BY `t`.`Nickname` + LIMIT 1 +) AS `t0` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE `w`.`IsAutomatic` = FALSE +) AS `t1` ON `t0`.`FullName` = `t1`.`OwnerFullName` +ORDER BY `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Id` +"""); + } + + public override async Task Project_one_value_type_from_empty_collection(bool async) + { + await base.Project_one_value_type_from_empty_collection(async); + + AssertSql( +""" +SELECT `s`.`Name`, COALESCE(( + SELECT `t`.`SquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`s`.`Id` = `t`.`SquadId`) AND (`t`.`HasSoulPatch` = TRUE) + LIMIT 1), 0) AS `SquadId` +FROM `Squads` AS `s` +WHERE `s`.`Name` = 'Kilo' +"""); + } + + public override async Task Project_one_value_type_converted_to_nullable_from_empty_collection(bool async) + { + await base.Project_one_value_type_converted_to_nullable_from_empty_collection(async); + + AssertSql( +""" +SELECT `s`.`Name`, ( + SELECT `t`.`SquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`s`.`Id` = `t`.`SquadId`) AND (`t`.`HasSoulPatch` = TRUE) + LIMIT 1) AS `SquadId` +FROM `Squads` AS `s` +WHERE `s`.`Name` = 'Kilo' +"""); + } + + public override async Task Project_one_value_type_with_client_projection_from_empty_collection(bool async) + { + await base.Project_one_value_type_with_client_projection_from_empty_collection(async); + + AssertSql( +""" +SELECT `s`.`Name`, `t1`.`SquadId`, `t1`.`LeaderSquadId`, `t1`.`c` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `t0`.`SquadId`, `t0`.`LeaderSquadId`, `t0`.`c` + FROM ( + SELECT `t`.`SquadId`, `t`.`LeaderSquadId`, 1 AS `c`, ROW_NUMBER() OVER(PARTITION BY `t`.`SquadId` ORDER BY `t`.`Nickname`, `t`.`SquadId`) AS `row` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch`, `o`.`LeaderSquadId` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = TRUE + ) AS `t0` + WHERE `t0`.`row` <= 1 +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +WHERE `s`.`Name` = 'Kilo' +"""); + } + + public override async Task Filter_on_subquery_projecting_one_value_type_from_empty_collection(bool async) + { + await base.Filter_on_subquery_projecting_one_value_type_from_empty_collection(async); + + AssertSql( +""" +SELECT `s`.`Name` +FROM `Squads` AS `s` +WHERE (`s`.`Name` = 'Kilo') AND (COALESCE(( + SELECT `t`.`SquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`s`.`Id` = `t`.`SquadId`) AND (`t`.`HasSoulPatch` = TRUE) + LIMIT 1), 0) <> 0) +"""); + } + + public override async Task Select_subquery_projecting_single_constant_int(bool async) + { + await base.Select_subquery_projecting_single_constant_int(async); + + AssertSql( +""" +SELECT `s`.`Name`, COALESCE(( + SELECT 42 + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`s`.`Id` = `t`.`SquadId`) AND (`t`.`HasSoulPatch` = TRUE) + LIMIT 1), 0) AS `Gear` +FROM `Squads` AS `s` +"""); + } + + public override async Task Select_subquery_projecting_single_constant_string(bool async) + { + await base.Select_subquery_projecting_single_constant_string(async); + + AssertSql( +""" +SELECT `s`.`Name`, ( + SELECT 'Foo' + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`s`.`Id` = `t`.`SquadId`) AND (`t`.`HasSoulPatch` = TRUE) + LIMIT 1) AS `Gear` +FROM `Squads` AS `s` +"""); + } + + public override async Task Select_subquery_projecting_single_constant_bool(bool async) + { + await base.Select_subquery_projecting_single_constant_bool(async); + + AssertSql( +""" +SELECT `s`.`Name`, COALESCE(( + SELECT TRUE + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`s`.`Id` = `t`.`SquadId`) AND (`t`.`HasSoulPatch` = TRUE) + LIMIT 1), FALSE) AS `Gear` +FROM `Squads` AS `s` +"""); + } + + public override async Task Select_subquery_projecting_single_constant_inside_anonymous(bool async) + { + await base.Select_subquery_projecting_single_constant_inside_anonymous(async); + + AssertSql( +""" +SELECT `s`.`Name`, `t1`.`One` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `t0`.`One`, `t0`.`SquadId` + FROM ( + SELECT 1 AS `One`, `t`.`SquadId`, ROW_NUMBER() OVER(PARTITION BY `t`.`SquadId` ORDER BY `t`.`Nickname`, `t`.`SquadId`) AS `row` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = TRUE + ) AS `t0` + WHERE `t0`.`row` <= 1 +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +"""); + } + + public override async Task Select_subquery_projecting_multiple_constants_inside_anonymous(bool async) + { + await base.Select_subquery_projecting_multiple_constants_inside_anonymous(async); + + AssertSql( +""" +SELECT `s`.`Name`, `t1`.`True1`, `t1`.`False1`, `t1`.`c` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `t0`.`True1`, `t0`.`False1`, `t0`.`c`, `t0`.`SquadId` + FROM ( + SELECT TRUE AS `True1`, FALSE AS `False1`, 1 AS `c`, `t`.`SquadId`, ROW_NUMBER() OVER(PARTITION BY `t`.`SquadId` ORDER BY `t`.`Nickname`, `t`.`SquadId`) AS `row` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = TRUE + ) AS `t0` + WHERE `t0`.`row` <= 1 +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +"""); + } + + public override async Task Include_with_order_by_constant(bool async) + { + await base.Include_with_order_by_constant(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name`, `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` ON `s`.`Id` = `t`.`SquadId` +ORDER BY `s`.`Id`, `t`.`Nickname` +"""); + } + + public override async Task Correlated_collection_order_by_constant(bool async) + { + await base.Correlated_collection_order_by_constant(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `w`.`Name`, `w`.`Id` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Select_subquery_projecting_single_constant_null_of_non_mapped_type(bool async) + { + await base.Select_subquery_projecting_single_constant_null_of_non_mapped_type(async); + + AssertSql( +""" +SELECT `s`.`Name`, `t1`.`c` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `t0`.`c`, `t0`.`SquadId` + FROM ( + SELECT 1 AS `c`, `t`.`SquadId`, ROW_NUMBER() OVER(PARTITION BY `t`.`SquadId` ORDER BY `t`.`Nickname`, `t`.`SquadId`) AS `row` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = TRUE + ) AS `t0` + WHERE `t0`.`row` <= 1 +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +"""); + } + + public override async Task Select_subquery_projecting_single_constant_of_non_mapped_type(bool async) + { + await base.Select_subquery_projecting_single_constant_of_non_mapped_type(async); + + AssertSql( +""" +SELECT `s`.`Name`, `t1`.`c` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `t0`.`c`, `t0`.`SquadId` + FROM ( + SELECT 1 AS `c`, `t`.`SquadId`, ROW_NUMBER() OVER(PARTITION BY `t`.`SquadId` ORDER BY `t`.`Nickname`, `t`.`SquadId`) AS `row` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` + ) AS `t` + WHERE `t`.`HasSoulPatch` = TRUE + ) AS `t0` + WHERE `t0`.`row` <= 1 +) AS `t1` ON `s`.`Id` = `t1`.`SquadId` +"""); + } + + public override async Task Include_collection_OrderBy_aggregate(bool async) + { + await base.Include_collection_OrderBy_aggregate(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY ( + SELECT COUNT(*) + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`), `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Include_collection_with_complex_OrderBy2(bool async) + { + await base.Include_collection_with_complex_OrderBy2(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY ( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1), `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Include_collection_with_complex_OrderBy3(bool async) + { + await base.Include_collection_with_complex_OrderBy3(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY COALESCE(( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1), FALSE), `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Correlated_collection_with_complex_OrderBy(bool async) + { + await base.Correlated_collection_with_complex_OrderBy(async); + + AssertSql( +$""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE `t1`.`HasSoulPatch` = FALSE +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY ( + SELECT COUNT(*) + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`), `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Correlated_collection_with_very_complex_order_by(bool async) + { + await base.Correlated_collection_with_very_complex_order_by(async); + + AssertSql( +$""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t2` + WHERE `t2`.`HasSoulPatch` = FALSE +) AS `t1` ON (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`) +ORDER BY ( + SELECT COUNT(*) + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`IsAutomatic` = COALESCE(( + SELECT `t0`.`HasSoulPatch` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o1`.`Nickname`, `o1`.`SquadId`, `o1`.`AssignedCityName`, `o1`.`CityOfBirthName`, `o1`.`FullName`, `o1`.`HasSoulPatch`, `o1`.`LeaderNickname`, `o1`.`LeaderSquadId`, `o1`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o1` + ) AS `t0` + WHERE `t0`.`Nickname` = 'Marcus' + LIMIT 1), FALSE))), `t`.`Nickname`, `t`.`SquadId`, `t1`.`Nickname` +"""); + } + + public override async Task Cast_to_derived_type_after_OfType_works(bool async) + { + await base.Cast_to_derived_type_after_OfType_works(async); + + AssertSql( +""" +SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` +FROM `Officers` AS `o` +"""); + } + + public override async Task Select_subquery_boolean(bool async) + { + await base.Select_subquery_boolean(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1), FALSE) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_subquery_boolean_with_pushdown(bool async) + { + await base.Select_subquery_boolean_with_pushdown(async); + + AssertSql( +""" +SELECT ( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_subquery_int_with_inside_cast_and_coalesce(bool async) + { + await base.Select_subquery_int_with_inside_cast_and_coalesce(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT `w`.`Id` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1), 42) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_subquery_int_with_outside_cast_and_coalesce(bool async) + { + await base.Select_subquery_int_with_outside_cast_and_coalesce(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT `w`.`Id` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1), 0, 42) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_subquery_int_with_pushdown_and_coalesce(bool async) + { + await base.Select_subquery_int_with_pushdown_and_coalesce(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT `w`.`Id` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1), 42) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_subquery_int_with_pushdown_and_coalesce2(bool async) + { + await base.Select_subquery_int_with_pushdown_and_coalesce2(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT `w`.`Id` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + ORDER BY `w`.`Id` + LIMIT 1), ( + SELECT `w0`.`Id` + FROM `Weapons` AS `w0` + WHERE `t`.`FullName` = `w0`.`OwnerFullName` + ORDER BY `w0`.`Id` + LIMIT 1)) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_subquery_boolean_empty(bool async) + { + await base.Select_subquery_boolean_empty(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` = 'BFG') + ORDER BY `w`.`Id` + LIMIT 1), FALSE) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_subquery_boolean_empty_with_pushdown(bool async) + { + await base.Select_subquery_boolean_empty_with_pushdown(async); + + AssertSql( +""" +SELECT ( + SELECT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` = 'BFG') + ORDER BY `w`.`Id` + LIMIT 1) +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Select_subquery_distinct_singleordefault_boolean1(bool async) + { + await base.Select_subquery_distinct_singleordefault_boolean1(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` LIKE '%Lancer%') + ) AS `t0` + LIMIT 1), FALSE) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +"""); + } + + public override async Task Select_subquery_distinct_singleordefault_boolean2(bool async) + { + await base.Select_subquery_distinct_singleordefault_boolean2(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT DISTINCT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` LIKE '%Lancer%') + LIMIT 1), FALSE) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Select_subquery_distinct_singleordefault_boolean_with_pushdown(bool async) + { + await base.Select_subquery_distinct_singleordefault_boolean_with_pushdown(async); + + AssertSql( +""" +SELECT ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` LIKE '%Lancer%') + ) AS `t0` + LIMIT 1) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Select_subquery_distinct_singleordefault_boolean_empty1(bool async) + { + await base.Select_subquery_distinct_singleordefault_boolean_empty1(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` = 'BFG') + ) AS `t0` + LIMIT 1), FALSE) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +"""); + } + + public override async Task Select_subquery_distinct_singleordefault_boolean_empty2(bool async) + { + await base.Select_subquery_distinct_singleordefault_boolean_empty2(async); + + AssertSql( +""" +SELECT COALESCE(( + SELECT DISTINCT `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` = 'BFG') + LIMIT 1), FALSE) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +"""); + } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.OuterReferenceInMultiLevelSubquery))] + public override async Task Select_subquery_distinct_singleordefault_boolean_empty_with_pushdown(bool async) + { + await base.Select_subquery_distinct_singleordefault_boolean_empty_with_pushdown(async); + + AssertSql( +""" +SELECT ( + SELECT `t0`.`IsAutomatic` + FROM ( + SELECT DISTINCT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` = 'BFG') + ) AS `t0` + LIMIT 1) +FROM ( + SELECT `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` = TRUE +"""); + } + + public override async Task Cast_subquery_to_base_type_using_typed_ToList(bool async) + { + await base.Cast_subquery_to_base_type_using_typed_ToList(async); + + AssertSql( +""" +SELECT `c`.`Name`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Nickname`, `t`.`Rank`, `t`.`SquadId` +FROM `Cities` AS `c` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` ON `c`.`Name` = `t`.`AssignedCityName` +WHERE `c`.`Name` = 'Ephyra' +ORDER BY `c`.`Name`, `t`.`Nickname` +"""); + } + + public override async Task Cast_ordered_subquery_to_base_type_using_typed_ToArray(bool async) + { + await base.Cast_ordered_subquery_to_base_type_using_typed_ToArray(async); + + AssertSql( +""" +SELECT `c`.`Name`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Nickname`, `t`.`Rank`, `t`.`SquadId` +FROM `Cities` AS `c` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` ON `c`.`Name` = `t`.`AssignedCityName` +WHERE `c`.`Name` = 'Ephyra' +ORDER BY `c`.`Name`, `t`.`Nickname` DESC +"""); + } + + public override async Task Correlated_collection_with_complex_order_by_funcletized_to_constant_bool(bool async) + { + await base.Correlated_collection_with_complex_order_by_funcletized_to_constant_bool(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `w`.`Name`, `w`.`Id` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Double_order_by_on_nullable_bool_coming_from_optional_navigation(bool async) + { + await base.Double_order_by_on_nullable_bool_coming_from_optional_navigation(async); + + AssertSql( +""" +SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY `w0`.`IsAutomatic`, `w0`.`Id` +"""); + } + + public override async Task Double_order_by_on_Like(bool async) + { + await base.Double_order_by_on_Like(async); + + AssertSql( +""" +SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY `w0`.`Name` LIKE '%Lancer' +"""); + } + + public override async Task Double_order_by_on_is_null(bool async) + { + await base.Double_order_by_on_is_null(async); + + AssertSql( +""" +SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY `w0`.`Name` IS NULL +"""); + } + + public override async Task Double_order_by_on_string_compare(bool async) + { + await base.Double_order_by_on_string_compare(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +ORDER BY (`w`.`Name` = 'Marcus'' Lancer') AND `w`.`Name` IS NOT NULL, `w`.`Id` +"""); + } + + public override async Task Double_order_by_binary_expression(bool async) + { + await base.Double_order_by_binary_expression(async); + + AssertSql( +""" +SELECT `w`.`Id` + 2 AS `Binary` +FROM `Weapons` AS `w` +ORDER BY `w`.`Id` + 2 +"""); + } + + public override async Task String_compare_with_null_conditional_argument(bool async) + { + await base.String_compare_with_null_conditional_argument(async); + + AssertSql( +""" +SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY (`w0`.`Name` = 'Marcus'' Lancer') AND `w0`.`Name` IS NOT NULL +"""); + } + + public override async Task String_compare_with_null_conditional_argument2(bool async) + { + await base.String_compare_with_null_conditional_argument2(async); + + AssertSql( +""" +SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY ('Marcus'' Lancer' = `w0`.`Name`) AND `w0`.`Name` IS NOT NULL +"""); + } + + public override async Task String_concat_with_null_conditional_argument(bool async) + { + await base.String_concat_with_null_conditional_argument(async); + + AssertSql( +""" +SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY CONCAT(COALESCE(`w0`.`Name`, ''), CAST(5 AS char)) +"""); + } + + public override async Task String_concat_with_null_conditional_argument2(bool async) + { + await base.String_concat_with_null_conditional_argument2(async); + + AssertSql( +""" +SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY CONCAT(`w0`.`Name`, 'Marcus'' Lancer') +"""); + } + + public override async Task String_concat_on_various_types(bool async) + { + await base.String_concat_on_various_types(async); + + AssertSql( +""" +SELECT CONCAT(CONCAT('HasSoulPatch ', CAST(`t`.`HasSoulPatch` AS char)), ' HasSoulPatch') AS `HasSoulPatch`, CONCAT(CONCAT('Rank ', CAST(`t`.`Rank` AS char)), ' Rank') AS `Rank`, CONCAT(CONCAT('SquadId ', CAST(`t`.`SquadId` AS char)), ' SquadId') AS `SquadId`, CONCAT(CONCAT('Rating ', COALESCE(CAST(`m`.`Rating` AS char), '')), ' Rating') AS `Rating`, CONCAT(CONCAT('Timeline ', CAST(`m`.`Timeline` AS char)), ' Timeline') AS `Timeline` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN `Missions` AS `m` +ORDER BY `t`.`Nickname`, `m`.`Id` +"""); + } + + public override async Task Time_of_day_datetimeoffset(bool async) + { + await base.Time_of_day_datetimeoffset(async); + + AssertSql( +""" +SELECT CAST(`m`.`Timeline` AS time(6)) +FROM `Missions` AS `m` +"""); + } + + public override async Task GroupBy_Property_Include_Select_Average(bool async) + { + await base.GroupBy_Property_Include_Select_Average(async); + + AssertSql( +$""" +SELECT AVG({MySqlTestHelpers.CastAsDouble(@"`t`.`SquadId`")}) +FROM ( + SELECT `g`.`SquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`SquadId`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +GROUP BY `t`.`Rank` +"""); + } + + public override async Task GroupBy_Property_Include_Select_Sum(bool async) + { + await base.GroupBy_Property_Include_Select_Sum(async); + + AssertSql( +""" +SELECT COALESCE(SUM(`t`.`SquadId`), 0) +FROM ( + SELECT `g`.`SquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`SquadId`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +GROUP BY `t`.`Rank` +"""); + } + + public override async Task GroupBy_Property_Include_Select_Count(bool async) + { + await base.GroupBy_Property_Include_Select_Count(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM ( + SELECT `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +GROUP BY `t`.`Rank` +"""); + } + + public override async Task GroupBy_Property_Include_Select_LongCount(bool async) + { + await base.GroupBy_Property_Include_Select_LongCount(async); + + AssertSql( +""" +SELECT COUNT(*) +FROM ( + SELECT `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +GROUP BY `t`.`Rank` +"""); + } + + public override async Task GroupBy_Property_Include_Select_Min(bool async) + { + await base.GroupBy_Property_Include_Select_Min(async); + + AssertSql( +""" +SELECT MIN(`t`.`SquadId`) +FROM ( + SELECT `g`.`SquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`SquadId`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +GROUP BY `t`.`Rank` +"""); + } + + public override async Task GroupBy_Property_Include_Aggregate_with_anonymous_selector(bool async) + { + await base.GroupBy_Property_Include_Aggregate_with_anonymous_selector(async); + + AssertSql( +""" +SELECT `t`.`Nickname` AS `Key`, COUNT(*) AS `c` +FROM ( + SELECT `g`.`Nickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname` + FROM `Officers` AS `o` +) AS `t` +GROUP BY `t`.`Nickname` +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Group_by_with_include_with_entity_in_result_selector(bool async) + { + await base.Group_by_with_include_with_entity_in_result_selector(async); + + AssertSql( +""" +SELECT `t0`.`Rank`, `t0`.`c`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator`, `t1`.`Name`, `t1`.`Location`, `t1`.`Nation` +FROM ( + SELECT `t`.`Rank`, COUNT(*) AS `c` + FROM ( + SELECT `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Rank` + FROM `Officers` AS `o` + ) AS `t` + GROUP BY `t`.`Rank` +) AS `t0` +LEFT JOIN ( + SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator`, `t2`.`Name`, `t2`.`Location`, `t2`.`Nation` + FROM ( + SELECT `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`AssignedCityName`, `t3`.`CityOfBirthName`, `t3`.`FullName`, `t3`.`HasSoulPatch`, `t3`.`LeaderNickname`, `t3`.`LeaderSquadId`, `t3`.`Rank`, `t3`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation`, ROW_NUMBER() OVER(PARTITION BY `t3`.`Rank` ORDER BY `t3`.`Nickname`) AS `row` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t3` + INNER JOIN `Cities` AS `c` ON `t3`.`CityOfBirthName` = `c`.`Name` + ) AS `t2` + WHERE `t2`.`row` <= 1 +) AS `t1` ON `t0`.`Rank` = `t1`.`Rank` +ORDER BY `t0`.`Rank` +"""); + } + + public override async Task GroupBy_Property_Include_Select_Max(bool async) + { + await base.GroupBy_Property_Include_Select_Max(async); + + AssertSql( +""" +SELECT MAX(`t`.`SquadId`) +FROM ( + SELECT `g`.`SquadId`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`SquadId`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +GROUP BY `t`.`Rank` +"""); + } + + public override async Task Include_with_group_by_and_FirstOrDefault_gets_properly_applied(bool async) + { + await base.Include_with_group_by_and_FirstOrDefault_gets_properly_applied(async); + + AssertSql( +""" +SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator`, `t1`.`Name`, `t1`.`Location`, `t1`.`Nation` +FROM ( + SELECT `t`.`Rank` + FROM ( + SELECT `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Rank` + FROM `Officers` AS `o` + ) AS `t` + GROUP BY `t`.`Rank` +) AS `t0` +LEFT JOIN ( + SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator`, `t2`.`Name`, `t2`.`Location`, `t2`.`Nation` + FROM ( + SELECT `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`AssignedCityName`, `t3`.`CityOfBirthName`, `t3`.`FullName`, `t3`.`HasSoulPatch`, `t3`.`LeaderNickname`, `t3`.`LeaderSquadId`, `t3`.`Rank`, `t3`.`Discriminator`, `c`.`Name`, `c`.`Location`, `c`.`Nation`, ROW_NUMBER() OVER(PARTITION BY `t3`.`Rank` ORDER BY `t3`.`Nickname`, `t3`.`SquadId`, `c`.`Name`) AS `row` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t3` + INNER JOIN `Cities` AS `c` ON `t3`.`CityOfBirthName` = `c`.`Name` + WHERE `t3`.`HasSoulPatch` = TRUE + ) AS `t2` + WHERE `t2`.`row` <= 1 +) AS `t1` ON `t0`.`Rank` = `t1`.`Rank` +"""); + } + + public override async Task Include_collection_with_Cast_to_base(bool async) + { + await base.Include_collection_with_Cast_to_base(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Include_with_client_method_and_member_access_still_applies_includes(bool async) + { + await base.Include_with_client_method_and_member_access_still_applies_includes(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`GearNickName`, `t0`.`GearSquadId`, `t0`.`IssueDate`, `t0`.`Note` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +"""); + } + + public override async Task Include_with_projection_of_unmapped_property_still_gets_applied(bool async) + { + await base.Include_with_projection_of_unmapped_property_still_gets_applied(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Multiple_includes_with_client_method_around_entity_and_also_projecting_included_collection() + { + await base.Multiple_includes_with_client_method_around_entity_and_also_projecting_included_collection(); + + AssertSql( +$""" +SELECT `s`.`Name`, `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Gear'")} AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'Officer'")} AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +) AS `t0` ON `s`.`Id` = `t0`.`SquadId` +WHERE `s`.`Name` = 'Delta' +ORDER BY `s`.`Id`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task OrderBy_same_expression_containing_IsNull_correctly_deduplicates_the_ordering(bool async) + { + await base.OrderBy_same_expression_containing_IsNull_correctly_deduplicates_the_ordering(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CHAR_LENGTH(`t`.`Nickname`) = 5 + ELSE NULL +END +FROM ( + SELECT `g`.`Nickname`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +ORDER BY CASE + WHEN `t`.`LeaderNickname` IS NOT NULL THEN CHAR_LENGTH(`t`.`Nickname`) = 5 + ELSE NULL +END IS NOT NULL +"""); + } + + public override async Task GetValueOrDefault_in_projection(bool async) + { + await base.GetValueOrDefault_in_projection(async); + + AssertSql( +""" +SELECT COALESCE(`w`.`SynergyWithId`, 0) +FROM `Weapons` AS `w` +"""); + } + + public override async Task GetValueOrDefault_in_filter(bool async) + { + await base.GetValueOrDefault_in_filter(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE COALESCE(`w`.`SynergyWithId`, 0) = 0 +"""); + } + + public override async Task GetValueOrDefault_in_filter_non_nullable_column(bool async) + { + await base.GetValueOrDefault_in_filter_non_nullable_column(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE COALESCE(`w`.`Id`, 0) = 0 +"""); + } + + public override async Task GetValueOrDefault_in_order_by(bool async) + { + await base.GetValueOrDefault_in_order_by(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +ORDER BY COALESCE(`w`.`SynergyWithId`, 0), `w`.`Id` +"""); + } + + public override async Task GetValueOrDefault_with_argument(bool async) + { + await base.GetValueOrDefault_with_argument(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE COALESCE(`w`.`SynergyWithId`, `w`.`Id`) = 1 +"""); + } + + public override async Task GetValueOrDefault_with_argument_complex(bool async) + { + await base.GetValueOrDefault_with_argument_complex(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE COALESCE(`w`.`SynergyWithId`, CHAR_LENGTH(`w`.`Name`) + 42) > 10 +"""); + } + + public override async Task Filter_with_complex_predicate_containing_subquery(bool async) + { + await base.Filter_with_complex_predicate_containing_subquery(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`FullName` <> 'Dom') AND EXISTS ( + SELECT 1 + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`IsAutomatic` = TRUE)) +"""); + } + + public override async Task Query_with_complex_let_containing_ordering_and_filter_projecting_firstOrDefault_element_of_let( + bool async) + { + await base.Query_with_complex_let_containing_ordering_and_filter_projecting_firstOrDefault_element_of_let(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, ( + SELECT `w`.`Name` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`IsAutomatic` = TRUE) + ORDER BY `w`.`AmmunitionType` DESC + LIMIT 1) AS `WeaponName` +FROM ( + SELECT `g`.`Nickname`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`Nickname` <> 'Dom' +"""); + } + + public override async Task + Null_semantics_is_correctly_applied_for_function_comparisons_that_take_arguments_from_optional_navigation(bool async) + { + await base.Null_semantics_is_correctly_applied_for_function_comparisons_that_take_arguments_from_optional_navigation(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (SUBSTRING(`t`.`Note`, 0 + 1, `t0`.`SquadId`) = `t`.`GearNickName`) OR ((`t`.`Note` IS NULL OR (`t0`.`SquadId` IS NULL)) AND `t`.`GearNickName` IS NULL) +"""); + } + + public override async Task + Null_semantics_is_correctly_applied_for_function_comparisons_that_take_arguments_from_optional_navigation_complex(bool async) + { + await base.Null_semantics_is_correctly_applied_for_function_comparisons_that_take_arguments_from_optional_navigation_complex( + async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` +WHERE (SUBSTRING(`t`.`Note`, 0 + 1, CHAR_LENGTH(`s`.`Name`)) = `t`.`GearNickName`) OR ((`t`.`Note` IS NULL OR (`s`.`Name` IS NULL)) AND `t`.`GearNickName` IS NULL) +"""); + } + + public override async Task Filter_with_new_Guid(bool async) + { + await base.Filter_with_new_Guid(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note` +FROM `Tags` AS `t` +WHERE `t`.`Id` = 'df36f493-463f-4123-83f9-6b135deeb7ba' +"""); + } + + public override async Task Filter_with_new_Guid_closure(bool async) + { + await base.Filter_with_new_Guid_closure(async); + + AssertSql(); + } + + public override async Task OfTypeNav1(bool async) + { + await base.OfTypeNav1(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +LEFT JOIN `Tags` AS `t1` ON (`t`.`Nickname` = `t1`.`GearNickName`) AND (`t`.`SquadId` = `t1`.`GearSquadId`) +WHERE ((`t0`.`Note` <> 'Foo') OR `t0`.`Note` IS NULL) AND ((`t1`.`Note` <> 'Bar') OR `t1`.`Note` IS NULL) +"""); + } + + public override async Task OfTypeNav2(bool async) + { + await base.OfTypeNav2(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +LEFT JOIN `Cities` AS `c` ON `t`.`AssignedCityName` = `c`.`Name` +WHERE ((`t0`.`Note` <> 'Foo') OR `t0`.`Note` IS NULL) AND ((`c`.`Location` <> 'Bar') OR `c`.`Location` IS NULL) +"""); + } + + public override async Task OfTypeNav3(bool async) + { + await base.OfTypeNav3(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +INNER JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +LEFT JOIN `Tags` AS `t1` ON (`t`.`Nickname` = `t1`.`GearNickName`) AND (`t`.`SquadId` = `t1`.`GearSquadId`) +WHERE ((`t0`.`Note` <> 'Foo') OR `t0`.`Note` IS NULL) AND ((`t1`.`Note` <> 'Bar') OR `t1`.`Note` IS NULL) +"""); + } + + public override async Task Nav_rewrite_Distinct_with_convert() + { + await base.Nav_rewrite_Distinct_with_convert(); + + AssertSql(); + } + + public override async Task Nav_rewrite_Distinct_with_convert_anonymous() + { + await base.Nav_rewrite_Distinct_with_convert_anonymous(); + + AssertSql(); + } + + public override async Task Nav_rewrite_with_convert1(bool async) + { + await base.Nav_rewrite_with_convert1(async); + + AssertSql( +""" +SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId` +FROM `LocustHordes` AS `l` +LEFT JOIN `Cities` AS `c` ON `l`.`CapitalName` = `c`.`Name` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +WHERE (`c`.`Name` <> 'Foo') OR `c`.`Name` IS NULL +"""); + } + + public override async Task Nav_rewrite_with_convert2(bool async) + { + await base.Nav_rewrite_with_convert2(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +LEFT JOIN `Cities` AS `c` ON `l`.`CapitalName` = `c`.`Name` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +WHERE ((`c`.`Name` <> 'Foo') OR `c`.`Name` IS NULL) AND ((`l0`.`Name` <> 'Bar') OR `l0`.`Name` IS NULL) +"""); + } + + public override async Task Nav_rewrite_with_convert3(bool async) + { + await base.Nav_rewrite_with_convert3(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +LEFT JOIN `Cities` AS `c` ON `l`.`CapitalName` = `c`.`Name` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +WHERE ((`c`.`Name` <> 'Foo') OR `c`.`Name` IS NULL) AND ((`l0`.`Name` <> 'Bar') OR `l0`.`Name` IS NULL) +"""); + } + + public override async Task Where_contains_on_navigation_with_composite_keys(bool async) + { + await base.Where_contains_on_navigation_with_composite_keys(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE EXISTS ( + SELECT 1 + FROM `Cities` AS `c` + WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t0` + WHERE (`c`.`Name` = `t0`.`CityOfBirthName`) AND ((`t0`.`Nickname` = `t`.`Nickname`) AND (`t0`.`SquadId` = `t`.`SquadId`)))) +"""); + } + + public override async Task Include_with_complex_order_by(bool async) + { + await base.Include_with_complex_order_by(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w0` ON `t`.`FullName` = `w0`.`OwnerFullName` +ORDER BY ( + SELECT `w`.`Name` + FROM `Weapons` AS `w` + WHERE (`t`.`FullName` = `w`.`OwnerFullName`) AND (`w`.`Name` LIKE '%Gnasher%') + LIMIT 1), `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Anonymous_projection_take_followed_by_projecting_single_element_from_collection_navigation(bool async) + { + await base.Anonymous_projection_take_followed_by_projecting_single_element_from_collection_navigation(async); + + AssertSql( +""" +@__p_0='25' + +SELECT `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId` +FROM ( + SELECT `t`.`FullName` + FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` + LIMIT @__p_0 +) AS `t0` +LEFT JOIN ( + SELECT `t2`.`Id`, `t2`.`AmmunitionType`, `t2`.`IsAutomatic`, `t2`.`Name`, `t2`.`OwnerFullName`, `t2`.`SynergyWithId` + FROM ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, ROW_NUMBER() OVER(PARTITION BY `w`.`OwnerFullName` ORDER BY `w`.`Id`) AS `row` + FROM `Weapons` AS `w` + ) AS `t2` + WHERE `t2`.`row` <= 1 +) AS `t1` ON `t0`.`FullName` = `t1`.`OwnerFullName` +"""); + } + + public override async Task Bool_projection_from_subquery_treated_appropriately_in_where(bool async) + { + await base.Bool_projection_from_subquery_treated_appropriately_in_where(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE ( + SELECT `t`.`HasSoulPatch` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + ORDER BY `t`.`Nickname`, `t`.`SquadId` + LIMIT 1) +"""); + } + + public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool async) + { + var dto = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); + var start = dto.AddDays(-1); + var end = dto.AddDays(1); + var dates = new[] { dto }; + + await AssertQuery( + async, + ss => ss.Set().Where( + m => start <= m.Timeline.Date && m.Timeline < end && dates.Contains(m.Timeline))); + + AssertSql( +""" +@__start_0='1902-01-01T08:30:00.1234560+00:00' +@__end_1='1902-01-03T08:30:00.1234560+00:00' + +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE ((@__start_0 <= CONVERT(`m`.`Timeline`, date)) AND (`m`.`Timeline` < @__end_1)) AND (`m`.`Timeline` = TIMESTAMP '1902-01-02 08:30:00.123456') +"""); + } + + [ConditionalTheory(Skip = "TODO: Does not work as expected, probably due to some test definition issues.")] + public override async Task DateTimeOffsetNow_minus_timespan(bool async) + { + var timeSpan = new TimeSpan(10000); // <-- changed from 1000 to 10000 ticks + + await AssertQuery( + async, + ss => ss.Set().Where(e => e.Timeline > DateTimeOffset.Now - timeSpan)); + + AssertSql( +""" +@__timeSpan_0='00:00:00.0010000' (DbType = DateTimeOffset) + +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE `m`.`Timeline` > (UTC_TIMESTAMP() - @__timeSpan_0) +"""); + } + + public override async Task Navigation_inside_interpolated_string_expanded(bool async) + { + await base.Navigation_inside_interpolated_string_expanded(async); + + AssertSql( +""" +SELECT `w`.`SynergyWithId` IS NOT NULL, `w0`.`OwnerFullName` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +"""); + } + + public override async Task Left_join_projection_using_coalesce_tracking(bool async) + { + await base.Left_join_projection_using_coalesce_tracking(async); + + AssertSql( +""" +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +"""); + } + + public override async Task Left_join_projection_using_conditional_tracking(bool async) + { + await base.Left_join_projection_using_conditional_tracking(async); + + AssertSql( +""" +SELECT `t0`.`Nickname` IS NULL OR (`t0`.`SquadId` IS NULL), `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`LeaderNickname` = `t0`.`Nickname` +"""); + } + + public override async Task Project_collection_navigation_nested_with_take_composite_key(bool async) + { + await base.Project_collection_navigation_nested_with_take_composite_key(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN ( + SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator` + FROM ( + SELECT `t3`.`Nickname`, `t3`.`SquadId`, `t3`.`AssignedCityName`, `t3`.`CityOfBirthName`, `t3`.`FullName`, `t3`.`HasSoulPatch`, `t3`.`LeaderNickname`, `t3`.`LeaderSquadId`, `t3`.`Rank`, `t3`.`Discriminator`, ROW_NUMBER() OVER(PARTITION BY `t3`.`LeaderNickname`, `t3`.`LeaderSquadId` ORDER BY `t3`.`Nickname`, `t3`.`SquadId`) AS `row` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t3` + ) AS `t2` + WHERE `t2`.`row` <= 50 +) AS `t1` ON ((`t0`.`Nickname` = `t1`.`LeaderNickname`) OR (`t0`.`Nickname` IS NULL AND (`t1`.`LeaderNickname` IS NULL))) AND (`t0`.`SquadId` = `t1`.`LeaderSquadId`) +WHERE `t0`.`Discriminator` = 'Officer' +ORDER BY `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Nickname` +"""); + } + + public override async Task Project_collection_navigation_nested_composite_key(bool async) + { + await base.Project_collection_navigation_nested_composite_key(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t1` ON ((`t0`.`Nickname` = `t1`.`LeaderNickname`) OR (`t0`.`Nickname` IS NULL AND (`t1`.`LeaderNickname` IS NULL))) AND (`t0`.`SquadId` = `t1`.`LeaderSquadId`) +WHERE `t0`.`Discriminator` = 'Officer' +ORDER BY `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Nickname` +"""); + } + + public override async Task Null_checks_in_correlated_predicate_are_correctly_translated(bool async) + { + await base.Null_checks_in_correlated_predicate_are_correctly_translated(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON ((`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`)) AND `t`.`Note` IS NOT NULL +ORDER BY `t`.`Id`, `t0`.`Nickname` +"""); + } + + public override async Task SelectMany_Where_DefaultIfEmpty_with_navigation_in_the_collection_selector(bool async) + { + await base.SelectMany_Where_DefaultIfEmpty_with_navigation_in_the_collection_selector(async); + + AssertSql( +""" +@__isAutomatic_0='True' + +SELECT `t`.`Nickname`, `t`.`FullName`, `t0`.`Id` IS NOT NULL AS `Collection` +FROM ( + SELECT `g`.`Nickname`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + WHERE `w`.`IsAutomatic` = @__isAutomatic_0 +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +"""); + } + + public override async Task Join_with_inner_being_a_subquery_projecting_single_property(bool async) + { + await base.Join_with_inner_being_a_subquery_projecting_single_property(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`Nickname` = `t0`.`Nickname` +"""); + } + + public override async Task Join_with_inner_being_a_subquery_projecting_anonymous_type_with_single_property(bool async) + { + await base.Join_with_inner_being_a_subquery_projecting_anonymous_type_with_single_property(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON `t`.`Nickname` = `t0`.`Nickname` +"""); + } + + public override async Task Navigation_based_on_complex_expression1(bool async) + { + await base.Navigation_based_on_complex_expression1(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +WHERE `l0`.`Name` IS NOT NULL +"""); + } + + public override async Task Navigation_based_on_complex_expression2(bool async) + { + await base.Navigation_based_on_complex_expression2(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +WHERE `l0`.`Name` IS NOT NULL +"""); + } + + public override async Task Navigation_based_on_complex_expression3(bool async) + { + await base.Navigation_based_on_complex_expression3(async); + + AssertSql( +""" +SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId` +FROM `LocustHordes` AS `l` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +"""); + } + + public override async Task Navigation_based_on_complex_expression4(bool async) + { + await base.Navigation_based_on_complex_expression4(async); + + AssertSql( +""" +SELECT TRUE, `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM `LocustHordes` AS `l` +CROSS JOIN ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, `l1`.`DefeatedByNickname`, `l1`.`DefeatedBySquadId`, `l1`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l1` +) AS `t` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +"""); + } + + public override async Task Navigation_based_on_complex_expression5(bool async) + { + await base.Navigation_based_on_complex_expression5(async); + + AssertSql( +""" +SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM `LocustHordes` AS `l` +CROSS JOIN ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, `l1`.`DefeatedByNickname`, `l1`.`DefeatedBySquadId`, `l1`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l1` +) AS `t` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +"""); + } + + public override async Task Navigation_based_on_complex_expression6(bool async) + { + await base.Navigation_based_on_complex_expression6(async); + + AssertSql( +""" +SELECT (`l0`.`Name` = 'Queen Myrrah') AND `l0`.`Name` IS NOT NULL, `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM `LocustHordes` AS `l` +CROSS JOIN ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, `l1`.`DefeatedByNickname`, `l1`.`DefeatedBySquadId`, `l1`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l1` +) AS `t` +LEFT JOIN `LocustCommanders` AS `l0` ON `l`.`CommanderName` = `l0`.`Name` +"""); + } + + public override async Task Select_as_operator(bool async) + { + await base.Select_as_operator(async); + + AssertSql( +""" +SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` +FROM `LocustLeaders` AS `l` +UNION ALL +SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` +FROM `LocustCommanders` AS `l0` +"""); + } + + public override async Task Select_datetimeoffset_comparison_in_projection(bool async) + { + await base.Select_datetimeoffset_comparison_in_projection(async); + + AssertSql( +""" +SELECT `m`.`Timeline` > UTC_TIMESTAMP() +FROM `Missions` AS `m` +"""); + } + + public override async Task OfType_in_subquery_works(bool async) + { + await base.OfType_in_subquery_works(async); + + AssertSql( +""" +SELECT `t0`.`Name`, `t0`.`Location`, `t0`.`Nation` +FROM `Officers` AS `o` +INNER JOIN ( + SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation`, `t`.`LeaderNickname`, `t`.`LeaderSquadId` + FROM ( + SELECT `o0`.`AssignedCityName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t` + LEFT JOIN `Cities` AS `c` ON `t`.`AssignedCityName` = `c`.`Name` +) AS `t0` ON (`o`.`Nickname` = `t0`.`LeaderNickname`) AND (`o`.`SquadId` = `t0`.`LeaderSquadId`) +"""); + } + + public override async Task Nullable_bool_comparison_is_translated_to_server(bool async) + { + await base.Nullable_bool_comparison_is_translated_to_server(async); + + AssertSql( +""" +SELECT (`l`.`Eradicated` = TRUE) AND (`l`.`Eradicated` IS NOT NULL) AS `IsEradicated` +FROM `LocustHordes` AS `l` +"""); + } + + public override async Task Accessing_reference_navigation_collection_composition_generates_single_query(bool async) + { + await base.Accessing_reference_navigation_collection_composition_generates_single_query(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`Id0` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`IsAutomatic`, `w0`.`Name`, `w0`.`Id` AS `Id0`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id` +"""); + } + + public override async Task Reference_include_chain_loads_correctly_when_middle_is_null(bool async) + { + await base.Reference_include_chain_loads_correctly_when_middle_is_null(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`GearNickName`, `t`.`GearSquadId`, `t`.`IssueDate`, `t`.`Note`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` +ORDER BY `t`.`Note` +"""); + } + + public override async Task Accessing_property_of_optional_navigation_in_child_projection_works(bool async) + { + await base.Accessing_property_of_optional_navigation_in_child_projection_works(async); + + AssertSql( +""" +SELECT `t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL), `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Nickname`, `t1`.`Id`, `t1`.`SquadId` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN ( + SELECT `t2`.`Nickname`, `w`.`Id`, `t2`.`SquadId`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t2` ON `w`.`OwnerFullName` = `t2`.`FullName` +) AS `t1` ON `t0`.`FullName` = `t1`.`OwnerFullName` +ORDER BY `t`.`Note`, `t`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t1`.`Id`, `t1`.`Nickname` +"""); + } + + public override async Task Collection_navigation_ofType_filter_works(bool async) + { + await base.Collection_navigation_ofType_filter_works(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`c`.`Name` = `t`.`CityOfBirthName`) AND (`t`.`Nickname` = 'Marcus')) +"""); + } + + public override async Task Query_reusing_parameter_doesnt_declare_duplicate_parameter(bool async) + { + await base.Query_reusing_parameter_doesnt_declare_duplicate_parameter(async); + + AssertSql( +""" +@__prm_Inner_Nickname_0='Marcus' (Size = 255) + +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT DISTINCT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`t`.`Nickname` <> @__prm_Inner_Nickname_0) AND (`t`.`Nickname` <> @__prm_Inner_Nickname_0) +) AS `t0` +ORDER BY `t0`.`FullName` +"""); + } + + public override async Task Query_reusing_parameter_with_inner_query_doesnt_declare_duplicate_parameter(bool async) + { + await base.Query_reusing_parameter_with_inner_query_doesnt_declare_duplicate_parameter(async); + + AssertSql( +""" +@__squadId_0='1' + +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + INNER JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` + WHERE EXISTS ( + SELECT 1 + FROM `Squads` AS `s0` + WHERE (`s0`.`Id` = @__squadId_0) AND (`s0`.`Id` = `s`.`Id`)) + UNION ALL + SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` + ) AS `t1` + INNER JOIN `Squads` AS `s1` ON `t1`.`SquadId` = `s1`.`Id` + WHERE EXISTS ( + SELECT 1 + FROM `Squads` AS `s2` + WHERE (`s2`.`Id` = @__squadId_0) AND (`s2`.`Id` = `s1`.`Id`)) +) AS `t0` +ORDER BY `t0`.`FullName` +"""); + } + + public override async Task Query_reusing_parameter_with_inner_query_expression_doesnt_declare_duplicate_parameter(bool async) + { + await base.Query_reusing_parameter_with_inner_query_expression_doesnt_declare_duplicate_parameter(async); + + AssertSql( +""" +@__gearId_0='1' + +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE ((`s`.`Id` = `t`.`SquadId`) AND (`t`.`SquadId` = @__gearId_0)) AND (`t`.`SquadId` = @__gearId_0)) +"""); + } + + public override async Task Query_reusing_parameter_doesnt_declare_duplicate_parameter_complex(bool async) + { + await base.Query_reusing_parameter_doesnt_declare_duplicate_parameter_complex(async); + + AssertSql( +""" +@__entity_equality_prm_Inner_Squad_0_Id='1' (Nullable = true) + +SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT DISTINCT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + INNER JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` + WHERE `s`.`Id` = @__entity_equality_prm_Inner_Squad_0_Id +) AS `t0` +INNER JOIN `Squads` AS `s0` ON `t0`.`SquadId` = `s0`.`Id` +WHERE `s0`.`Id` = @__entity_equality_prm_Inner_Squad_0_Id +ORDER BY `t0`.`FullName` +"""); + } + + public override async Task Complex_GroupBy_after_set_operator(bool async) + { + await base.Complex_GroupBy_after_set_operator(async); + + AssertSql( +""" +SELECT `t0`.`Name`, `t0`.`Count`, COALESCE(SUM(`t0`.`Count`), 0) AS `Sum` +FROM ( + SELECT `c`.`Name`, ( + SELECT COUNT(*) + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`) AS `Count` + FROM ( + SELECT `g`.`AssignedCityName`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`AssignedCityName`, `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` + LEFT JOIN `Cities` AS `c` ON `t`.`AssignedCityName` = `c`.`Name` + UNION ALL + SELECT `c0`.`Name`, ( + SELECT COUNT(*) + FROM `Weapons` AS `w0` + WHERE `t1`.`FullName` = `w0`.`OwnerFullName`) AS `Count` + FROM ( + SELECT `g0`.`CityOfBirthName`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`CityOfBirthName`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t1` + INNER JOIN `Cities` AS `c0` ON `t1`.`CityOfBirthName` = `c0`.`Name` +) AS `t0` +GROUP BY `t0`.`Name`, `t0`.`Count` +"""); + } + + public override async Task Complex_GroupBy_after_set_operator_using_result_selector(bool async) + { + await base.Complex_GroupBy_after_set_operator_using_result_selector(async); + + AssertSql( +""" +SELECT `t0`.`Name`, `t0`.`Count`, COALESCE(SUM(`t0`.`Count`), 0) AS `Sum` +FROM ( + SELECT `c`.`Name`, ( + SELECT COUNT(*) + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`) AS `Count` + FROM ( + SELECT `g`.`AssignedCityName`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`AssignedCityName`, `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` + LEFT JOIN `Cities` AS `c` ON `t`.`AssignedCityName` = `c`.`Name` + UNION ALL + SELECT `c0`.`Name`, ( + SELECT COUNT(*) + FROM `Weapons` AS `w0` + WHERE `t1`.`FullName` = `w0`.`OwnerFullName`) AS `Count` + FROM ( + SELECT `g0`.`CityOfBirthName`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`CityOfBirthName`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t1` + INNER JOIN `Cities` AS `c0` ON `t1`.`CityOfBirthName` = `c0`.`Name` +) AS `t0` +GROUP BY `t0`.`Name`, `t0`.`Count` +"""); + } + + public override async Task Left_join_with_GroupBy_with_composite_group_key(bool async) + { + await base.Left_join_with_GroupBy_with_composite_group_key(async); + + AssertSql( +""" +SELECT `t`.`CityOfBirthName`, `t`.`HasSoulPatch` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`CityOfBirthName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`CityOfBirthName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` +LEFT JOIN `Tags` AS `t0` ON `t`.`Nickname` = `t0`.`GearNickName` +GROUP BY `t`.`CityOfBirthName`, `t`.`HasSoulPatch` +"""); + } + + public override async Task GroupBy_with_boolean_grouping_key(bool async) + { + await base.GroupBy_with_boolean_grouping_key(async); + + AssertSql( +""" +SELECT `t0`.`CityOfBirthName`, `t0`.`HasSoulPatch`, `t0`.`IsMarcus`, COUNT(*) AS `Count` +FROM ( + SELECT `t`.`CityOfBirthName`, `t`.`HasSoulPatch`, `t`.`Nickname` = 'Marcus' AS `IsMarcus` + FROM ( + SELECT `g`.`Nickname`, `g`.`CityOfBirthName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`CityOfBirthName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` + ) AS `t` +) AS `t0` +GROUP BY `t0`.`CityOfBirthName`, `t0`.`HasSoulPatch`, `t0`.`IsMarcus` +"""); + } + + public override async Task GroupBy_with_boolean_groupin_key_thru_navigation_access(bool async) + { + await base.GroupBy_with_boolean_groupin_key_thru_navigation_access(async); + + AssertSql( +""" +SELECT `t0`.`HasSoulPatch`, LOWER(`s`.`Name`) AS `Name` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +LEFT JOIN `Squads` AS `s` ON `t0`.`SquadId` = `s`.`Id` +GROUP BY `t0`.`HasSoulPatch`, `s`.`Name` +"""); + } + + public override async Task Group_by_over_projection_with_multiple_properties_accessed_thru_navigation(bool async) + { + await base.Group_by_over_projection_with_multiple_properties_accessed_thru_navigation(async); + + AssertSql( +""" +SELECT `c`.`Name` +FROM ( + SELECT `g`.`CityOfBirthName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`CityOfBirthName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +GROUP BY `c`.`Name` +"""); + } + + public override async Task Group_by_on_StartsWith_with_null_parameter_as_argument(bool async) + { + await base.Group_by_on_StartsWith_with_null_parameter_as_argument(async); + + AssertSql( +""" +SELECT `t0`.`Key` +FROM ( + SELECT FALSE AS `Key` + FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` + ) AS `t` +) AS `t0` +GROUP BY `t0`.`Key` +"""); + } + + public override async Task Group_by_with_having_StartsWith_with_null_parameter_as_argument(bool async) + { + await base.Group_by_with_having_StartsWith_with_null_parameter_as_argument(async); + + AssertSql( +""" +SELECT `t`.`FullName` +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +GROUP BY `t`.`FullName` +HAVING FALSE +"""); + } + + public override async Task Select_StartsWith_with_null_parameter_as_argument(bool async) + { + await base.Select_StartsWith_with_null_parameter_as_argument(async); + + AssertSql( +""" +SELECT FALSE +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Select_null_parameter_is_not_null(bool async) + { + await base.Select_null_parameter_is_not_null(async); + + AssertSql( +""" +@__p_0='False' + +SELECT @__p_0 +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Where_null_parameter_is_not_null(bool async) + { + await base.Where_null_parameter_is_not_null(async); + + AssertSql( +""" +@__p_0='False' + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE @__p_0 +"""); + } + + public override async Task OrderBy_StartsWith_with_null_parameter_as_argument(bool async) + { + await base.OrderBy_StartsWith_with_null_parameter_as_argument(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task OrderBy_Contains_empty_list(bool async) + { + await base.OrderBy_Contains_empty_list(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Where_with_enum_flags_parameter(bool async) + { + await base.Where_with_enum_flags_parameter(async); + + AssertSql( +""" +@__rank_0='1' (Nullable = true) + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & @__rank_0) = @__rank_0 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +""", + // + """ +@__rank_0='2' (Nullable = true) + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` | @__rank_0) <> @__rank_0 +""", + // + """ +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE FALSE +"""); + } + + public override async Task FirstOrDefault_navigation_access_entity_equality_in_where_predicate_apply_peneding_selector(bool async) + { + await base.FirstOrDefault_navigation_access_entity_equality_in_where_predicate_apply_peneding_selector(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +LEFT JOIN `Cities` AS `c` ON `l`.`CapitalName` = `c`.`Name` +WHERE (`c`.`Name` = ( + SELECT `c0`.`Name` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + INNER JOIN `Cities` AS `c0` ON `t`.`CityOfBirthName` = `c0`.`Name` + ORDER BY `t`.`Nickname` + LIMIT 1)) OR (`c`.`Name` IS NULL AND (( + SELECT `c0`.`Name` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + INNER JOIN `Cities` AS `c0` ON `t`.`CityOfBirthName` = `c0`.`Name` + ORDER BY `t`.`Nickname` + LIMIT 1) IS NULL)) +"""); + } + + public override async Task Bitwise_operation_with_non_null_parameter_optimizes_null_checks(bool async) + { + await base.Bitwise_operation_with_non_null_parameter_optimizes_null_checks(async); + + AssertSql( +""" +@__ranks_0='134' + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`Rank` & @__ranks_0) <> 0 +""", + // + """ +@__ranks_0='134' + +SELECT (`t`.`Rank` | @__ranks_0) = @__ranks_0 +FROM ( + SELECT `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +""", + // + """ +@__ranks_0='134' + +SELECT (`t`.`Rank` | (`t`.`Rank` | (@__ranks_0 | (`t`.`Rank` | @__ranks_0)))) = @__ranks_0 +FROM ( + SELECT `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Bitwise_operation_with_null_arguments(bool async) + { + await base.Bitwise_operation_with_null_arguments(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` IS NULL +""", + // + """ +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` IS NULL +""", + // + """ +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` IS NULL +""", + // + """ +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +""", + // + """ +@__prm_0='2' (Nullable = true) + +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE ((`w`.`AmmunitionType` & @__prm_0) <> 0) OR `w`.`AmmunitionType` IS NULL +""", + // + """ +@__prm_0='1' (Nullable = true) + +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE (`w`.`AmmunitionType` & @__prm_0) = @__prm_0 +"""); + } + + public override async Task Logical_operation_with_non_null_parameter_optimizes_null_checks(bool async) + { + await base.Logical_operation_with_non_null_parameter_optimizes_null_checks(async); + + AssertSql( +""" +@__prm_0='True' + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` <> @__prm_0 +""", + // + """ +@__prm_0='False' + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE `t`.`HasSoulPatch` <> @__prm_0 +"""); + } + + public override async Task Cast_OfType_works_correctly(bool async) + { + await base.Cast_OfType_works_correctly(async); + + AssertSql( +""" +SELECT `o`.`FullName` +FROM `Officers` AS `o` +"""); + } + + public override async Task Join_inner_source_custom_projection_followed_by_filter(bool async) + { + await base.Join_inner_source_custom_projection_followed_by_filter(async); + + AssertSql( +""" +SELECT CASE + WHEN `l`.`Name` = 'Locust' THEN TRUE + ELSE NULL +END AS `IsEradicated`, `l`.`CommanderName`, `l`.`Name` +FROM ( + SELECT `l0`.`Name` + FROM `LocustLeaders` AS `l0` + UNION ALL + SELECT `l1`.`Name` + FROM `LocustCommanders` AS `l1` +) AS `t` +INNER JOIN `LocustHordes` AS `l` ON `t`.`Name` = `l`.`CommanderName` +WHERE (CASE + WHEN `l`.`Name` = 'Locust' THEN TRUE + ELSE NULL +END <> TRUE) OR (CASE + WHEN `l`.`Name` = 'Locust' THEN TRUE + ELSE NULL +END IS NULL) +"""); + } + + public override async Task Byte_array_contains_literal(bool async) + { + await base.Byte_array_contains_literal(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE LOCATE(0x01, `s`.`Banner`) > 0 +"""); + } + + public override async Task Byte_array_filter_by_length_literal(bool async) + { + await base.Byte_array_filter_by_length_literal(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE LENGTH(`s`.`Banner`) = 1 +"""); + } + + public override async Task Byte_array_filter_by_length_parameter(bool async) + { + await base.Byte_array_filter_by_length_parameter(async); + + AssertSql( +""" +@__p_0='1' + +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE LENGTH(`s`.`Banner`) = @__p_0 +"""); + } + + public override void Byte_array_filter_by_length_parameter_compiled() + { + base.Byte_array_filter_by_length_parameter_compiled(); + + AssertSql( +""" +@__byteArrayParam='0x2A80' (Size = 8000) + +SELECT COUNT(*) +FROM `Squads` AS `s` +WHERE LENGTH(`s`.`Banner`) = LENGTH(@__byteArrayParam) +"""); + } + + public override async Task Byte_array_contains_parameter(bool async) + { + await base.Byte_array_contains_parameter(async); + + AssertSql( +""" +@__someByte_0='1' + +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE LOCATE(UNHEX(HEX(@__someByte_0)), `s`.`Banner`) > 0 +"""); + } + + public override async Task Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(bool async) + { + await base.Byte_array_filter_by_length_literal_does_not_cast_on_varbinary_n(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE LENGTH(`s`.`Banner5`) = 5 +"""); + } + + public override async Task Conditional_expression_with_test_being_simplified_to_constant_simple(bool isAsync) + { + await base.Conditional_expression_with_test_being_simplified_to_constant_simple(isAsync); + + AssertSql( +""" +@__prm_0='True' + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE CASE + WHEN `t`.`HasSoulPatch` = @__prm_0 THEN TRUE + ELSE FALSE +END +"""); + } + + public override async Task Conditional_expression_with_test_being_simplified_to_constant_complex(bool isAsync) + { + await base.Conditional_expression_with_test_being_simplified_to_constant_complex(isAsync); + + AssertSql( +""" +@__prm_0='True' +@__prm2_1='Dom's Lancer' (Size = 4000) + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE CASE + WHEN `t`.`HasSoulPatch` = @__prm_0 THEN (( + SELECT `w`.`Name` + FROM `Weapons` AS `w` + WHERE `w`.`Id` = `t`.`SquadId` + LIMIT 1) = @__prm2_1) AND ( + SELECT `w`.`Name` + FROM `Weapons` AS `w` + WHERE `w`.`Id` = `t`.`SquadId` + LIMIT 1) IS NOT NULL + ELSE FALSE +END +"""); + } + + public override async Task OrderBy_bool_coming_from_optional_navigation(bool async) + { + await base.OrderBy_bool_coming_from_optional_navigation(async); + + AssertSql( +""" +SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +ORDER BY `w0`.`IsAutomatic` +"""); + } + + public override async Task DateTimeOffset_Date_returns_datetime(bool async) + { + await base.DateTimeOffset_Date_returns_datetime(async); + + AssertSql( +""" +@__dateTimeOffset_Date_0='0002-03-01T00:00:00.0000000' (DbType = DateTime) + +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE CONVERT(`m`.`Timeline`, date) >= @__dateTimeOffset_Date_0 +"""); + } + + public override async Task Conditional_with_conditions_evaluating_to_false_gets_optimized(bool async) + { + await base.Conditional_with_conditions_evaluating_to_false_gets_optimized(async); + + AssertSql( +""" +SELECT `t`.`FullName` +FROM ( + SELECT `g`.`Nickname`, `g`.`CityOfBirthName`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`CityOfBirthName`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Conditional_with_conditions_evaluating_to_true_gets_optimized(bool async) + { + await base.Conditional_with_conditions_evaluating_to_true_gets_optimized(async); + + AssertSql( +""" +SELECT `t`.`CityOfBirthName` +FROM ( + SELECT `g`.`Nickname`, `g`.`CityOfBirthName`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`CityOfBirthName`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Projecting_required_string_column_compared_to_null_parameter(bool async) + { + await base.Projecting_required_string_column_compared_to_null_parameter(async); + + AssertSql( +""" +SELECT FALSE +FROM ( + SELECT `g`.`Nickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Byte_array_filter_by_SequenceEqual(bool isAsync) + { + await base.Byte_array_filter_by_SequenceEqual(isAsync); + + AssertSql( +""" +@__byteArrayParam_0='0x0405060708' (Size = 5) + +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE `s`.`Banner5` = @__byteArrayParam_0 +"""); + } + + public override async Task Group_by_nullable_property_HasValue_and_project_the_grouping_key(bool async) + { + await base.Group_by_nullable_property_HasValue_and_project_the_grouping_key(async); + + AssertSql( +""" +SELECT `t`.`Key` +FROM ( + SELECT `w`.`SynergyWithId` IS NOT NULL AS `Key` + FROM `Weapons` AS `w` +) AS `t` +GROUP BY `t`.`Key` +"""); + } + + public override async Task Group_by_nullable_property_and_project_the_grouping_key_HasValue(bool async) + { + await base.Group_by_nullable_property_and_project_the_grouping_key_HasValue(async); + + AssertSql( +""" +SELECT `w`.`SynergyWithId` IS NOT NULL +FROM `Weapons` AS `w` +GROUP BY `w`.`SynergyWithId` +"""); + } + + public override async Task Checked_context_with_cast_does_not_fail(bool isAsync) + { + await base.Checked_context_with_cast_does_not_fail(isAsync); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE CAST(`t`.`ThreatLevel` AS unsigned) >= 5 +"""); + } + + public override async Task Checked_context_with_addition_does_not_fail(bool isAsync) + { + await base.Checked_context_with_addition_does_not_fail(isAsync); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE CAST(`t`.`ThreatLevel` AS signed) >= (5 + CAST(`t`.`ThreatLevel` AS signed)) +"""); + } + + public override async Task TimeSpan_Hours(bool async) + { + await base.TimeSpan_Hours(async); + + AssertSql( +""" +SELECT EXTRACT(hour FROM `m`.`Duration`) +FROM `Missions` AS `m` +"""); + } + + public override async Task TimeSpan_Minutes(bool async) + { + await base.TimeSpan_Minutes(async); + + AssertSql( +""" +SELECT EXTRACT(minute FROM `m`.`Duration`) +FROM `Missions` AS `m` +"""); + } + + public override async Task TimeSpan_Seconds(bool async) + { + await base.TimeSpan_Seconds(async); + + AssertSql( +""" +SELECT EXTRACT(second FROM `m`.`Duration`) +FROM `Missions` AS `m` +"""); + } + + public override async Task TimeSpan_Milliseconds(bool async) + { + await base.TimeSpan_Milliseconds(async); + + AssertSql( +""" +SELECT (EXTRACT(microsecond FROM `m`.`Duration`)) DIV (1000) +FROM `Missions` AS `m` +"""); + } + + public override async Task Where_TimeSpan_Hours(bool async) + { + await base.Where_TimeSpan_Hours(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(hour FROM `m`.`Duration`) = 1 +"""); + } + + public override async Task Where_TimeSpan_Minutes(bool async) + { + await base.Where_TimeSpan_Minutes(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(minute FROM `m`.`Duration`) = 1 +"""); + } + + public override async Task Where_TimeSpan_Seconds(bool async) + { + await base.Where_TimeSpan_Seconds(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(second FROM `m`.`Duration`) = 1 +"""); + } + + public override async Task Where_TimeSpan_Milliseconds(bool async) + { + await base.Where_TimeSpan_Milliseconds(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE (EXTRACT(microsecond FROM `m`.`Duration`)) DIV (1000) = 1 +"""); + } + + public override async Task Contains_on_collection_of_byte_subquery(bool async) + { + await base.Contains_on_collection_of_byte_subquery(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` + ) AS `t0` + WHERE `t0`.`ThreatLevelByte` = `t`.`ThreatLevelByte`) +"""); + } + + public override async Task Contains_on_collection_of_nullable_byte_subquery(bool async) + { + await base.Contains_on_collection_of_nullable_byte_subquery(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` + ) AS `t0` + WHERE (`t0`.`ThreatLevelNullableByte` = `t`.`ThreatLevelNullableByte`) OR (`t0`.`ThreatLevelNullableByte` IS NULL AND (`t`.`ThreatLevelNullableByte` IS NULL))) +"""); + } + + public override async Task Contains_on_collection_of_nullable_byte_subquery_null_constant(bool async) + { + await base.Contains_on_collection_of_nullable_byte_subquery_null_constant(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` + ) AS `t0` + WHERE `t0`.`ThreatLevelNullableByte` IS NULL) +"""); + } + + public override async Task Contains_on_collection_of_nullable_byte_subquery_null_parameter(bool async) + { + await base.Contains_on_collection_of_nullable_byte_subquery_null_parameter(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` + ) AS `t0` + WHERE `t0`.`ThreatLevelNullableByte` IS NULL) +"""); + } + + public override async Task Contains_on_byte_array_property_using_byte_column(bool async) + { + await base.Contains_on_byte_array_property_using_byte_column(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name`, `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM `Squads` AS `s` +CROSS JOIN ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE LOCATE(UNHEX(HEX(`t`.`ThreatLevelByte`)), `s`.`Banner`) > 0 +"""); + } + + public override async Task Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion( + bool async) + { + await base.Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion(async); + + AssertSql( +""" +SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM ( + SELECT `l`.`ThreatLevelByte` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`ThreatLevelByte` + FROM `LocustCommanders` AS `l0` +) AS `t` +JOIN LATERAL ( + SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t0` + WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` + ) AS `t2` + WHERE `t2`.`ThreatLevelByte` = `t`.`ThreatLevelByte`) +) AS `t1` ON TRUE +"""); + } + + public override async Task Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion_negated( + bool async) + { + await base.Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion_negated(async); + + AssertSql( +""" +SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM ( + SELECT `l`.`ThreatLevelByte` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`ThreatLevelByte` + FROM `LocustCommanders` AS `l0` +) AS `t` +JOIN LATERAL ( + SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t0` + WHERE NOT (EXISTS ( + SELECT 1 + FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` + ) AS `t2` + WHERE `t2`.`ThreatLevelByte` = `t`.`ThreatLevelByte`)) +) AS `t1` ON TRUE +"""); + } + + public override async Task Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion(bool async) + { + await base.Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion(async); + + AssertSql( +""" +SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM ( + SELECT `l`.`ThreatLevelNullableByte` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`ThreatLevelNullableByte` + FROM `LocustCommanders` AS `l0` +) AS `t` +JOIN LATERAL ( + SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t0` + WHERE EXISTS ( + SELECT 1 + FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` + ) AS `t2` + WHERE (`t2`.`ThreatLevelNullableByte` = `t`.`ThreatLevelNullableByte`) OR (`t2`.`ThreatLevelNullableByte` IS NULL AND (`t`.`ThreatLevelNullableByte` IS NULL))) +) AS `t1` ON TRUE +"""); + } + + public override async Task Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion_negated(bool async) + { + await base.Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion_negated(async); + + AssertSql( +""" +SELECT `t1`.`Nickname`, `t1`.`SquadId`, `t1`.`AssignedCityName`, `t1`.`CityOfBirthName`, `t1`.`FullName`, `t1`.`HasSoulPatch`, `t1`.`LeaderNickname`, `t1`.`LeaderSquadId`, `t1`.`Rank`, `t1`.`Discriminator` +FROM ( + SELECT `l`.`ThreatLevelNullableByte` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`ThreatLevelNullableByte` + FROM `LocustCommanders` AS `l0` +) AS `t` +JOIN LATERAL ( + SELECT `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t0` + WHERE NOT (EXISTS ( + SELECT 1 + FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` + ) AS `t2` + WHERE (`t2`.`ThreatLevelNullableByte` = `t`.`ThreatLevelNullableByte`) OR (`t2`.`ThreatLevelNullableByte` IS NULL AND (`t`.`ThreatLevelNullableByte` IS NULL)))) +) AS `t1` ON TRUE +"""); + } + + public override async Task Enum_closure_typed_as_underlying_type_generates_correct_parameter_type(bool async) + { + await base.Enum_closure_typed_as_underlying_type_generates_correct_parameter_type(async); + + AssertSql( +""" +@__prm_0='1' (Nullable = true) + +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE @__prm_0 = `w`.`AmmunitionType` +"""); + } + + public override async Task Enum_flags_closure_typed_as_underlying_type_generates_correct_parameter_type(bool async) + { + await base.Enum_flags_closure_typed_as_underlying_type_generates_correct_parameter_type(async); + + AssertSql( +""" +@__prm_0='133' + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (@__prm_0 & `t`.`Rank`) = `t`.`Rank` +"""); + } + + public override async Task Enum_flags_closure_typed_as_different_type_generates_correct_parameter_type(bool async) + { + await base.Enum_flags_closure_typed_as_different_type_generates_correct_parameter_type(async); + + AssertSql( +""" +@__prm_0='5' + +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (@__prm_0 & CAST(`t`.`Rank` AS signed)) = CAST(`t`.`Rank` AS signed) +"""); + } + + public override async Task Constant_enum_with_same_underlying_value_as_previously_parameterized_int(bool async) + { + await base.Constant_enum_with_same_underlying_value_as_previously_parameterized_int(async); + + AssertSql( +""" +@__p_0='1' + +SELECT `t`.`Rank` & 1 +FROM ( + SELECT `g`.`Nickname`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +ORDER BY `t`.`Nickname` +LIMIT @__p_0 +"""); + } + + public override async Task Enum_array_contains(bool async) + { + await base.Enum_array_contains(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +WHERE `w0`.`Id` IS NOT NULL AND ((`w0`.`AmmunitionType` = 1) OR `w0`.`AmmunitionType` IS NULL) +"""); + } + + public override async Task CompareTo_used_with_non_unicode_string_column_and_constant(bool async) + { + await base.CompareTo_used_with_non_unicode_string_column_and_constant(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE `c`.`Location` = 'Unknown' +"""); + } + + public override async Task Coalesce_used_with_non_unicode_string_column_and_constant(bool async) + { + await base.Coalesce_used_with_non_unicode_string_column_and_constant(async); + + AssertSql( +""" +SELECT COALESCE(`c`.`Location`, 'Unknown') +FROM `Cities` AS `c` +"""); + } + + public override async Task Groupby_anonymous_type_with_navigations_followed_up_by_anonymous_projection_and_orderby(bool async) + { + await base.Groupby_anonymous_type_with_navigations_followed_up_by_anonymous_projection_and_orderby(async); + + AssertSql( +""" +SELECT `c`.`Name`, `c`.`Location`, COUNT(*) AS `Count` +FROM `Weapons` AS `w` +LEFT JOIN ( + SELECT `g`.`CityOfBirthName`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`CityOfBirthName`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` ON `w`.`OwnerFullName` = `t`.`FullName` +LEFT JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +GROUP BY `c`.`Name`, `c`.`Location` +ORDER BY `c`.`Location` +"""); + } + + public override async Task SelectMany_predicate_with_non_equality_comparison_converted_to_inner_join(bool async) + { + await base.SelectMany_predicate_with_non_equality_comparison_converted_to_inner_join(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Weapons` AS `w` ON (`t`.`FullName` <> `w`.`OwnerFullName`) OR `w`.`OwnerFullName` IS NULL +ORDER BY `t`.`Nickname`, `w`.`Id` +"""); + } + + public override async Task SelectMany_predicate_with_non_equality_comparison_DefaultIfEmpty_converted_to_left_join(bool async) + { + await base.SelectMany_predicate_with_non_equality_comparison_DefaultIfEmpty_converted_to_left_join(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON (`t`.`FullName` <> `w`.`OwnerFullName`) OR `w`.`OwnerFullName` IS NULL +ORDER BY `t`.`Nickname`, `w`.`Id` +"""); + } + + public override async Task SelectMany_predicate_after_navigation_with_non_equality_comparison_DefaultIfEmpty_converted_to_left_join( + bool async) + { + await base.SelectMany_predicate_after_navigation_with_non_equality_comparison_DefaultIfEmpty_converted_to_left_join(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId` + FROM `Weapons` AS `w` + LEFT JOIN `Weapons` AS `w0` ON `w`.`SynergyWithId` = `w0`.`Id` +) AS `t0` ON (`t`.`FullName` <> `t0`.`OwnerFullName`) OR `t0`.`OwnerFullName` IS NULL +ORDER BY `t`.`Nickname`, `t0`.`Id` +"""); + } + + public override async Task SelectMany_without_result_selector_and_non_equality_comparison_converted_to_join(bool async) + { + await base.SelectMany_without_result_selector_and_non_equality_comparison_converted_to_join(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON (`t`.`FullName` <> `w`.`OwnerFullName`) OR `w`.`OwnerFullName` IS NULL +"""); + } + + public override async Task Filtered_collection_projection_with_order_comparison_predicate_converted_to_join(bool async) + { + await base.Filtered_collection_projection_with_order_comparison_predicate_converted_to_join(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON (`t`.`FullName` = `w`.`OwnerFullName`) AND (`t`.`SquadId` < `w`.`Id`) +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Filtered_collection_projection_with_order_comparison_predicate_converted_to_join2(bool async) + { + await base.Filtered_collection_projection_with_order_comparison_predicate_converted_to_join2(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON (`t`.`FullName` = `w`.`OwnerFullName`) AND (`t`.`SquadId` <= `w`.`Id`) +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Filtered_collection_projection_with_order_comparison_predicate_converted_to_join3(bool async) + { + await base.Filtered_collection_projection_with_order_comparison_predicate_converted_to_join3(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Weapons` AS `w` ON (`t`.`FullName` = `w`.`OwnerFullName`) AND (`t`.`SquadId` >= `w`.`Id`) +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task SelectMany_predicate_with_non_equality_comparison_with_Take_doesnt_convert_to_join(bool async) + { + await base.SelectMany_predicate_with_non_equality_comparison_with_Take_doesnt_convert_to_join(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +JOIN LATERAL ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` + FROM `Weapons` AS `w` + WHERE (`w`.`OwnerFullName` <> `t`.`FullName`) OR `w`.`OwnerFullName` IS NULL + ORDER BY `w`.`Id` + LIMIT 3 +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t0`.`Id` +"""); + } + + public override async Task FirstOrDefault_over_int_compared_to_zero(bool async) + { + await base.FirstOrDefault_over_int_compared_to_zero(async); + + AssertSql( +""" +SELECT `s`.`Name` +FROM `Squads` AS `s` +WHERE (`s`.`Name` = 'Kilo') AND (COALESCE(( + SELECT `t`.`SquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE (`s`.`Id` = `t`.`SquadId`) AND (`t`.`HasSoulPatch` = TRUE) + LIMIT 1), 0) <> 0) +"""); + } + + public override async Task Correlated_collection_with_inner_collection_references_element_two_levels_up(bool async) + { + await base.Correlated_collection_with_inner_collection_references_element_two_levels_up(async); + + AssertSql( +""" +SELECT `t`.`FullName`, `t`.`Nickname`, `t`.`SquadId`, `t0`.`ReportName`, `t0`.`OfficerName`, `t0`.`Nickname`, `t0`.`SquadId` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `t1`.`FullName` AS `ReportName`, `t`.`FullName` AS `OfficerName`, `t1`.`Nickname`, `t1`.`SquadId` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`LeaderNickname`, `g`.`LeaderSquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`FullName`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE (`t`.`Nickname` = `t1`.`LeaderNickname`) AND (`t`.`SquadId` = `t1`.`LeaderSquadId`) +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task Accessing_derived_property_using_hard_and_soft_cast(bool async) + { + await base.Accessing_derived_property_using_hard_and_soft_cast(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE (`t`.`Discriminator` = 'LocustCommander') AND ((`t`.`HighCommandId` <> 0) OR `t`.`HighCommandId` IS NULL) +""", + // + """ +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +WHERE (`t`.`Discriminator` = 'LocustCommander') AND ((`t`.`HighCommandId` <> 0) OR `t`.`HighCommandId` IS NULL) +"""); + } + + public override async Task Cast_to_derived_followed_by_include_and_FirstOrDefault(bool async) + { + await base.Cast_to_derived_followed_by_include_and_FirstOrDefault(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +WHERE `t`.`Name` LIKE '%Queen%' +LIMIT 1 +"""); + } + + public override async Task Correlated_collection_take(bool async) + { + await base.Correlated_collection_take(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `c`.`Name`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId`, `c`.`Location`, `c`.`Nation` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`CityOfBirthName`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`CityOfBirthName`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +LEFT JOIN ( + SELECT `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId` + FROM ( + SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, ROW_NUMBER() OVER(PARTITION BY `w`.`OwnerFullName` ORDER BY `w`.`Id`) AS `row` + FROM `Weapons` AS `w` + ) AS `t1` + WHERE `t1`.`row` <= 10 +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `c`.`Name` +"""); + } + + public override async Task First_on_byte_array(bool async) + { + await base.First_on_byte_array(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE ASCII(`s`.`Banner`) = 2 +"""); + } + + public override async Task Array_access_on_byte_array(bool async) + { + await base.Array_access_on_byte_array(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE ASCII(SUBSTRING(`s`.`Banner5`, 2 + 1, 1)) = 6 +"""); + } + + public override async Task Project_shadow_properties(bool async) + { + await base.Project_shadow_properties(async); + + AssertSql( +""" +SELECT `g`.`Nickname`, `g`.`AssignedCityName` +FROM `Gears` AS `g` +UNION ALL +SELECT `o`.`Nickname`, `o`.`AssignedCityName` +FROM `Officers` AS `o` +"""); + } + + public override async Task Composite_key_entity_equal(bool async) + { + await base.Composite_key_entity_equal(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` +WHERE (`t`.`Nickname` = `t0`.`Nickname`) AND (`t`.`SquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Composite_key_entity_not_equal(bool async) + { + await base.Composite_key_entity_not_equal(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +CROSS JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` +WHERE (`t`.`Nickname` <> `t0`.`Nickname`) OR (`t`.`SquadId` <> `t0`.`SquadId`) +"""); + } + + public override async Task Composite_key_entity_equal_null(bool async) + { + await base.Composite_key_entity_equal_null(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, `l`.`DefeatedByNickname`, `l`.`DefeatedBySquadId`, `l`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +WHERE `t0`.`Nickname` IS NULL OR (`t0`.`SquadId` IS NULL) +"""); + } + + public override async Task Composite_key_entity_not_equal_null(bool async) + { + await base.Composite_key_entity_not_equal_null(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, `l`.`DefeatedByNickname`, `l`.`DefeatedBySquadId`, `l`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +WHERE `t0`.`Nickname` IS NOT NULL AND (`t0`.`SquadId` IS NOT NULL) +"""); + } + + public override async Task Projecting_property_converted_to_nullable_with_comparison(bool async) + { + await base.Projecting_property_converted_to_nullable_with_comparison(async); + + AssertSql( +""" +SELECT `t`.`Note`, `t`.`GearNickName` IS NOT NULL, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`HasSoulPatch` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END = 1 +"""); + } + + public override async Task Projecting_property_converted_to_nullable_with_addition(bool async) + { + await base.Projecting_property_converted_to_nullable_with_addition(async); + + AssertSql( +""" +SELECT `t`.`Note`, `t`.`GearNickName` IS NOT NULL, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`HasSoulPatch` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE (CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END + 1) = 2 +"""); + } + + public override async Task Projecting_property_converted_to_nullable_with_addition_and_final_projection(bool async) + { + await base.Projecting_property_converted_to_nullable_with_addition_and_final_projection(async); + + AssertSql( +""" +SELECT `t`.`Note`, CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END + 1 AS `Value` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`Nickname` + ELSE NULL +END IS NOT NULL +"""); + } + + public override async Task Projecting_property_converted_to_nullable_with_conditional(bool async) + { + await base.Projecting_property_converted_to_nullable_with_conditional(async); + + AssertSql( +""" +SELECT CASE + WHEN (`t`.`Note` <> 'K.I.A.') OR `t`.`Note` IS NULL THEN CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL + END + ELSE -1 +END +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Projecting_property_converted_to_nullable_with_function_call(bool async) + { + await base.Projecting_property_converted_to_nullable_with_function_call(async); + + AssertSql( +""" +SELECT SUBSTRING(CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`Nickname` + ELSE NULL +END, 0 + 1, 3) +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Projecting_property_converted_to_nullable_with_function_call2(bool async) + { + await base.Projecting_property_converted_to_nullable_with_function_call2(async); + + AssertSql( +""" +SELECT `t`.`Note`, SUBSTRING(`t`.`Note`, 0 + 1, CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END) AS `Function` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`Nickname` + ELSE NULL +END IS NOT NULL +"""); + } + + public override async Task Projecting_property_converted_to_nullable_into_element_init(bool async) + { + await base.Projecting_property_converted_to_nullable_into_element_init(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN CHAR_LENGTH(`t0`.`Nickname`) + ELSE NULL +END, CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END, CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END + 1 +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`Nickname` + ELSE NULL +END IS NOT NULL +ORDER BY `t`.`Note` +"""); + } + + public override async Task Projecting_property_converted_to_nullable_into_member_assignment(bool async) + { + await base.Projecting_property_converted_to_nullable_into_member_assignment(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END AS `Id` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`Nickname` + ELSE NULL +END IS NOT NULL +ORDER BY `t`.`Note` +"""); + } + + public override async Task Projecting_property_converted_to_nullable_into_new_array(bool async) + { + await base.Projecting_property_converted_to_nullable_into_new_array(async); + + AssertSql( +""" +SELECT CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN CHAR_LENGTH(`t0`.`Nickname`) + ELSE NULL +END, CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END, CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END + 1 +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`Nickname` + ELSE NULL +END IS NOT NULL +ORDER BY `t`.`Note` +"""); + } + + public override async Task Projecting_property_converted_to_nullable_into_unary(bool async) + { + await base.Projecting_property_converted_to_nullable_into_unary(async); + + AssertSql( +""" +SELECT `t`.`Note` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`Nickname` + ELSE NULL +END IS NOT NULL AND NOT (CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`HasSoulPatch` + ELSE NULL +END) +ORDER BY `t`.`Note` +"""); + } + + public override async Task Projecting_property_converted_to_nullable_into_member_access(bool async) + { + await base.Projecting_property_converted_to_nullable_into_member_access(async); + + AssertSql( +""" +SELECT `t`.`Nickname` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`CityOfBirthName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`CityOfBirthName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE (EXTRACT(month FROM `t0`.`IssueDate`) <> 5) OR EXTRACT(month FROM `t0`.`IssueDate`) IS NULL +ORDER BY `t`.`Nickname` +"""); + } + + public override async Task Projecting_property_converted_to_nullable_and_use_it_in_order_by(bool async) + { + await base.Projecting_property_converted_to_nullable_and_use_it_in_order_by(async); + + AssertSql( +""" +SELECT `t`.`Note`, `t`.`GearNickName` IS NOT NULL, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`HasSoulPatch` +FROM `Tags` AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`GearNickName` = `t0`.`Nickname`) AND (`t`.`GearSquadId` = `t0`.`SquadId`) +WHERE CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`Nickname` + ELSE NULL +END IS NOT NULL +ORDER BY CASE + WHEN `t`.`GearNickName` IS NOT NULL THEN `t0`.`SquadId` + ELSE NULL +END, `t`.`Note` +"""); + } + + public override async Task Where_DateOnly_Year(bool async) + { + await base.Where_DateOnly_Year(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(year FROM `m`.`Date`) = 1990 +"""); + } + + public override async Task Where_DateOnly_Month(bool async) + { + await base.Where_DateOnly_Month(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(month FROM `m`.`Date`) = 11 +"""); + } + + public override async Task Where_DateOnly_Day(bool async) + { + await base.Where_DateOnly_Day(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(day FROM `m`.`Date`) = 10 +"""); + } + + public override async Task Where_DateOnly_DayOfYear(bool async) + { + await base.Where_DateOnly_DayOfYear(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE DAYOFYEAR(`m`.`Date`) = 314 +"""); + } + + public override async Task Where_DateOnly_DayOfWeek(bool async) + { + await base.Where_DateOnly_DayOfWeek(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE (DAYOFWEEK(`m`.`Date`) - 1) = 6 +"""); + } + + public override async Task Where_DateOnly_AddYears(bool async) + { + await base.Where_DateOnly_AddYears(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE DATE_ADD(`m`.`Date`, INTERVAL CAST(3 AS signed) year) = DATE '1993-11-10' +"""); + } + + public override async Task Where_DateOnly_AddMonths(bool async) + { + await base.Where_DateOnly_AddMonths(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE DATE_ADD(`m`.`Date`, INTERVAL CAST(3 AS signed) month) = DATE '1991-02-10' +"""); + } + + public override async Task Where_DateOnly_AddDays(bool async) + { + await base.Where_DateOnly_AddDays(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE DATE_ADD(`m`.`Date`, INTERVAL CAST(3 AS signed) day) = DATE '1990-11-13' +"""); + } + + public override async Task Where_TimeOnly_Hour(bool async) + { + await base.Where_TimeOnly_Hour(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(hour FROM `m`.`Time`) = 10 +"""); + } + + public override async Task Where_TimeOnly_Minute(bool async) + { + await base.Where_TimeOnly_Minute(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(minute FROM `m`.`Time`) = 15 +"""); + } + + public override async Task Where_TimeOnly_Second(bool async) + { + await base.Where_TimeOnly_Second(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE EXTRACT(second FROM `m`.`Time`) = 50 +"""); + } + + public override async Task Where_TimeOnly_Millisecond(bool async) + { + await base.Where_TimeOnly_Millisecond(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE (EXTRACT(microsecond FROM `m`.`Time`)) DIV (1000) = 500 +"""); + } + + public override async Task Where_TimeOnly_AddHours(bool async) + { + await base.Where_TimeOnly_AddHours(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE DATE_ADD(`m`.`Time`, INTERVAL CAST(3.0 AS signed) hour) = TIME '13:15:50.5' +"""); + } + + public override async Task Where_TimeOnly_AddMinutes(bool async) + { + await base.Where_TimeOnly_AddMinutes(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE DATE_ADD(`m`.`Time`, INTERVAL CAST(3.0 AS signed) minute) = TIME '10:18:50.5' +"""); + } + + public override async Task Where_TimeOnly_Add_TimeSpan(bool async) + { + await base.Where_TimeOnly_Add_TimeSpan(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE (`m`.`Time` + TIME '03:00:00') = TIME '13:15:50.5' +"""); + } + + public override async Task Where_TimeOnly_IsBetween(bool async) + { + await base.Where_TimeOnly_IsBetween(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE (`m`.`Time` >= TIME '10:00:00') & (`m`.`Time` < TIME '11:00:00') +"""); + } + + public override async Task Where_TimeOnly_subtract_TimeOnly(bool async) + { + await base.Where_TimeOnly_subtract_TimeOnly(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE (`m`.`Time` - TIME '10:00:00') = TIME '00:15:50.5' +"""); + } + + public override async Task Project_navigation_defined_on_base_from_entity_with_inheritance_using_soft_cast(bool async) + { + await base.Project_navigation_defined_on_base_from_entity_with_inheritance_using_soft_cast(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`GearNickName`, `t0`.`GearSquadId`, `t0`.`IssueDate`, `t0`.`Note`, `t0`.`Id` IS NULL AS `IsNull`, `c`.`Name`, `c`.`Location`, `c`.`Nation`, `c`.`Name` IS NULL AS `IsNull`, `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name`, `s`.`Id` IS NULL AS `IsNull` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +LEFT JOIN `Cities` AS `c` ON `t`.`CityOfBirthName` = `c`.`Name` +LEFT JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` +"""); + } + + public override async Task Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(bool async) + { + await base.Project_navigation_defined_on_derived_from_entity_with_inheritance_using_soft_cast(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `t0`.`Nickname` IS NULL OR (`t0`.`SquadId` IS NULL) AS `IsNull`, `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated`, `l`.`Id` IS NULL AS `IsNull`, `l0`.`Id`, `l0`.`IsOperational`, `l0`.`Name`, `l0`.`Id` IS NULL AS `IsNull` +FROM ( + SELECT `l1`.`Name`, `l1`.`LocustHordeId`, `l1`.`ThreatLevel`, `l1`.`ThreatLevelByte`, `l1`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l1` + UNION ALL + SELECT `l2`.`Name`, `l2`.`LocustHordeId`, `l2`.`ThreatLevel`, `l2`.`ThreatLevelByte`, `l2`.`ThreatLevelNullableByte`, `l2`.`DefeatedByNickname`, `l2`.`DefeatedBySquadId`, `l2`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l2` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +LEFT JOIN `LocustHordes` AS `l` ON `t`.`Name` = `l`.`CommanderName` +LEFT JOIN `LocustHighCommands` AS `l0` ON `t`.`HighCommandId` = `l0`.`Id` +"""); + } + + public override async Task Join_entity_with_itself_grouped_by_key_followed_by_include_skip_take(bool async) + { + await base.Join_entity_with_itself_grouped_by_key_followed_by_include_skip_take(async); + + AssertSql( +""" +@__p_1='10' +@__p_0='0' + +SELECT `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`AssignedCityName`, `t2`.`CityOfBirthName`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`LeaderNickname`, `t2`.`LeaderSquadId`, `t2`.`Rank`, `t2`.`Discriminator`, `t2`.`HasSoulPatch0`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`HasSoulPatch` AS `HasSoulPatch0` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + INNER JOIN ( + SELECT MIN(CHAR_LENGTH(`t1`.`Nickname`)) AS `c`, `t1`.`HasSoulPatch` + FROM ( + SELECT `g0`.`Nickname`, `g0`.`HasSoulPatch` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`HasSoulPatch` + FROM `Officers` AS `o0` + ) AS `t1` + WHERE `t1`.`Nickname` <> 'Dom' + GROUP BY `t1`.`HasSoulPatch` + ) AS `t0` ON CHAR_LENGTH(`t`.`Nickname`) = `t0`.`c` + ORDER BY `t`.`Nickname` + LIMIT @__p_1 OFFSET @__p_0 +) AS `t2` +LEFT JOIN `Weapons` AS `w` ON `t2`.`FullName` = `w`.`OwnerFullName` +ORDER BY `t2`.`Nickname`, `t2`.`SquadId`, `t2`.`HasSoulPatch0` +"""); + } + + public override async Task Where_bool_column_and_Contains(bool async) + { + await base.Where_bool_column_and_Contains(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND `t`.`HasSoulPatch` IN (FALSE, TRUE) +"""); + } + + public override async Task Where_bool_column_or_Contains(bool async) + { + await base.Where_bool_column_or_Contains(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE (`t`.`HasSoulPatch` = TRUE) AND `t`.`HasSoulPatch` IN (FALSE, TRUE) +"""); + } + + public override async Task Parameter_used_multiple_times_take_appropriate_inferred_type_mapping(bool async) + { + await base.Parameter_used_multiple_times_take_appropriate_inferred_type_mapping(async); + + AssertSql( +""" +@__place_0='Seattle' (Size = 4000) + +SELECT `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `Cities` AS `c` +WHERE (`c`.`Nation` = @__place_0) OR (`c`.`Location` = @__place_0) +"""); + } + + public override async Task Enum_matching_take_value_gets_different_type_mapping(bool async) + { + await base.Enum_matching_take_value_gets_different_type_mapping(async); + + AssertSql( +""" +@__value_1='1' +@__p_0='1' + +SELECT `t`.`Rank` & @__value_1 +FROM ( + SELECT `g`.`Nickname`, `g`.`Rank` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`Rank` + FROM `Officers` AS `o` +) AS `t` +ORDER BY `t`.`Nickname` +LIMIT @__p_0 +"""); + } + + public override async Task SelectMany_Where_DefaultIfEmpty_with_navigation_in_the_collection_selector_order_comparison(bool async) + { + await base.SelectMany_Where_DefaultIfEmpty_with_navigation_in_the_collection_selector_order_comparison(async); + + AssertSql( +""" +@__prm_0='1' + +SELECT `t`.`Nickname`, `t`.`FullName`, `t0`.`Id` IS NOT NULL AS `Collection` +FROM ( + SELECT `g`.`Nickname`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + WHERE `w`.`Id` > @__prm_0 +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +"""); + } + + public override async Task Project_entity_and_collection_element(bool async) + { + await base.Project_entity_and_collection_element(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`, `t0`.`Id`, `t0`.`AmmunitionType`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`OwnerFullName`, `t0`.`SynergyWithId` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +INNER JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` +LEFT JOIN `Weapons` AS `w` ON `t`.`FullName` = `w`.`OwnerFullName` +LEFT JOIN ( + SELECT `t1`.`Id`, `t1`.`AmmunitionType`, `t1`.`IsAutomatic`, `t1`.`Name`, `t1`.`OwnerFullName`, `t1`.`SynergyWithId` + FROM ( + SELECT `w0`.`Id`, `w0`.`AmmunitionType`, `w0`.`IsAutomatic`, `w0`.`Name`, `w0`.`OwnerFullName`, `w0`.`SynergyWithId`, ROW_NUMBER() OVER(PARTITION BY `w0`.`OwnerFullName` ORDER BY `w0`.`Id`) AS `row` + FROM `Weapons` AS `w0` + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `s`.`Id` +"""); + } + + public override async Task DateTimeOffset_DateAdd_AddYears(bool async) + { + await base.DateTimeOffset_DateAdd_AddYears(async); + + AssertSql( +""" +SELECT DATE_ADD(`m`.`Timeline`, INTERVAL CAST(1 AS signed) year) +FROM `Missions` AS `m` +"""); + } + + public override async Task Correlated_collection_via_SelectMany_with_Distinct_missing_indentifying_columns_in_projection(bool async) + { + await base.Correlated_collection_via_SelectMany_with_Distinct_missing_indentifying_columns_in_projection(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t1`.`HasSoulPatch` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT DISTINCT `t2`.`HasSoulPatch` + FROM `Weapons` AS `w` + LEFT JOIN ( + SELECT `g0`.`AssignedCityName`, `g0`.`FullName` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`AssignedCityName`, `o0`.`FullName` + FROM `Officers` AS `o0` + ) AS `t0` ON `w`.`OwnerFullName` = `t0`.`FullName` + LEFT JOIN `Cities` AS `c` ON `t0`.`AssignedCityName` = `c`.`Name` + INNER JOIN ( + SELECT `g1`.`CityOfBirthName`, `g1`.`HasSoulPatch` + FROM `Gears` AS `g1` + UNION ALL + SELECT `o1`.`CityOfBirthName`, `o1`.`HasSoulPatch` + FROM `Officers` AS `o1` + ) AS `t2` ON `c`.`Name` = `t2`.`CityOfBirthName` + WHERE `t`.`FullName` = `w`.`OwnerFullName` +) AS `t1` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Basic_query_gears(bool async) + { + await base.Basic_query_gears(async); + + AssertSql( +""" +SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` +FROM `Gears` AS `g` +UNION ALL +SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` +FROM `Officers` AS `o` +"""); + } + + public override async Task Contains_on_readonly_enumerable(bool async) + { + await base.Contains_on_readonly_enumerable(async); + + AssertSql( +""" +SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM `Weapons` AS `w` +WHERE `w`.`AmmunitionType` = 1 +"""); + } + + public override async Task SelectMany_Where_DefaultIfEmpty_with_navigation_in_the_collection_selector_not_equal(bool async) + { + await base.SelectMany_Where_DefaultIfEmpty_with_navigation_in_the_collection_selector_not_equal(async); + + AssertSql( +""" +@__isAutomatic_0='True' + +SELECT `t`.`Nickname`, `t`.`FullName`, `t0`.`Id` IS NOT NULL AS `Collection` +FROM ( + SELECT `g`.`Nickname`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `w`.`Id`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` + WHERE `w`.`IsAutomatic` <> @__isAutomatic_0 +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +"""); + } + + public override async Task Trying_to_access_unmapped_property_in_projection(bool async) + { + await base.Trying_to_access_unmapped_property_in_projection(async); + + AssertSql( +""" +SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` +FROM `Gears` AS `g` +UNION ALL +SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` +FROM `Officers` AS `o` +"""); + } + + public override async Task Cast_to_derived_type_causes_client_eval(bool async) + { + await base.Cast_to_derived_type_causes_client_eval(async); + + AssertSql( +""" +SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` +FROM `Gears` AS `g` +UNION ALL +SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` +FROM `Officers` AS `o` +"""); + } + + public override async Task Comparison_with_value_converted_subclass(bool async) + { + await base.Comparison_with_value_converted_subclass(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +WHERE `l`.`ServerAddress` = CAST('127.0.0.1' AS char) +"""); + } + + public override async Task FirstOrDefault_on_empty_collection_of_DateTime_in_subquery(bool async) + { + await base.FirstOrDefault_on_empty_collection_of_DateTime_in_subquery(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, COALESCE(( + SELECT `t2`.`IssueDate` + FROM `Tags` AS `t2` + WHERE `t2`.`GearNickName` = `t`.`FullName` + ORDER BY `t2`.`Id` + LIMIT 1), TIMESTAMP '0001-01-01 00:00:00') AS `invalidTagIssueDate` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN `Tags` AS `t0` ON (`t`.`Nickname` = `t0`.`GearNickName`) AND (`t`.`SquadId` = `t0`.`GearSquadId`) +WHERE `t0`.`IssueDate` > COALESCE(( + SELECT `t1`.`IssueDate` + FROM `Tags` AS `t1` + WHERE `t1`.`GearNickName` = `t`.`FullName` + ORDER BY `t1`.`Id` + LIMIT 1), TIMESTAMP '0001-01-01 00:00:00') +"""); + } + + public override async Task + Correlated_collection_with_groupby_not_projecting_identifier_column_with_group_aggregate_in_final_projection_multiple_grouping_keys( + bool async) + { + await base + .Correlated_collection_with_groupby_not_projecting_identifier_column_with_group_aggregate_in_final_projection_multiple_grouping_keys( + async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`IsAutomatic`, `t0`.`Name`, `t0`.`Count` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `w`.`IsAutomatic`, `w`.`Name`, COUNT(*) AS `Count` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + GROUP BY `w`.`IsAutomatic`, `w`.`Name` +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`IsAutomatic` +"""); + } + + public override async Task Sum_with_no_data_nullable_double(bool async) + { + await base.Sum_with_no_data_nullable_double(async); + + AssertSql( +""" +SELECT COALESCE(SUM(`m`.`Rating`), 0.0) +FROM `Missions` AS `m` +WHERE `m`.`CodeName` = 'Operation Foobar' +"""); + } + + public override async Task ToString_guid_property_projection(bool async) + { + await base.ToString_guid_property_projection(async); + + AssertSql( +""" +SELECT `t`.`GearNickName` AS `A`, CAST(`t`.`Id` AS char) AS `B` +FROM `Tags` AS `t` +"""); + } + + public override async Task Correlated_collection_with_distinct_not_projecting_identifier_column(bool async) + { + await base.Correlated_collection_with_distinct_not_projecting_identifier_column(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Name`, `t0`.`IsAutomatic` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT DISTINCT `w`.`Name`, `w`.`IsAutomatic` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Name` +"""); + } + + public override async Task Include_after_Select_throws(bool async) + { + await base.Include_after_Select_throws(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated`, `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `LocustHordes` AS `l` +LEFT JOIN `Cities` AS `c` ON `l`.`CapitalName` = `c`.`Name` +"""); + } + + public override async Task Cast_to_derived_followed_by_multiple_includes(bool async) + { + await base.Cast_to_derived_followed_by_multiple_includes(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator`, `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +LEFT JOIN `Weapons` AS `w` ON `t0`.`FullName` = `w`.`OwnerFullName` +WHERE `t`.`Name` LIKE '%Queen%' +ORDER BY `t`.`Name`, `t0`.`Nickname`, `t0`.`SquadId` +"""); + } + + public override async Task Correlated_collection_with_distinct_projecting_identifier_column(bool async) + { + await base.Correlated_collection_with_distinct_projecting_identifier_column(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`Name` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT DISTINCT `w`.`Id`, `w`.`Name` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Where_equals_method_on_nullable_with_object_overload(bool async) + { + await base.Where_equals_method_on_nullable_with_object_overload(async); + + AssertSql( +""" +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE `m`.`Rating` IS NULL +"""); + } + + public override async Task + Correlated_collection_with_groupby_not_projecting_identifier_column_but_only_grouping_key_in_final_projection(bool async) + { + await base.Correlated_collection_with_groupby_not_projecting_identifier_column_but_only_grouping_key_in_final_projection(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Key` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `w`.`IsAutomatic` AS `Key` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + GROUP BY `w`.`IsAutomatic` +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Project_derivied_entity_with_convert_to_parent(bool async) + { + await base.Project_derivied_entity_with_convert_to_parent(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated` +FROM `LocustHordes` AS `l` +"""); + } + + public override async Task Include_after_SelectMany_throws(bool async) + { + await base.Include_after_SelectMany_throws(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `LocustHordes` AS `l` +LEFT JOIN `Cities` AS `c` ON `l`.`CapitalName` = `c`.`Name` +INNER JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` ON `c`.`Name` = `t`.`CityOfBirthName` +INNER JOIN `Squads` AS `s` ON `t`.`SquadId` = `s`.`Id` +"""); + } + + public override async Task Correlated_collection_with_distinct_projecting_identifier_column_composite_key(bool async) + { + await base.Correlated_collection_with_distinct_projecting_identifier_column_composite_key(async); + + AssertSql( +""" +SELECT `s`.`Id`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`HasSoulPatch` +FROM `Squads` AS `s` +LEFT JOIN ( + SELECT DISTINCT `t`.`Nickname`, `t`.`SquadId`, `t`.`HasSoulPatch` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` + ) AS `t` +) AS `t0` ON `s`.`Id` = `t0`.`SquadId` +ORDER BY `s`.`Id`, `t0`.`Nickname` +"""); + } + + public override async Task Include_on_entity_that_is_not_present_in_final_projection_but_uses_TypeIs_instead(bool async) + { + await base.Include_on_entity_that_is_not_present_in_final_projection_but_uses_TypeIs_instead(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`Discriminator` = 'Officer' AS `IsOfficer` +FROM ( + SELECT `g`.`Nickname`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task GroupBy_Select_sum(bool async) + { + await base.GroupBy_Select_sum(async); + + AssertSql( +""" +SELECT COALESCE(SUM(`m`.`Rating`), 0.0) +FROM `Missions` AS `m` +GROUP BY `m`.`CodeName` +"""); + } + + public override async Task ToString_boolean_property_nullable(bool async) + { + await base.ToString_boolean_property_nullable(async); + + AssertSql( +""" +SELECT CASE + WHEN `l`.`Eradicated` = FALSE THEN 'False' + WHEN `l`.`Eradicated` = TRUE THEN 'True' + ELSE NULL +END +FROM `LocustHordes` AS `l` +"""); + } + + public override async Task Correlated_collection_after_distinct_3_levels(bool async) + { + await base.Correlated_collection_after_distinct_3_levels(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t2`.`Nickname`, `t2`.`FullName`, `t2`.`HasSoulPatch`, `t2`.`Id`, `t2`.`Name`, `t2`.`Nickname0`, `t2`.`FullName0`, `t2`.`HasSoulPatch0`, `t2`.`Id0` +FROM ( + SELECT DISTINCT `s`.`Id`, `s`.`Name` + FROM `Squads` AS `s` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `t0`.`Nickname`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t1`.`Id`, `t1`.`Name`, `t1`.`Nickname` AS `Nickname0`, `t1`.`FullName` AS `FullName0`, `t1`.`HasSoulPatch` AS `HasSoulPatch0`, `t1`.`Id0` + FROM ( + SELECT DISTINCT `t3`.`Nickname`, `t3`.`FullName`, `t3`.`HasSoulPatch` + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName`, `g`.`HasSoulPatch` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName`, `o`.`HasSoulPatch` + FROM `Officers` AS `o` + ) AS `t3` + WHERE `t3`.`SquadId` = `t`.`Id` + ) AS `t0` + LEFT JOIN LATERAL ( + SELECT `t`.`Id`, `t`.`Name`, `t0`.`Nickname`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `w`.`Id` AS `Id0` + FROM `Weapons` AS `w` + WHERE `w`.`OwnerFullName` = `t0`.`FullName` + ) AS `t1` ON TRUE +) AS `t2` ON TRUE +ORDER BY `t`.`Id`, `t2`.`Nickname`, `t2`.`FullName`, `t2`.`HasSoulPatch` +"""); + } + + public override async Task ToString_boolean_property_non_nullable(bool async) + { + await base.ToString_boolean_property_non_nullable(async); + + AssertSql( +""" +SELECT CASE + WHEN `w`.`IsAutomatic` = FALSE THEN 'False' + ELSE 'True' +END +FROM `Weapons` AS `w` +"""); + } + + public override async Task Include_on_derived_entity_with_cast(bool async) + { + await base.Include_on_derived_entity_with_cast(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`CapitalName`, `l`.`Name`, `l`.`ServerAddress`, `l`.`CommanderName`, `l`.`Eradicated`, `c`.`Name`, `c`.`Location`, `c`.`Nation` +FROM `LocustHordes` AS `l` +LEFT JOIN `Cities` AS `c` ON `l`.`CapitalName` = `c`.`Name` +ORDER BY `l`.`Id` +"""); + } + + public override async Task String_concat_nullable_expressions_are_coalesced(bool async) + { + await base.String_concat_nullable_expressions_are_coalesced(async); + + AssertSql( +""" +SELECT CONCAT(CONCAT(CONCAT(`t`.`FullName`, ''), COALESCE(`t`.`LeaderNickname`, '')), '') +FROM ( + SELECT `g`.`FullName`, `g`.`LeaderNickname` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`FullName`, `o`.`LeaderNickname` + FROM `Officers` AS `o` +) AS `t` +"""); + } + + public override async Task Correlated_collection_with_distinct_projecting_identifier_column_and_correlation_key(bool async) + { + await base.Correlated_collection_with_distinct_projecting_identifier_column_and_correlation_key(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Id`, `t0`.`Name`, `t0`.`OwnerFullName` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT DISTINCT `w`.`Id`, `w`.`Name`, `w`.`OwnerFullName` + FROM `Weapons` AS `w` +) AS `t0` ON `t`.`FullName` = `t0`.`OwnerFullName` +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Correlated_collection_with_groupby_not_projecting_identifier_column_with_group_aggregate_in_final_projection( + bool async) + { + await base.Correlated_collection_with_groupby_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t0`.`Key`, `t0`.`Count` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`FullName` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`FullName` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN LATERAL ( + SELECT `w`.`IsAutomatic` AS `Key`, COUNT(*) AS `Count` + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` + GROUP BY `w`.`IsAutomatic` +) AS `t0` ON TRUE +ORDER BY `t`.`Nickname`, `t`.`SquadId` +"""); + } + + public override async Task Project_discriminator_columns(bool async) + { + await base.Project_discriminator_columns(async); + + AssertSql(); + } + + [ConditionalTheory(Skip = "Another LATERAL JOIN bug in MySQL. Grouping leads to unexpected result set.")] + public override async Task + Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection( + bool async) + { + await base + .Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection( + async); + + AssertSql(""); + } + + public override async Task Correlated_collection_with_distinct_not_projecting_identifier_column_also_projecting_complex_expressions( + bool async) + { + await base.Correlated_collection_with_distinct_not_projecting_identifier_column_also_projecting_complex_expressions(async); + + AssertSql(); + } + + public override async Task Client_eval_followed_by_aggregate_operation(bool async) + { + await base.Client_eval_followed_by_aggregate_operation(async); + + AssertSql(); + } + + // TODO: Implement strategy as discussed with @roji (including emails) for EF Core 5. + [ConditionalTheory(Skip = "#996")] + public override async Task Client_member_and_unsupported_string_Equals_in_the_same_query(bool async) + { + await base.Client_member_and_unsupported_string_Equals_in_the_same_query(async); + + AssertSql(); + } + + public override async Task Client_side_equality_with_parameter_works_with_optional_navigations(bool async) + { + await base.Client_side_equality_with_parameter_works_with_optional_navigations(async); + + AssertSql(); + } + + public override async Task Correlated_collection_order_by_constant_null_of_non_mapped_type(bool async) + { + await base.Correlated_collection_order_by_constant_null_of_non_mapped_type(async); + + AssertSql(); + } + + public override async Task GetValueOrDefault_on_DateTimeOffset(bool async) + { + await base.GetValueOrDefault_on_DateTimeOffset(async); + + AssertSql(); + } + + public override async Task Where_coalesce_with_anonymous_types(bool async) + { + await base.Where_coalesce_with_anonymous_types(async); + + AssertSql(); + } + + public override async Task Projecting_correlated_collection_followed_by_Distinct(bool async) + { + await base.Projecting_correlated_collection_followed_by_Distinct(async); + + AssertSql(); + } + + public override async Task Projecting_some_properties_as_well_as_correlated_collection_followed_by_Distinct(bool async) + { + await base.Projecting_some_properties_as_well_as_correlated_collection_followed_by_Distinct(async); + + AssertSql(); + } + + public override async Task Projecting_entity_as_well_as_correlated_collection_followed_by_Distinct(bool async) + { + await base.Projecting_entity_as_well_as_correlated_collection_followed_by_Distinct(async); + + AssertSql(); + } + + public override async Task Projecting_entity_as_well_as_complex_correlated_collection_followed_by_Distinct(bool async) + { + await base.Projecting_entity_as_well_as_complex_correlated_collection_followed_by_Distinct(async); + + AssertSql(); + } + + public override async Task Projecting_entity_as_well_as_correlated_collection_of_scalars_followed_by_Distinct(bool async) + { + await base.Projecting_entity_as_well_as_correlated_collection_of_scalars_followed_by_Distinct(async); + + AssertSql(); + } + + public override async Task Correlated_collection_with_distinct_3_levels(bool async) + { + await base.Correlated_collection_with_distinct_3_levels(async); + + AssertSql(); + } + + public override async Task Correlated_collection_after_distinct_3_levels_without_original_identifiers(bool async) + { + await base.Correlated_collection_after_distinct_3_levels_without_original_identifiers(async); + + AssertSql(); + } + + public override async Task Checked_context_throws_on_client_evaluation(bool async) + { + await base.Checked_context_throws_on_client_evaluation(async); + + AssertSql(); + } + + public override async Task Trying_to_access_unmapped_property_throws_informative_error(bool async) + { + await base.Trying_to_access_unmapped_property_throws_informative_error(async); + + AssertSql(); + } + + public override async Task Trying_to_access_unmapped_property_inside_aggregate(bool async) + { + await base.Trying_to_access_unmapped_property_inside_aggregate(async); + + AssertSql(); + } + + public override async Task Trying_to_access_unmapped_property_inside_subquery(bool async) + { + await base.Trying_to_access_unmapped_property_inside_subquery(async); + + AssertSql(); + } + + public override async Task Trying_to_access_unmapped_property_inside_join_key_selector(bool async) + { + await base.Trying_to_access_unmapped_property_inside_join_key_selector(async); + + AssertSql(); + } + + public override async Task Client_projection_with_nested_unmapped_property_bubbles_up_translation_failure_info(bool async) + { + await base.Client_projection_with_nested_unmapped_property_bubbles_up_translation_failure_info(async); + + AssertSql(); + } + + public override async Task Include_after_select_with_cast_throws(bool async) + { + await base.Include_after_select_with_cast_throws(async); + + AssertSql(); + } + + public override async Task Include_after_select_with_entity_projection_throws(bool async) + { + await base.Include_after_select_with_entity_projection_throws(async); + + AssertSql(); + } + + public override async Task Include_after_select_anonymous_projection_throws(bool async) + { + await base.Include_after_select_anonymous_projection_throws(async); + + AssertSql(); + } + + public override async Task Group_by_with_aggregate_max_on_entity_type(bool async) + { + await base.Group_by_with_aggregate_max_on_entity_type(async); + + AssertSql(); + } + + public override async Task Include_collection_and_invalid_navigation_using_string_throws(bool async) + { + await base.Include_collection_and_invalid_navigation_using_string_throws(async); + + AssertSql(); + } + + public override async Task Include_with_concat(bool async) + { + await base.Include_with_concat(async); + + AssertSql(); + } + + public override async Task Join_with_complex_key_selector(bool async) + { + await base.Join_with_complex_key_selector(async); + + AssertSql( +""" +SELECT `s`.`Id`, `t0`.`Id` AS `TagId` +FROM `Squads` AS `s` +CROSS JOIN ( + SELECT `t`.`Id` + FROM `Tags` AS `t` + WHERE `t`.`Note` = 'Marcus'' Tag' +) AS `t0` +"""); + } + + public override async Task Streaming_correlated_collection_issue_11403_returning_ordered_enumerable_throws(bool async) + { + await base.Streaming_correlated_collection_issue_11403_returning_ordered_enumerable_throws(async); + + AssertSql(); + } + + public override async Task Select_correlated_filtered_collection_returning_queryable_throws(bool async) + { + await base.Select_correlated_filtered_collection_returning_queryable_throws(async); + + AssertSql(); + } + + public override async Task Client_method_on_collection_navigation_in_predicate(bool async) + { + await base.Client_method_on_collection_navigation_in_predicate(async); + + AssertSql(); + } + + public override async Task Client_method_on_collection_navigation_in_predicate_accessed_by_ef_property(bool async) + { + await base.Client_method_on_collection_navigation_in_predicate_accessed_by_ef_property(async); + + AssertSql(); + } + + public override async Task Client_method_on_collection_navigation_in_order_by(bool async) + { + await base.Client_method_on_collection_navigation_in_order_by(async); + + AssertSql(); + } + + public override async Task Client_method_on_collection_navigation_in_additional_from_clause(bool async) + { + await base.Client_method_on_collection_navigation_in_additional_from_clause(async); + + AssertSql(); + } + + public override async Task Include_multiple_one_to_one_and_one_to_many_self_reference(bool async) + { + await base.Include_multiple_one_to_one_and_one_to_many_self_reference(async); + + AssertSql(); + } + + public override async Task Include_multiple_one_to_one_and_one_to_one_and_one_to_many(bool async) + { + await base.Include_multiple_one_to_one_and_one_to_one_and_one_to_many(async); + + AssertSql(); + } + + public override async Task Include_multiple_include_then_include(bool async) + { + await base.Include_multiple_include_then_include(async); + + AssertSql(); + } + + public override async Task Select_Where_Navigation_Client(bool async) + { + await base.Select_Where_Navigation_Client(async); + + AssertSql(); + } + + public override async Task Where_subquery_equality_to_null_with_composite_key(bool async) + { + await base.Where_subquery_equality_to_null_with_composite_key(async); + + AssertSql( +""" +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` +WHERE NOT (EXISTS ( + SELECT 1 + FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE `s`.`Id` = `t`.`SquadId`)) +"""); + } + + public override async Task Where_subquery_equality_to_null_without_composite_key(bool async) + { + await base.Where_subquery_equality_to_null_without_composite_key(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +WHERE NOT (EXISTS ( + SELECT 1 + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName`)) +"""); + } + + public override async Task Include_reference_on_derived_type_using_EF_Property(bool async) + { + await base.Include_reference_on_derived_type_using_EF_Property(async); + + AssertSql( +""" +SELECT `t`.`Name`, `t`.`LocustHordeId`, `t`.`ThreatLevel`, `t`.`ThreatLevelByte`, `t`.`ThreatLevelNullableByte`, `t`.`DefeatedByNickname`, `t`.`DefeatedBySquadId`, `t`.`HighCommandId`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `l`.`Name`, `l`.`LocustHordeId`, `l`.`ThreatLevel`, `l`.`ThreatLevelByte`, `l`.`ThreatLevelNullableByte`, NULL AS `DefeatedByNickname`, NULL AS `DefeatedBySquadId`, NULL AS `HighCommandId`, 'LocustLeader' AS `Discriminator` + FROM `LocustLeaders` AS `l` + UNION ALL + SELECT `l0`.`Name`, `l0`.`LocustHordeId`, `l0`.`ThreatLevel`, `l0`.`ThreatLevelByte`, `l0`.`ThreatLevelNullableByte`, `l0`.`DefeatedByNickname`, `l0`.`DefeatedBySquadId`, `l0`.`HighCommandId`, 'LocustCommander' AS `Discriminator` + FROM `LocustCommanders` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t0` ON (`t`.`DefeatedByNickname` = `t0`.`Nickname`) AND (`t`.`DefeatedBySquadId` = `t0`.`SquadId`) +"""); + } + + public override async Task Include_collection_on_derived_type_using_EF_Property(bool async) + { + await base.Include_collection_on_derived_type_using_EF_Property(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g0`.`Nickname`, `g0`.`SquadId`, `g0`.`AssignedCityName`, `g0`.`CityOfBirthName`, `g0`.`FullName`, `g0`.`HasSoulPatch`, `g0`.`LeaderNickname`, `g0`.`LeaderSquadId`, `g0`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g0` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + public override async Task EF_Property_based_Include_navigation_on_derived_type(bool async) + { + await base.EF_Property_based_Include_navigation_on_derived_type(async); + + AssertSql( +""" +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator`, `t0`.`Nickname`, `t0`.`SquadId`, `t0`.`AssignedCityName`, `t0`.`CityOfBirthName`, `t0`.`FullName`, `t0`.`HasSoulPatch`, `t0`.`LeaderNickname`, `t0`.`LeaderSquadId`, `t0`.`Rank`, `t0`.`Discriminator` +FROM ( + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` +LEFT JOIN ( + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` + UNION ALL + SELECT `o0`.`Nickname`, `o0`.`SquadId`, `o0`.`AssignedCityName`, `o0`.`CityOfBirthName`, `o0`.`FullName`, `o0`.`HasSoulPatch`, `o0`.`LeaderNickname`, `o0`.`LeaderSquadId`, `o0`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o0` +) AS `t0` ON (`t`.`Nickname` = `t0`.`LeaderNickname`) AND (`t`.`SquadId` = `t0`.`LeaderSquadId`) +ORDER BY `t`.`Nickname`, `t`.`SquadId`, `t0`.`Nickname` +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCInheritanceQueryMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCInheritanceQueryMySqlFixture.cs new file mode 100644 index 000000000..fa01f0dc2 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCInheritanceQueryMySqlFixture.cs @@ -0,0 +1,34 @@ +using System.Linq; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCInheritanceQueryMySqlFixture : TPCInheritanceQueryFixture +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + // TODO: Add sequence support for server implementations that have them. + protected override bool UseGeneratedKeys + => false; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + // We currently do not support an official way to set a seed and auto_increment value for auto_increment columns, which is needed + // for TPC if the database implementation does not support sequences (which MariaDB does, but we have not fully implemented yet). + // We therefore just remove the auto_increment flag from the appropriate entities here, so we do not trigger the related TPC + // warning by EF Core. + foreach (var tpcPrimaryKey in modelBuilder.Model.GetEntityTypes() + .Where(e => e.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) + .Select(e => e.FindPrimaryKey())) + { + tpcPrimaryKey.Properties.Single().ValueGenerated = ValueGenerated.Never; + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCInheritanceQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCInheritanceQueryMySqlTest.cs new file mode 100644 index 000000000..2e0c26abd --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCInheritanceQueryMySqlTest.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Storage; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCInheritanceQueryMySqlTest : TPCInheritanceQueryTestBase +{ + public TPCInheritanceQueryMySqlTest(TPCInheritanceQueryMySqlFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) + => facade.UseTransaction(transaction.GetDbTransaction()); +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyNoTrackingQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyNoTrackingQueryMySqlTest.cs new file mode 100644 index 000000000..9df263287 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyNoTrackingQueryMySqlTest.cs @@ -0,0 +1,2807 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCManyToManyNoTrackingQueryMySqlTest : TPCManyToManyNoTrackingQueryRelationalTestBase +{ + public TPCManyToManyNoTrackingQueryMySqlTest(TPCManyToManyQueryMySqlFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + protected override bool CanExecuteQueryString + => true; + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Skip_navigation_all(bool async) + { + await base.Skip_navigation_all(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE NOT EXISTS ( + SELECT 1 + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE (`e`.`Id` = `j`.`OneId`) AND NOT (`e0`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_any_without_predicate(bool async) + { + await base.Skip_navigation_any_without_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE EXISTS ( + SELECT 1 + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + WHERE (`e`.`Id` = `j`.`OneId`) AND (`e0`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_any_with_predicate(bool async) + { + await base.Skip_navigation_any_with_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE EXISTS ( + SELECT 1 + FROM `EntityOneEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + WHERE (`e`.`Id` = `e0`.`OneSkipSharedId`) AND (`e1`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_contains(bool async) + { + await base.Skip_navigation_contains(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE EXISTS ( + SELECT 1 + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + WHERE (`e`.`Id` = `j`.`OneId`) AND (`e0`.`Id` = 1)) +"""); + } + + public override async Task Skip_navigation_count_without_predicate(bool async) + { + await base.Skip_navigation_count_without_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE ( + SELECT COUNT(*) + FROM `JoinOneSelfPayload` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`LeftId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`RightId`) > 0 +"""); + } + + public override async Task Skip_navigation_count_with_predicate(bool async) + { + await base.Skip_navigation_count_with_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +ORDER BY ( + SELECT COUNT(*) + FROM `JoinOneToBranch` AS `j` + INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + ) AS `t` ON `j`.`EntityBranchId` = `t`.`Id` + WHERE (`e`.`Id` = `j`.`EntityOneId`) AND (`t`.`Name` IS NOT NULL AND (`t`.`Name` LIKE 'L%'))), `e`.`Id` +"""); + } + + public override async Task Skip_navigation_long_count_without_predicate(bool async) + { + await base.Skip_navigation_long_count_without_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +WHERE ( + SELECT COUNT(*) + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`TwoId`) > 0 +"""); + } + + public override async Task Skip_navigation_long_count_with_predicate(bool async) + { + await base.Skip_navigation_long_count_with_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +ORDER BY ( + SELECT COUNT(*) + FROM `EntityTwoEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`SelfSkipSharedLeftId` = `e1`.`Id` + WHERE (`e`.`Id` = `e0`.`SelfSkipSharedRightId`) AND (`e1`.`Name` IS NOT NULL AND (`e1`.`Name` LIKE 'L%'))) DESC, `e`.`Id` +"""); + } + + public override async Task Skip_navigation_select_many_average(bool async) + { + await base.Skip_navigation_select_many_average(async); + + AssertSql( +$""" +SELECT AVG({MySqlTestHelpers.CastAsDouble(@"`t`.`Key1`")}) +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `e1`.`Key1`, `e0`.`TwoSkipSharedId` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityCompositeKeys` AS `e1` ON ((`e0`.`CompositeKeySkipSharedKey1` = `e1`.`Key1`) AND (`e0`.`CompositeKeySkipSharedKey2` = `e1`.`Key2`)) AND (`e0`.`CompositeKeySkipSharedKey3` = `e1`.`Key3`) +) AS `t` ON `e`.`Id` = `t`.`TwoSkipSharedId` +"""); + } + + public override async Task Skip_navigation_select_many_max(bool async) + { + await base.Skip_navigation_select_many_max(async); + + AssertSql( +""" +SELECT MAX(`t`.`Key1`) +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Key1`, `j`.`ThreeId` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`j`.`CompositeId1` = `e0`.`Key1`) AND (`j`.`CompositeId2` = `e0`.`Key2`)) AND (`j`.`CompositeId3` = `e0`.`Key3`) +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +"""); + } + + public override async Task Skip_navigation_select_many_min(bool async) + { + await base.Skip_navigation_select_many_min(async); + + AssertSql( +""" +SELECT MIN(`t0`.`Id`) +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `e0`.`ThreeSkipSharedId` + FROM `EntityRootEntityThree` AS `e0` + INNER JOIN ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` +) AS `t0` ON `e`.`Id` = `t0`.`ThreeSkipSharedId` +"""); + } + + public override async Task Skip_navigation_select_many_sum(bool async) + { + await base.Skip_navigation_select_many_sum(async); + + AssertSql( +""" +SELECT COALESCE(SUM(`t0`.`Key1`), 0) +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e0`.`Key1`, `e`.`RootSkipSharedId` + FROM `EntityCompositeKeyEntityRoot` AS `e` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`e`.`CompositeKeySkipSharedKey1` = `e0`.`Key1`) AND (`e`.`CompositeKeySkipSharedKey2` = `e0`.`Key2`)) AND (`e`.`CompositeKeySkipSharedKey3` = `e0`.`Key3`) +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +"""); + } + + public override async Task Skip_navigation_select_subquery_average(bool async) + { + await base.Skip_navigation_select_subquery_average(async); + + AssertSql( +$""" +SELECT ( + SELECT AVG({MySqlTestHelpers.CastAsDouble(@"`e`.`Key1`")}) + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e` ON ((`j`.`CompositeId1` = `e`.`Key1`) AND (`j`.`CompositeId2` = `e`.`Key2`)) AND (`j`.`CompositeId3` = `e`.`Key3`) + WHERE `l`.`Id` = `j`.`LeafId`) +FROM `Leaves` AS `l` +"""); + } + + public override async Task Skip_navigation_select_subquery_max(bool async) + { + await base.Skip_navigation_select_subquery_max(async); + + AssertSql( +""" +SELECT ( + SELECT MAX(`e0`.`Id`) + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`TwoId`) +FROM `EntityTwos` AS `e` +"""); + } + + public override async Task Skip_navigation_select_subquery_min(bool async) + { + await base.Skip_navigation_select_subquery_min(async); + + AssertSql( +""" +SELECT ( + SELECT MIN(`e0`.`Id`) + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`ThreeId`) +FROM `EntityThrees` AS `e` +"""); + } + + public override async Task Skip_navigation_select_subquery_sum(bool async) + { + await base.Skip_navigation_select_subquery_sum(async); + + AssertSql( +""" +SELECT ( + SELECT COALESCE(SUM(`e1`.`Id`), 0) + FROM `EntityOneEntityTwo` AS `e0` + INNER JOIN `EntityOnes` AS `e1` ON `e0`.`OneSkipSharedId` = `e1`.`Id` + WHERE `e`.`Id` = `e0`.`TwoSkipSharedId`) +FROM `EntityTwos` AS `e` +"""); + } + + public override async Task Skip_navigation_order_by_first_or_default(bool async) + { + await base.Skip_navigation_order_by_first_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`ThreeId` + FROM ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`ThreeId`, ROW_NUMBER() OVER(PARTITION BY `j`.`ThreeId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +"""); + } + + public override async Task Skip_navigation_order_by_single_or_default(bool async) + { + await base.Skip_navigation_order_by_single_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name` +FROM `EntityOnes` AS `e` +LEFT JOIN LATERAL ( + SELECT `t`.`Id`, `t`.`Name` + FROM ( + SELECT `e0`.`Id`, `e0`.`Name` + FROM `JoinOneSelfPayload` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`RightId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`LeftId` + ORDER BY `e0`.`Id` + LIMIT 1 + ) AS `t` + ORDER BY `t`.`Id` + LIMIT 1 +) AS `t0` ON TRUE +"""); + } + + public override async Task Skip_navigation_order_by_last_or_default(bool async) + { + await base.Skip_navigation_order_by_last_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name` +FROM ( + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Id`, `t1`.`Name`, `t1`.`EntityBranchId` + FROM ( + SELECT `e`.`Id`, `e`.`Name`, `j`.`EntityBranchId`, ROW_NUMBER() OVER(PARTITION BY `j`.`EntityBranchId` ORDER BY `e`.`Id` DESC) AS `row` + FROM `JoinOneToBranch` AS `j` + INNER JOIN `EntityOnes` AS `e` ON `j`.`EntityOneId` = `e`.`Id` + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`Id` = `t0`.`EntityBranchId` +"""); + } + + public override async Task Skip_navigation_order_by_reverse_first_or_default(bool async) + { + await base.Skip_navigation_order_by_reverse_first_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`ThreeId`, ROW_NUMBER() OVER(PARTITION BY `j`.`ThreeId` ORDER BY `e0`.`Id` DESC) AS `row` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +"""); + } + + public override async Task Skip_navigation_cast(bool async) + { + await base.Skip_navigation_cast(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `Leaves` AS `l` ON `j`.`LeafId` = `l`.`Id` +) AS `t` ON ((`e`.`Key1` = `t`.`CompositeId1`) AND (`e`.`Key2` = `t`.`CompositeId2`)) AND (`e`.`Key3` = `t`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` +"""); + } + + public override async Task Skip_navigation_of_type(bool async) + { + await base.Skip_navigation_of_type(async); + + AssertSql( +$""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `e0`.`RootSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityRoot` AS `e0` + INNER JOIN ( + SELECT `r`.`Id`, `r`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityRoot'")} AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityBranch'")} AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityLeaf2'")} AS `Discriminator` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` + WHERE `t`.`Discriminator` = 'EntityLeaf' +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +"""); + } + + public override async Task Join_with_skip_navigation(bool async) + { + await base.Join_with_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +INNER JOIN `EntityTwos` AS `e0` ON `e`.`Id` = ( + SELECT `e2`.`Id` + FROM `EntityTwoEntityTwo` AS `e1` + INNER JOIN `EntityTwos` AS `e2` ON `e1`.`SelfSkipSharedRightId` = `e2`.`Id` + WHERE `e0`.`Id` = `e1`.`SelfSkipSharedLeftId` + ORDER BY `e2`.`Id` + LIMIT 1) +"""); + } + + public override async Task Left_join_with_skip_navigation(bool async) + { + await base.Left_join_with_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e0`.`Name` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN `EntityCompositeKeys` AS `e0` ON ( + SELECT `e2`.`Id` + FROM `EntityCompositeKeyEntityTwo` AS `e1` + INNER JOIN `EntityTwos` AS `e2` ON `e1`.`TwoSkipSharedId` = `e2`.`Id` + WHERE ((`e`.`Key1` = `e1`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `e1`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `e1`.`CompositeKeySkipSharedKey3`) + ORDER BY `e2`.`Id` + LIMIT 1) = ( + SELECT `e3`.`Id` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e3` ON `j`.`ThreeId` = `e3`.`Id` + WHERE ((`e0`.`Key1` = `j`.`CompositeId1`) AND (`e0`.`Key2` = `j`.`CompositeId2`)) AND (`e0`.`Key3` = `j`.`CompositeId3`) + ORDER BY `e3`.`Id` + LIMIT 1) +ORDER BY `e`.`Key1`, `e0`.`Key1`, `e`.`Key2`, `e0`.`Key2` +"""); + } + + public override async Task Select_many_over_skip_navigation(bool async) + { + await base.Select_many_over_skip_navigation(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `e`.`RootSkipSharedId` + FROM `EntityRootEntityThree` AS `e` + INNER JOIN `EntityThrees` AS `e0` ON `e`.`ThreeSkipSharedId` = `e0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +"""); + } + + public override async Task Select_many_over_skip_navigation_where(bool async) + { + await base.Select_many_over_skip_navigation_where(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, ROW_NUMBER() OVER(PARTITION BY `j`.`OneId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + ) AS `t` + WHERE 2 < `t`.`row` +) AS `t0` ON `e`.`Id` = `t0`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_take(bool async) + { + await base.Select_many_over_skip_navigation_order_by_take(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneSkipSharedId` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`OneSkipSharedId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`OneSkipSharedId` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityOneEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON `e`.`Id` = `t0`.`OneSkipSharedId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip_take(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip_take(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, ROW_NUMBER() OVER(PARTITION BY `j`.`OneId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + ) AS `t` + WHERE (2 < `t`.`row`) AND (`t`.`row` <= 5) +) AS `t0` ON `e`.`Id` = `t0`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_of_type(bool async) + { + await base.Select_many_over_skip_navigation_of_type(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `e0`.`ThreeSkipSharedId` + FROM `EntityRootEntityThree` AS `e0` + INNER JOIN ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` + WHERE `t`.`Discriminator` IN ('EntityBranch', 'EntityLeaf') +) AS `t0` ON `e`.`Id` = `t0`.`ThreeSkipSharedId` +"""); + } + + public override async Task Select_many_over_skip_navigation_cast(bool async) + { + await base.Select_many_over_skip_navigation_cast(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `j`.`EntityOneId` + FROM `JoinOneToBranch` AS `j` + INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + ) AS `t` ON `j`.`EntityBranchId` = `t`.`Id` +) AS `t0` ON `e`.`Id` = `t0`.`EntityOneId` +"""); + } + + public override async Task Select_skip_navigation(bool async) + { + await base.Select_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `t`.`Id`, `t`.`Name`, `t`.`LeftId`, `t`.`RightId` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`LeftId`, `j`.`RightId` + FROM `JoinOneSelfPayload` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`LeftId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`RightId` +ORDER BY `e`.`Id`, `t`.`LeftId`, `t`.`RightId` +"""); + } + + public override async Task Select_skip_navigation_multiple(bool async) + { + await base.Select_skip_navigation_multiple(async); + + AssertSql( +""" +SELECT `e`.`Id`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId`, `t`.`TwoId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`SelfSkipSharedLeftId`, `t0`.`SelfSkipSharedRightId`, `t1`.`Key1`, `t1`.`Key2`, `t1`.`Key3`, `t1`.`Name`, `t1`.`TwoSkipSharedId`, `t1`.`CompositeKeySkipSharedKey1`, `t1`.`CompositeKeySkipSharedKey2`, `t1`.`CompositeKeySkipSharedKey3` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`ThreeId`, `j`.`TwoId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`TwoId` +LEFT JOIN ( + SELECT `e2`.`Id`, `e2`.`CollectionInverseId`, `e2`.`ExtraId`, `e2`.`Name`, `e2`.`ReferenceInverseId`, `e1`.`SelfSkipSharedLeftId`, `e1`.`SelfSkipSharedRightId` + FROM `EntityTwoEntityTwo` AS `e1` + INNER JOIN `EntityTwos` AS `e2` ON `e1`.`SelfSkipSharedLeftId` = `e2`.`Id` +) AS `t0` ON `e`.`Id` = `t0`.`SelfSkipSharedRightId` +LEFT JOIN ( + SELECT `e4`.`Key1`, `e4`.`Key2`, `e4`.`Key3`, `e4`.`Name`, `e3`.`TwoSkipSharedId`, `e3`.`CompositeKeySkipSharedKey1`, `e3`.`CompositeKeySkipSharedKey2`, `e3`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityTwo` AS `e3` + INNER JOIN `EntityCompositeKeys` AS `e4` ON ((`e3`.`CompositeKeySkipSharedKey1` = `e4`.`Key1`) AND (`e3`.`CompositeKeySkipSharedKey2` = `e4`.`Key2`)) AND (`e3`.`CompositeKeySkipSharedKey3` = `e4`.`Key3`) +) AS `t1` ON `e`.`Id` = `t1`.`TwoSkipSharedId` +ORDER BY `e`.`Id`, `t`.`ThreeId`, `t`.`TwoId`, `t`.`Id`, `t0`.`SelfSkipSharedLeftId`, `t0`.`SelfSkipSharedRightId`, `t0`.`Id`, `t1`.`TwoSkipSharedId`, `t1`.`CompositeKeySkipSharedKey1`, `t1`.`CompositeKeySkipSharedKey2`, `t1`.`CompositeKeySkipSharedKey3`, `t1`.`Key1`, `t1`.`Key2` +"""); + } + + public override async Task Select_skip_navigation_first_or_default(bool async) + { + await base.Select_skip_navigation_first_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`Name` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `t`.`Key1`, `t`.`Key2`, `t`.`Key3`, `t`.`Name`, `t`.`ThreeId` + FROM ( + SELECT `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e0`.`Name`, `j`.`ThreeId`, ROW_NUMBER() OVER(PARTITION BY `j`.`ThreeId` ORDER BY `e0`.`Key1`, `e0`.`Key2`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`j`.`CompositeId1` = `e0`.`Key1`) AND (`j`.`CompositeId2` = `e0`.`Key2`)) AND (`j`.`CompositeId3` = `e0`.`Key3`) + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +ORDER BY `e`.`Id` +"""); + } + + public override async Task Include_skip_navigation(bool async) + { + await base.Include_skip_navigation(async); + + AssertSql( +$""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`Slumber`, `t0`.`IsGreen`, `t0`.`IsBrown`, `t0`.`Discriminator`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator`, `e0`.`RootSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityRoot` AS `e0` + INNER JOIN ( + SELECT `r`.`Id`, `r`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Slumber`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsBrown`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityRoot'")} AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Slumber`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsBrown`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityBranch'")} AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Number`, `l0`.`Slumber`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, `l0`.`IsBrown`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityLeaf2'")} AS `Discriminator` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +"""); + } + + public override async Task Include_skip_navigation_then_reference(bool async) + { + await base.Include_skip_navigation_then_reference(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id0`, `t0`.`Name0`, `t0`.`EntityBranchId`, `t0`.`EntityOneId` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `t`.`Id` AS `Id0`, `t`.`Name` AS `Name0`, `t`.`EntityBranchId`, `t`.`EntityOneId` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `Leaves` AS `l` ON `j`.`LeafId` = `l`.`Id` + LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j0`.`EntityBranchId`, `j0`.`EntityOneId` + FROM `JoinOneToBranch` AS `j0` + INNER JOIN `EntityOnes` AS `e0` ON `j0`.`EntityOneId` = `e0`.`Id` + ) AS `t` ON `l`.`Id` = `t`.`EntityBranchId` +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeId1`) AND (`e`.`Key2` = `t0`.`CompositeId2`)) AND (`e`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id`, `t0`.`EntityBranchId`, `t0`.`EntityOneId` +"""); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t0`.`Id`, `t0`.`Name`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id1`, `t0`.`Name1`, `t0`.`LeftId`, `t0`.`RightId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `j`.`OneId`, `j`.`ThreeId`, `t`.`Id` AS `Id1`, `t`.`Name` AS `Name1`, `t`.`LeftId`, `t`.`RightId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + LEFT JOIN ( + SELECT `e2`.`Id`, `e2`.`Name`, `j0`.`LeftId`, `j0`.`RightId` + FROM `JoinOneSelfPayload` AS `j0` + INNER JOIN `EntityOnes` AS `e2` ON `j0`.`RightId` = `e2`.`Id` + ) AS `t` ON `e0`.`Id` = `t`.`LeftId` +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id`, `t0`.`Id0`, `t0`.`LeftId`, `t0`.`RightId` +"""); + } + + public override async Task Include_skip_navigation_and_reference(bool async) + { + await base.Include_skip_navigation_and_reference(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `e0`.`Id`, `t`.`Id`, `t`.`Name`, `t`.`OneSkipSharedId`, `t`.`TwoSkipSharedId`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +LEFT JOIN `EntityThrees` AS `e0` ON `e`.`Id` = `e0`.`ReferenceInverseId` +LEFT JOIN ( + SELECT `e2`.`Id`, `e2`.`Name`, `e1`.`OneSkipSharedId`, `e1`.`TwoSkipSharedId` + FROM `EntityOneEntityTwo` AS `e1` + INNER JOIN `EntityOnes` AS `e2` ON `e1`.`OneSkipSharedId` = `e2`.`Id` +) AS `t` ON `e`.`Id` = `t`.`TwoSkipSharedId` +ORDER BY `e`.`Id`, `e0`.`Id`, `t`.`OneSkipSharedId`, `t`.`TwoSkipSharedId` +"""); + } + + public override async Task Filtered_include_skip_navigation_where(bool async) + { + await base.Filtered_include_skip_navigation_where(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`Id`, `t`.`Name`, `t`.`OneId`, `t`.`ThreeId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by(bool async) + { + await base.Filtered_include_skip_navigation_order_by(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId`, `t`.`TwoId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`ThreeId`, `j`.`TwoId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`Id`, `t`.`ThreeId` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`SelfSkipSharedLeftId`, `t0`.`SelfSkipSharedRightId` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`SelfSkipSharedLeftId`, `t`.`SelfSkipSharedRightId` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`SelfSkipSharedLeftId`, `e0`.`SelfSkipSharedRightId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`SelfSkipSharedLeftId` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityTwoEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`SelfSkipSharedRightId` = `e1`.`Id` + ) AS `t` + WHERE 2 < `t`.`row` +) AS `t0` ON `e`.`Id` = `t0`.`SelfSkipSharedLeftId` +ORDER BY `e`.`Id`, `t0`.`SelfSkipSharedLeftId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_take(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`TwoSkipSharedId`, `t`.`CompositeKeySkipSharedKey1`, `t`.`CompositeKeySkipSharedKey2`, `t`.`CompositeKeySkipSharedKey3` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`TwoSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, ROW_NUMBER() OVER(PARTITION BY `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`Id0` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`Id0`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`Id` AS `Id0`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, ROW_NUMBER() OVER(PARTITION BY `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeId1`) AND (`e`.`Key2` = `t0`.`CompositeId2`)) AND (`e`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_then_include_skip_navigation_where(bool async) + { + await base.Filtered_then_include_skip_navigation_where(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id0`, `t0`.`Name0`, `t0`.`OneId`, `t0`.`ThreeId` +FROM ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `e`.`RootSkipSharedId`, `e`.`ThreeSkipSharedId`, `t1`.`Id` AS `Id0`, `t1`.`Name` AS `Name0`, `t1`.`OneId`, `t1`.`ThreeId` + FROM `EntityRootEntityThree` AS `e` + INNER JOIN `EntityThrees` AS `e0` ON `e`.`ThreeSkipSharedId` = `e0`.`Id` + LEFT JOIN ( + SELECT `e1`.`Id`, `e1`.`Name`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e1` ON `j`.`OneId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 + ) AS `t1` ON `e0`.`Id` = `t1`.`ThreeId` +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id`, `t0`.`OneId`, `t0`.`ThreeId` +"""); + } + + public override async Task Filtered_then_include_skip_navigation_order_by_skip_take(bool async) + { + await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator`, `t1`.`Key1`, `t1`.`Key2`, `t1`.`Key3`, `t1`.`Name`, `t1`.`RootSkipSharedId`, `t1`.`CompositeKeySkipSharedKey1`, `t1`.`CompositeKeySkipSharedKey2`, `t1`.`CompositeKeySkipSharedKey3`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`Name0`, `t1`.`ReferenceInverseId`, `t1`.`Id0` +FROM ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e0`.`Name`, `e`.`RootSkipSharedId`, `e`.`CompositeKeySkipSharedKey1`, `e`.`CompositeKeySkipSharedKey2`, `e`.`CompositeKeySkipSharedKey3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId`, `t0`.`Id0`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3` + FROM `EntityCompositeKeyEntityRoot` AS `e` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`e`.`CompositeKeySkipSharedKey1` = `e0`.`Key1`) AND (`e`.`CompositeKeySkipSharedKey2` = `e0`.`Key2`)) AND (`e`.`CompositeKeySkipSharedKey3` = `e0`.`Key3`) + LEFT JOIN ( + SELECT `t2`.`Id`, `t2`.`CollectionInverseId`, `t2`.`Name`, `t2`.`ReferenceInverseId`, `t2`.`Id0`, `t2`.`CompositeId1`, `t2`.`CompositeId2`, `t2`.`CompositeId3` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j`.`Id` AS `Id0`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, ROW_NUMBER() OVER(PARTITION BY `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e1` ON `j`.`ThreeId` = `e1`.`Id` + ) AS `t2` + WHERE (1 < `t2`.`row`) AND (`t2`.`row` <= 3) + ) AS `t0` ON ((`e0`.`Key1` = `t0`.`CompositeId1`) AND (`e0`.`Key2` = `t0`.`CompositeId2`)) AND (`e0`.`Key3` = `t0`.`CompositeId3`) +) AS `t1` ON `t`.`Id` = `t1`.`RootSkipSharedId` +ORDER BY `t`.`Id`, `t1`.`RootSkipSharedId`, `t1`.`CompositeKeySkipSharedKey1`, `t1`.`CompositeKeySkipSharedKey2`, `t1`.`CompositeKeySkipSharedKey3`, `t1`.`Key1`, `t1`.`Key2`, `t1`.`Key3`, `t1`.`CompositeId1`, `t1`.`CompositeId2`, `t1`.`CompositeId3`, `t1`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`Name`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId`, `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +FROM `Leaves` AS `l` +LEFT JOIN ( + SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId`, `t`.`TwoSkipSharedId`, `t`.`CompositeKeySkipSharedKey1`, `t`.`CompositeKeySkipSharedKey2`, `t`.`CompositeKeySkipSharedKey3` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e` ON ((`j`.`CompositeId1` = `e`.`Key1`) AND (`j`.`CompositeId2` = `e`.`Key2`)) AND (`j`.`CompositeId3` = `e`.`Key3`) + LEFT JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`TwoSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` ON ((`e`.`Key1` = `t`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t`.`CompositeKeySkipSharedKey3`) + WHERE `e`.`Key1` < 5 +) AS `t0` ON `l`.`Id` = `t0`.`LeafId` +ORDER BY `l`.`Id`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`ExtraId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`Id0`, `t1`.`CollectionInverseId0`, `t1`.`Name0`, `t1`.`ReferenceInverseId0`, `t1`.`ThreeId`, `t1`.`TwoId0` +FROM `EntityOnes` AS `e` +LEFT JOIN LATERAL ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId`, `t0`.`Id` AS `Id0`, `t0`.`CollectionInverseId` AS `CollectionInverseId0`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId` AS `ReferenceInverseId0`, `t0`.`ThreeId`, `t0`.`TwoId` AS `TwoId0` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`OneId` + ORDER BY `e0`.`Id` + LIMIT 2 OFFSET 1 + ) AS `t` + LEFT JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j0`.`ThreeId`, `j0`.`TwoId` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 + ) AS `t0` ON `t`.`Id` = `t0`.`TwoId` +) AS `t1` ON TRUE +ORDER BY `e`.`Id`, `t1`.`Id`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`ThreeId`, `t1`.`TwoId0` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`ExtraId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`Id0`, `t1`.`CollectionInverseId0`, `t1`.`Name0`, `t1`.`ReferenceInverseId0`, `t1`.`ThreeId`, `t1`.`TwoId0` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId`, `t0`.`Id` AS `Id0`, `t0`.`CollectionInverseId` AS `CollectionInverseId0`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId` AS `ReferenceInverseId0`, `t0`.`ThreeId`, `t0`.`TwoId` AS `TwoId0` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId`, `t`.`TwoId` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j0`.`ThreeId`, `j0`.`TwoId`, ROW_NUMBER() OVER(PARTITION BY `j0`.`TwoId` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) + ) AS `t0` ON `e0`.`Id` = `t0`.`TwoId` + WHERE `e0`.`Id` < 10 +) AS `t1` ON `e`.`Id` = `t1`.`OneId` +ORDER BY `e`.`Id`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`Id`, `t1`.`TwoId0`, `t1`.`Id0` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined(bool async) + { + await base.Filter_include_on_skip_navigation_combined(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id1`, `t`.`CollectionInverseId0`, `t`.`ExtraId0`, `t`.`Name1`, `t`.`ReferenceInverseId0` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId`, `e2`.`Id` AS `Id1`, `e2`.`CollectionInverseId` AS `CollectionInverseId0`, `e2`.`ExtraId` AS `ExtraId0`, `e2`.`Name` AS `Name1`, `e2`.`ReferenceInverseId` AS `ReferenceInverseId0` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + LEFT JOIN `EntityTwos` AS `e2` ON `e0`.`Id` = `e2`.`CollectionInverseId` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined_with_filtered_then_includes(bool async) + { + await base.Filter_include_on_skip_navigation_combined_with_filtered_then_includes(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t3`.`Id`, `t3`.`Name`, `t3`.`OneId`, `t3`.`ThreeId`, `t3`.`Id0`, `t3`.`CollectionInverseId`, `t3`.`ExtraId`, `t3`.`Name0`, `t3`.`ReferenceInverseId`, `t3`.`OneId0`, `t3`.`TwoId`, `t3`.`Id1`, `t3`.`Name1`, `t3`.`Number`, `t3`.`IsGreen`, `t3`.`Discriminator`, `t3`.`EntityBranchId`, `t3`.`EntityOneId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`OneId`, `j`.`ThreeId`, `t0`.`Id` AS `Id0`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId`, `t0`.`OneId` AS `OneId0`, `t0`.`TwoId`, `t1`.`Id` AS `Id1`, `t1`.`Name` AS `Name1`, `t1`.`Number`, `t1`.`IsGreen`, `t1`.`Discriminator`, `t1`.`EntityBranchId`, `t1`.`EntityOneId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j0`.`OneId`, `j0`.`TwoId`, ROW_NUMBER() OVER(PARTITION BY `j0`.`OneId` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinOneToTwo` AS `j0` + INNER JOIN `EntityTwos` AS `e1` ON `j0`.`TwoId` = `e1`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) + ) AS `t0` ON `e0`.`Id` = `t0`.`OneId` + LEFT JOIN ( + SELECT `t2`.`Id`, `t2`.`Name`, `t2`.`Number`, `t2`.`IsGreen`, `t2`.`Discriminator`, `j1`.`EntityBranchId`, `j1`.`EntityOneId` + FROM `JoinOneToBranch` AS `j1` + INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + ) AS `t2` ON `j1`.`EntityBranchId` = `t2`.`Id` + WHERE `t2`.`Id` < 20 + ) AS `t1` ON `e0`.`Id` = `t1`.`EntityOneId` + WHERE `e0`.`Id` < 10 +) AS `t3` ON `e`.`Id` = `t3`.`ThreeId` +ORDER BY `e`.`Id`, `t3`.`OneId`, `t3`.`ThreeId`, `t3`.`Id`, `t3`.`OneId0`, `t3`.`Id0`, `t3`.`TwoId`, `t3`.`EntityBranchId`, `t3`.`EntityOneId` +"""); + } + + public override async Task Filtered_include_on_skip_navigation_then_filtered_include_on_navigation(bool async) + { + await base.Filtered_include_on_skip_navigation_then_filtered_include_on_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t0`.`Id`, `t0`.`Name`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`OneId`, `j`.`ThreeId`, `t`.`Id` AS `Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `EntityTwos` AS `e1` + WHERE `e1`.`Id` < 5 + ) AS `t` ON `e0`.`Id` = `t`.`CollectionInverseId` + WHERE `e0`.`Id` > 15 +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_on_navigation_then_filtered_include_on_skip_navigation(bool async) + { + await base.Filtered_include_on_navigation_then_filtered_include_on_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`Id0`, `t0`.`CollectionInverseId0`, `t0`.`Name0`, `t0`.`ReferenceInverseId0`, `t0`.`ThreeId`, `t0`.`TwoId` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `t`.`Id` AS `Id0`, `t`.`CollectionInverseId` AS `CollectionInverseId0`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId` AS `ReferenceInverseId0`, `t`.`ThreeId`, `t`.`TwoId` + FROM `EntityTwos` AS `e0` + LEFT JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j`.`ThreeId`, `j`.`TwoId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityThrees` AS `e1` ON `j`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 5 + ) AS `t` ON `e0`.`Id` = `t`.`TwoId` + WHERE `e0`.`Id` > 15 +) AS `t0` ON `e`.`Id` = `t0`.`CollectionInverseId` +ORDER BY `e`.`Id`, `t0`.`Id`, `t0`.`ThreeId`, `t0`.`TwoId` +"""); + } + + public override async Task Includes_accessed_via_different_path_are_merged(bool async) + { + await base.Includes_accessed_via_different_path_are_merged(async); + + AssertSql(); + } + + public override async Task Filtered_includes_accessed_via_different_path_are_merged(bool async) + { + await base.Filtered_includes_accessed_via_different_path_are_merged(async); + + AssertSql(); + } + + public override async Task Include_skip_navigation_split(bool async) + { + await base.Include_skip_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` +FROM `EntityCompositeKeys` AS `e` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`Slumber`, `t0`.`IsGreen`, `t0`.`IsBrown`, `t0`.`Discriminator`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityRoot` AS `e0` + INNER JOIN ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +"""); + } + + public override async Task Include_skip_navigation_then_reference_split(bool async) + { + await base.Include_skip_navigation_then_reference_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `j`.`TwoId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation_split(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` +FROM `EntityCompositeKeys` AS `e` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `Leaves` AS `l` ON `j`.`LeafId` = `l`.`Id` +) AS `t` ON ((`e`.`Key1` = `t`.`CompositeId1`) AND (`e`.`Key2` = `t`.`CompositeId2`)) AND (`e`.`Key3` = `t`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`Name`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Id` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `l`.`Id`, `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `Leaves` AS `l` ON `j`.`LeafId` = `l`.`Id` +) AS `t` ON ((`e`.`Key1` = `t`.`CompositeId1`) AND (`e`.`Key2` = `t`.`CompositeId2`)) AND (`e`.`Key3` = `t`.`CompositeId3`) +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j0`.`EntityBranchId` + FROM `JoinOneToBranch` AS `j0` + INNER JOIN `EntityOnes` AS `e0` ON `j0`.`EntityOneId` = `e0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`EntityBranchId` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation_split(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id`, `t`.`Id0` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`Name`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id`, `t`.`Id0` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e1`.`Id` AS `Id0`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +INNER JOIN ( + SELECT `e2`.`Id`, `e2`.`Name`, `j0`.`LeftId` + FROM `JoinOneSelfPayload` AS `j0` + INNER JOIN `EntityOnes` AS `e2` ON `j0`.`RightId` = `e2`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`LeftId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Include_skip_navigation_and_reference_split(bool async) + { + await base.Include_skip_navigation_and_reference_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +LEFT JOIN `EntityThrees` AS `e0` ON `e`.`Id` = `e0`.`ReferenceInverseId` +ORDER BY `e`.`Id`, `e0`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `e`.`Id`, `e0`.`Id` +FROM `EntityTwos` AS `e` +LEFT JOIN `EntityThrees` AS `e0` ON `e`.`Id` = `e0`.`ReferenceInverseId` +INNER JOIN ( + SELECT `e2`.`Id`, `e2`.`Name`, `e1`.`TwoSkipSharedId` + FROM `EntityOneEntityTwo` AS `e1` + INNER JOIN `EntityOnes` AS `e2` ON `e1`.`OneSkipSharedId` = `e2`.`Id` +) AS `t` ON `e`.`Id` = `t`.`TwoSkipSharedId` +ORDER BY `e`.`Id`, `e0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_split(bool async) + { + await base.Filtered_include_skip_navigation_where_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `e`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`ThreeId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`SelfSkipSharedLeftId` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`SelfSkipSharedLeftId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`SelfSkipSharedLeftId` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityTwoEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`SelfSkipSharedRightId` = `e1`.`Id` + ) AS `t` + WHERE 2 < `t`.`row` +) AS `t0` ON `e`.`Id` = `t0`.`SelfSkipSharedLeftId` +ORDER BY `e`.`Id`, `t0`.`SelfSkipSharedLeftId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_split(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` +FROM `EntityCompositeKeys` AS `e` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`CompositeKeySkipSharedKey1`, `t`.`CompositeKeySkipSharedKey2`, `t`.`CompositeKeySkipSharedKey3` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, ROW_NUMBER() OVER(PARTITION BY `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_split(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` +FROM `EntityCompositeKeys` AS `e` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, ROW_NUMBER() OVER(PARTITION BY `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeId1`) AND (`e`.`Key2` = `t0`.`CompositeId2`)) AND (`e`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_then_include_skip_navigation_where_split(bool async) + { + await base.Filtered_then_include_skip_navigation_where_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator` +FROM ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` +) AS `t` +ORDER BY `t`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `e`.`RootSkipSharedId`, `e`.`ThreeSkipSharedId` + FROM `EntityRootEntityThree` AS `e` + INNER JOIN `EntityThrees` AS `e0` ON `e`.`ThreeSkipSharedId` = `e0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id` +""", + // + """ +SELECT `t1`.`Id`, `t1`.`Name`, `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e0`.`Id`, `e`.`RootSkipSharedId`, `e`.`ThreeSkipSharedId` + FROM `EntityRootEntityThree` AS `e` + INNER JOIN `EntityThrees` AS `e0` ON `e`.`ThreeSkipSharedId` = `e0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +INNER JOIN ( + SELECT `e1`.`Id`, `e1`.`Name`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e1` ON `j`.`OneId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 +) AS `t1` ON `t0`.`Id` = `t1`.`ThreeId` +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_then_include_skip_navigation_order_by_skip_take_split(bool async) + { + await base.Filtered_then_include_skip_navigation_order_by_skip_take_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator` +FROM ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` +) AS `t` +ORDER BY `t`.`Id` +""", + // + """ +SELECT `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`Name`, `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e0`.`Name`, `e`.`RootSkipSharedId`, `e`.`CompositeKeySkipSharedKey1`, `e`.`CompositeKeySkipSharedKey2`, `e`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityRoot` AS `e` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`e`.`CompositeKeySkipSharedKey1` = `e0`.`Key1`) AND (`e`.`CompositeKeySkipSharedKey2` = `e0`.`Key2`)) AND (`e`.`CompositeKeySkipSharedKey3` = `e0`.`Key3`) +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3` +""", + // + """ +SELECT `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e`.`RootSkipSharedId`, `e`.`CompositeKeySkipSharedKey1`, `e`.`CompositeKeySkipSharedKey2`, `e`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityRoot` AS `e` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`e`.`CompositeKeySkipSharedKey1` = `e0`.`Key1`) AND (`e`.`CompositeKeySkipSharedKey2` = `e0`.`Key2`)) AND (`e`.`CompositeKeySkipSharedKey3` = `e0`.`Key3`) +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +INNER JOIN ( + SELECT `t2`.`Id`, `t2`.`CollectionInverseId`, `t2`.`Name`, `t2`.`ReferenceInverseId`, `t2`.`CompositeId1`, `t2`.`CompositeId2`, `t2`.`CompositeId3` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, ROW_NUMBER() OVER(PARTITION BY `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e1` ON `j`.`ThreeId` = `e1`.`Id` + ) AS `t2` + WHERE (1 < `t2`.`row`) AND (`t2`.`row` <= 3) +) AS `t1` ON ((`t0`.`Key1` = `t1`.`CompositeId1`) AND (`t0`.`Key2` = `t1`.`CompositeId2`)) AND (`t0`.`Key3` = `t1`.`CompositeId3`) +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t1`.`CompositeId1`, `t1`.`CompositeId2`, `t1`.`CompositeId3`, `t1`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_split(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_split(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen` +FROM `Leaves` AS `l` +ORDER BY `l`.`Id` +""", + // + """ +SELECT `t`.`Key1`, `t`.`Key2`, `t`.`Key3`, `t`.`Name`, `l`.`Id`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` +FROM `Leaves` AS `l` +INNER JOIN ( + SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e` ON ((`j`.`CompositeId1` = `e`.`Key1`) AND (`j`.`CompositeId2` = `e`.`Key2`)) AND (`j`.`CompositeId3` = `e`.`Key3`) + WHERE `e`.`Key1` < 5 +) AS `t` ON `l`.`Id` = `t`.`LeafId` +ORDER BY `l`.`Id`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Key1`, `t`.`Key2`, `t`.`Key3` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `l`.`Id`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Key1`, `t`.`Key2`, `t`.`Key3` +FROM `Leaves` AS `l` +INNER JOIN ( + SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e` ON ((`j`.`CompositeId1` = `e`.`Key1`) AND (`j`.`CompositeId2` = `e`.`Key2`)) AND (`j`.`CompositeId3` = `e`.`Key3`) + WHERE `e`.`Key1` < 5 +) AS `t` ON `l`.`Id` = `t`.`LeafId` +INNER JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` +) AS `t0` ON ((`t`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`t`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`t`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `l`.`Id`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Key1`, `t`.`Key2`, `t`.`Key3` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t0`.`OneId`, `t0`.`TwoId` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId`, ROW_NUMBER() OVER(PARTITION BY `j`.`OneId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON `e`.`Id` = `t0`.`OneId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`Id`, `t0`.`TwoId` +""", + // + """ +SELECT `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `e`.`Id`, `t0`.`OneId`, `t0`.`TwoId`, `t0`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`OneId`, `t`.`TwoId` + FROM ( + SELECT `e0`.`Id`, `j`.`OneId`, `j`.`TwoId`, ROW_NUMBER() OVER(PARTITION BY `j`.`OneId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON `e`.`Id` = `t0`.`OneId` +INNER JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j0`.`TwoId` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 +) AS `t1` ON `t0`.`Id` = `t1`.`TwoId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`Id`, `t0`.`TwoId` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take_split(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`TwoId` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`OneId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `j`.`OneId`, `j`.`TwoId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`OneId` +INNER JOIN ( + SELECT `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t1`.`TwoId` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j0`.`TwoId`, ROW_NUMBER() OVER(PARTITION BY `j0`.`TwoId` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + ) AS `t1` + WHERE (1 < `t1`.`row`) AND (`t1`.`row` <= 3) +) AS `t0` ON `t`.`Id` = `t0`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t0`.`TwoId`, `t0`.`Id` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined_split(bool async) + { + await base.Filter_include_on_skip_navigation_combined_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`TwoId` +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +""", + // + """ +SELECT `e2`.`Id`, `e2`.`CollectionInverseId`, `e2`.`ExtraId`, `e2`.`Name`, `e2`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e1`.`Id` AS `Id0`, `j`.`OneId`, `j`.`TwoId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`TwoId` +INNER JOIN `EntityTwos` AS `e2` ON `t`.`Id` = `e2`.`CollectionInverseId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined_with_filtered_then_includes_split(bool async) + { + await base.Filter_include_on_skip_navigation_combined_with_filtered_then_includes_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +INNER JOIN ( + SELECT `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`ExtraId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t1`.`OneId` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j0`.`OneId`, ROW_NUMBER() OVER(PARTITION BY `j0`.`OneId` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinOneToTwo` AS `j0` + INNER JOIN `EntityTwos` AS `e1` ON `j0`.`TwoId` = `e1`.`Id` + ) AS `t1` + WHERE (1 < `t1`.`row`) AND (`t1`.`row` <= 3) +) AS `t0` ON `t`.`Id` = `t0`.`OneId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id`, `t0`.`OneId`, `t0`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +INNER JOIN ( + SELECT `t1`.`Id`, `t1`.`Name`, `t1`.`Number`, `t1`.`IsGreen`, `t1`.`Discriminator`, `j0`.`EntityOneId` + FROM `JoinOneToBranch` AS `j0` + INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + ) AS `t1` ON `j0`.`EntityBranchId` = `t1`.`Id` + WHERE `t1`.`Id` < 20 +) AS `t0` ON `t`.`Id` = `t0`.`EntityOneId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +"""); + } + + public override async Task Filtered_include_on_skip_navigation_then_filtered_include_on_navigation_split(bool async) + { + await base.Filtered_include_on_skip_navigation_then_filtered_include_on_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` > 15 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` > 15 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +INNER JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `EntityTwos` AS `e1` + WHERE `e1`.`Id` < 5 +) AS `t0` ON `t`.`Id` = `t0`.`CollectionInverseId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +"""); + } + + public override async Task Filtered_include_on_navigation_then_filtered_include_on_skip_navigation_split(bool async) + { + await base.Filtered_include_on_navigation_then_filtered_include_on_skip_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` + FROM `EntityTwos` AS `e0` + WHERE `e0`.`Id` > 15 +) AS `t` ON `e`.`Id` = `t`.`CollectionInverseId` +ORDER BY `e`.`Id`, `t`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId` + FROM `EntityTwos` AS `e0` + WHERE `e0`.`Id` > 15 +) AS `t` ON `e`.`Id` = `t`.`CollectionInverseId` +INNER JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j`.`TwoId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityThrees` AS `e1` ON `j`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 5 +) AS `t0` ON `t`.`Id` = `t0`.`TwoId` +ORDER BY `e`.`Id`, `t`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_inverse_throws_in_no_tracking(bool async) + { + await base.Include_skip_navigation_then_include_inverse_throws_in_no_tracking(async); + + AssertSql(); + } + + public override async Task Include_skip_navigation_then_include_inverse_works_for_tracking_query(bool async) + { + await base.Include_skip_navigation_then_include_inverse_works_for_tracking_query(async); + + AssertSql(); + } + + public override async Task Throws_when_different_filtered_include(bool async) + { + await base.Throws_when_different_filtered_include(async); + + AssertSql(); + } + + public override async Task Throws_when_different_filtered_then_include(bool async) + { + await base.Throws_when_different_filtered_then_include(async); + + AssertSql(); + } + + public override async Task Throws_when_different_filtered_then_include_via_different_paths(bool async) + { + await base.Throws_when_different_filtered_then_include_via_different_paths(async); + + AssertSql(); + } + + public override async Task Select_many_over_skip_navigation_where_non_equality(bool async) + { + await base.Select_many_over_skip_navigation_where_non_equality(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` +) AS `t` ON (`e`.`Id` = `t`.`OneId`) AND (`e`.`Id` <> `t`.`Id`) +"""); + } + + public override async Task Contains_on_skip_collection_navigation(bool async) + { + await base.Contains_on_skip_collection_navigation(async); + + AssertSql( +""" +@__entity_equality_two_0_Id='1' (Nullable = true) + +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE EXISTS ( + SELECT 1 + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE (`e`.`Id` = `j`.`OneId`) AND (`e0`.`Id` = @__entity_equality_two_0_Id)) +"""); + } + + public override async Task GetType_in_hierarchy_in_base_type(bool async) + { + await base.GetType_in_hierarchy_in_base_type(async); + + AssertSql( +""" +SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` +FROM `Roots` AS `r` +"""); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` +FROM `Branches` AS `b` +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` +FROM `Leaves` AS `l` +"""); + } + + public override async Task GetType_in_hierarchy_in_querying_base_type(bool async) + { + await base.GetType_in_hierarchy_in_querying_base_type(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` +) AS `t` +WHERE FALSE +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_EF_Property(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_EF_Property(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`TwoSkipSharedId`, `t`.`CompositeKeySkipSharedKey1`, `t`.`CompositeKeySkipSharedKey2`, `t`.`CompositeKeySkipSharedKey3` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`TwoSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, ROW_NUMBER() OVER(PARTITION BY `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property( + bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`ExtraId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`Id0`, `t1`.`CollectionInverseId0`, `t1`.`Name0`, `t1`.`ReferenceInverseId0`, `t1`.`ThreeId`, `t1`.`TwoId0` +FROM `EntityOnes` AS `e` +LEFT JOIN LATERAL ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId`, `t0`.`Id` AS `Id0`, `t0`.`CollectionInverseId` AS `CollectionInverseId0`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId` AS `ReferenceInverseId0`, `t0`.`ThreeId`, `t0`.`TwoId` AS `TwoId0` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`OneId` + ORDER BY `e0`.`Id` + LIMIT 2 OFFSET 1 + ) AS `t` + LEFT JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `j0`.`ThreeId`, `j0`.`TwoId` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 + ) AS `t0` ON `t`.`Id` = `t0`.`TwoId` +) AS `t1` ON TRUE +ORDER BY `e`.`Id`, `t1`.`Id`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`ThreeId`, `t1`.`TwoId0` +"""); + } + + public override async Task Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(async); + + AssertSql(); + } + + public override async Task Skip_navigation_all_unidirectional(bool async) + { + await base.Skip_navigation_all_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE NOT EXISTS ( + SELECT 1 + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` + WHERE (`u`.`Id` = `u0`.`OneId`) AND NOT (`u1`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_any_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_any_with_predicate_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE EXISTS ( + SELECT 1 + FROM `UnidirectionalEntityOneUnidirectionalEntityTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoSkipSharedId` = `u1`.`Id` + WHERE (`u`.`Id` = `u0`.`UnidirectionalEntityOneId`) AND (`u1`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_contains_unidirectional(bool async) + { + await base.Skip_navigation_contains_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE EXISTS ( + SELECT 1 + FROM `UnidirectionalJoinOneToThreePayloadFullShared` AS `u0` + INNER JOIN `UnidirectionalEntityThrees` AS `u1` ON `u0`.`ThreeId` = `u1`.`Id` + WHERE (`u`.`Id` = `u0`.`OneId`) AND (`u1`.`Id` = 1)) +"""); + } + + public override async Task Skip_navigation_count_without_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_without_predicate_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE ( + SELECT COUNT(*) + FROM `UnidirectionalJoinOneSelfPayload` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`LeftId` = `u1`.`Id` + WHERE `u`.`Id` = `u0`.`RightId`) > 0 +"""); + } + + public override async Task Skip_navigation_count_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_with_predicate_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +ORDER BY ( + SELECT COUNT(*) + FROM `UnidirectionalJoinOneToBranch` AS `u0` + INNER JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u1`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u1` + UNION ALL + SELECT `u2`.`Id`, `u2`.`Name`, `u2`.`Number`, `u2`.`IsGreen`, 'UnidirectionalEntityLeaf' AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u2` + ) AS `t` ON `u0`.`UnidirectionalEntityBranchId` = `t`.`Id` + WHERE (`u`.`Id` = `u0`.`UnidirectionalEntityOneId`) AND (`t`.`Name` IS NOT NULL AND (`t`.`Name` LIKE 'L%'))), `u`.`Id` +"""); + } + + public override async Task Skip_navigation_select_subquery_average_unidirectional(bool async) + { + await base.Skip_navigation_select_subquery_average_unidirectional(async); + + AssertSql( +$""" +SELECT ( + SELECT AVG({MySqlTestHelpers.CastAsDouble(@"`u1`.`Key1`")}) + FROM `UnidirectionalJoinCompositeKeyToLeaf` AS `u0` + INNER JOIN `UnidirectionalEntityCompositeKeys` AS `u1` ON ((`u0`.`CompositeId1` = `u1`.`Key1`) AND (`u0`.`CompositeId2` = `u1`.`Key2`)) AND (`u0`.`CompositeId3` = `u1`.`Key3`) + WHERE `u`.`Id` = `u0`.`LeafId`) +FROM `UnidirectionalLeaves` AS `u` +"""); + } + + public override async Task Skip_navigation_order_by_reverse_first_or_default_unidirectional(bool async) + { + await base.Skip_navigation_order_by_reverse_first_or_default_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityThrees` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`ThreeId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`ThreeId` ORDER BY `u1`.`Id` DESC) AS `row` + FROM `UnidirectionalJoinTwoToThree` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `u`.`Id` = `t0`.`ThreeId` +"""); + } + + public override async Task Skip_navigation_of_type_unidirectional(bool async) + { + await base.Skip_navigation_of_type_unidirectional(async); + + AssertSql( +$""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator`, `t0`.`RootSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `u0`.`RootSkipSharedId`, `u0`.`UnidirectionalEntityCompositeKeyKey1`, `u0`.`UnidirectionalEntityCompositeKeyKey2`, `u0`.`UnidirectionalEntityCompositeKeyKey3` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot` AS `u0` + INNER JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'UnidirectionalEntityRoot' AS `Discriminator` + FROM `UnidirectionalRoots` AS `u1` + UNION ALL + SELECT `u2`.`Id`, `u2`.`Name`, `u2`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u2` + UNION ALL + SELECT `u3`.`Id`, `u3`.`Name`, `u3`.`Number`, `u3`.`IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'UnidirectionalEntityLeaf'")} AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u3` + ) AS `t` ON `u0`.`RootSkipSharedId` = `t`.`Id` + WHERE `t`.`Discriminator` = 'UnidirectionalEntityLeaf' +) AS `t0` ON ((`u`.`Key1` = `t0`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u`.`Key2` = `t0`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u`.`Key3` = `t0`.`UnidirectionalEntityCompositeKeyKey3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`RootSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +"""); + } + + public override async Task Join_with_skip_navigation_unidirectional(bool async) + { + await base.Join_with_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`ExtraId`, `u`.`Name`, `u`.`ReferenceInverseId`, `u0`.`Id`, `u0`.`CollectionInverseId`, `u0`.`ExtraId`, `u0`.`Name`, `u0`.`ReferenceInverseId` +FROM `UnidirectionalEntityTwos` AS `u` +INNER JOIN `UnidirectionalEntityTwos` AS `u0` ON `u`.`Id` = ( + SELECT `u2`.`Id` + FROM `UnidirectionalEntityTwoUnidirectionalEntityTwo` AS `u1` + INNER JOIN `UnidirectionalEntityTwos` AS `u2` ON `u1`.`SelfSkipSharedRightId` = `u2`.`Id` + WHERE `u0`.`Id` = `u1`.`UnidirectionalEntityTwoId` + ORDER BY `u2`.`Id` + LIMIT 1) +"""); + } + + public override async Task Left_join_with_skip_navigation_unidirectional(bool async) + { + await base.Left_join_with_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `u0`.`Key1`, `u0`.`Key2`, `u0`.`Key3`, `u0`.`Name` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN `UnidirectionalEntityCompositeKeys` AS `u0` ON ( + SELECT `u2`.`Id` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo` AS `u1` + INNER JOIN `UnidirectionalEntityTwos` AS `u2` ON `u1`.`TwoSkipSharedId` = `u2`.`Id` + WHERE ((`u`.`Key1` = `u1`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u`.`Key2` = `u1`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u`.`Key3` = `u1`.`UnidirectionalEntityCompositeKeyKey3`) + ORDER BY `u2`.`Id` + LIMIT 1) = ( + SELECT `u4`.`Id` + FROM `UnidirectionalJoinThreeToCompositeKeyFull` AS `u3` + INNER JOIN `UnidirectionalEntityThrees` AS `u4` ON `u3`.`ThreeId` = `u4`.`Id` + WHERE ((`u0`.`Key1` = `u3`.`CompositeId1`) AND (`u0`.`Key2` = `u3`.`CompositeId2`)) AND (`u0`.`Key3` = `u3`.`CompositeId3`) + ORDER BY `u4`.`Id` + LIMIT 1) +ORDER BY `u`.`Key1`, `u0`.`Key1`, `u`.`Key2`, `u0`.`Key2` +"""); + } + + public override async Task Select_many_over_skip_navigation_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM ( + SELECT `u1`.`Id` + FROM `UnidirectionalRoots` AS `u1` + UNION ALL + SELECT `u2`.`Id` + FROM `UnidirectionalBranches` AS `u2` + UNION ALL + SELECT `u3`.`Id` + FROM `UnidirectionalLeaves` AS `u3` +) AS `t` +INNER JOIN ( + SELECT `u0`.`Id`, `u0`.`CollectionInverseId`, `u0`.`Name`, `u0`.`ReferenceInverseId`, `u`.`UnidirectionalEntityRootId` + FROM `UnidirectionalEntityRootUnidirectionalEntityThree` AS `u` + INNER JOIN `UnidirectionalEntityThrees` AS `u0` ON `u`.`ThreeSkipSharedId` = `u0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`UnidirectionalEntityRootId` +"""); + } + + public override async Task Select_many_over_skip_navigation_where_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_unidirectional(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `UnidirectionalEntityOnes` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`OneId` + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` +) AS `t` ON `u`.`Id` = `t`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityOnes` AS `u` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`UnidirectionalEntityOneId` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`UnidirectionalEntityOneId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`UnidirectionalEntityOneId` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalEntityOneUnidirectionalEntityTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoSkipSharedId` = `u1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON `u`.`Id` = `t0`.`UnidirectionalEntityOneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityOnes` AS `u` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`OneId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`OneId` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalJoinOneToThreePayloadFullShared` AS `u0` + INNER JOIN `UnidirectionalEntityThrees` AS `u1` ON `u0`.`ThreeId` = `u1`.`Id` + ) AS `t` + WHERE (2 < `t`.`row`) AND (`t`.`row` <= 5) +) AS `t0` ON `u`.`Id` = `t0`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_cast_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_cast_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator` +FROM `UnidirectionalEntityOnes` AS `u` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `u0`.`UnidirectionalEntityOneId` + FROM `UnidirectionalJoinOneToBranch` AS `u0` + INNER JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u1`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u1` + UNION ALL + SELECT `u2`.`Id`, `u2`.`Name`, `u2`.`Number`, `u2`.`IsGreen`, 'UnidirectionalEntityLeaf' AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u2` + ) AS `t` ON `u0`.`UnidirectionalEntityBranchId` = `t`.`Id` +) AS `t0` ON `u`.`Id` = `t0`.`UnidirectionalEntityOneId` +"""); + } + + public override async Task Select_skip_navigation_unidirectional(bool async) + { + await base.Select_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `t`.`Id`, `t`.`Name`, `t`.`LeftId`, `t`.`RightId` +FROM `UnidirectionalEntityOnes` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u0`.`LeftId`, `u0`.`RightId` + FROM `UnidirectionalJoinOneSelfPayload` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`LeftId` = `u1`.`Id` +) AS `t` ON `u`.`Id` = `t`.`RightId` +ORDER BY `u`.`Id`, `t`.`LeftId`, `t`.`RightId` +"""); + } + + public override async Task Include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_unidirectional(async); + + AssertSql( +$""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator`, `t0`.`RootSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `u0`.`RootSkipSharedId`, `u0`.`UnidirectionalEntityCompositeKeyKey1`, `u0`.`UnidirectionalEntityCompositeKeyKey2`, `u0`.`UnidirectionalEntityCompositeKeyKey3` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot` AS `u0` + INNER JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'UnidirectionalEntityRoot' AS `Discriminator` + FROM `UnidirectionalRoots` AS `u1` + UNION ALL + SELECT `u2`.`Id`, `u2`.`Name`, `u2`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u2` + UNION ALL + SELECT `u3`.`Id`, `u3`.`Name`, `u3`.`Number`, `u3`.`IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'UnidirectionalEntityLeaf'")} AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u3` + ) AS `t` ON `u0`.`RootSkipSharedId` = `t`.`Id` +) AS `t0` ON ((`u`.`Key1` = `t0`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u`.`Key2` = `t0`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u`.`Key3` = `t0`.`UnidirectionalEntityCompositeKeyKey3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`RootSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +"""); + } + + public override async Task Include_skip_navigation_then_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_then_reference_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`ExtraId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId` +FROM `UnidirectionalEntityTwos` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u2`.`Id` AS `Id0`, `u2`.`CollectionInverseId`, `u2`.`ExtraId`, `u2`.`Name` AS `Name0`, `u2`.`ReferenceInverseId`, `u0`.`OneId`, `u0`.`TwoId` + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`OneId` = `u1`.`Id` + LEFT JOIN `UnidirectionalEntityTwos` AS `u2` ON `u1`.`Id` = `u2`.`ReferenceInverseId` +) AS `t` ON `u`.`Id` = `t`.`TwoId` +ORDER BY `u`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id0`, `t0`.`Name0`, `t0`.`UnidirectionalEntityBranchId`, `t0`.`UnidirectionalEntityOneId` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u1`.`Number`, `u1`.`IsGreen`, `u0`.`LeafId`, `u0`.`CompositeId1`, `u0`.`CompositeId2`, `u0`.`CompositeId3`, `t`.`Id` AS `Id0`, `t`.`Name` AS `Name0`, `t`.`UnidirectionalEntityBranchId`, `t`.`UnidirectionalEntityOneId` + FROM `UnidirectionalJoinCompositeKeyToLeaf` AS `u0` + INNER JOIN `UnidirectionalLeaves` AS `u1` ON `u0`.`LeafId` = `u1`.`Id` + LEFT JOIN ( + SELECT `u3`.`Id`, `u3`.`Name`, `u2`.`UnidirectionalEntityBranchId`, `u2`.`UnidirectionalEntityOneId` + FROM `UnidirectionalJoinOneToBranch` AS `u2` + INNER JOIN `UnidirectionalEntityOnes` AS `u3` ON `u2`.`UnidirectionalEntityOneId` = `u3`.`Id` + ) AS `t` ON `u1`.`Id` = `t`.`UnidirectionalEntityBranchId` +) AS `t0` ON ((`u`.`Key1` = `t0`.`CompositeId1`) AND (`u`.`Key2` = `t0`.`CompositeId2`)) AND (`u`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id`, `t0`.`UnidirectionalEntityBranchId`, `t0`.`UnidirectionalEntityOneId` +"""); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t0`.`Id`, `t0`.`Name`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id1`, `t0`.`Name1`, `t0`.`LeftId`, `t0`.`RightId` +FROM `UnidirectionalEntityThrees` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u2`.`Id` AS `Id0`, `u2`.`CollectionInverseId`, `u2`.`ExtraId`, `u2`.`Name` AS `Name0`, `u2`.`ReferenceInverseId`, `u0`.`OneId`, `u0`.`ThreeId`, `t`.`Id` AS `Id1`, `t`.`Name` AS `Name1`, `t`.`LeftId`, `t`.`RightId` + FROM `UnidirectionalJoinOneToThreePayloadFull` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`OneId` = `u1`.`Id` + LEFT JOIN `UnidirectionalEntityTwos` AS `u2` ON `u1`.`Id` = `u2`.`ReferenceInverseId` + LEFT JOIN ( + SELECT `u4`.`Id`, `u4`.`Name`, `u3`.`LeftId`, `u3`.`RightId` + FROM `UnidirectionalJoinOneSelfPayload` AS `u3` + INNER JOIN `UnidirectionalEntityOnes` AS `u4` ON `u3`.`RightId` = `u4`.`Id` + ) AS `t` ON `u1`.`Id` = `t`.`LeftId` +) AS `t0` ON `u`.`Id` = `t0`.`ThreeId` +ORDER BY `u`.`Id`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id`, `t0`.`Id0`, `t0`.`LeftId`, `t0`.`RightId` +"""); + } + + public override async Task Include_skip_navigation_and_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_and_reference_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`ExtraId`, `u`.`Name`, `u`.`ReferenceInverseId`, `u0`.`Id`, `t`.`Id`, `t`.`Name`, `t`.`TwoSkipSharedId`, `t`.`UnidirectionalEntityOneId`, `u0`.`CollectionInverseId`, `u0`.`Name`, `u0`.`ReferenceInverseId` +FROM `UnidirectionalEntityTwos` AS `u` +LEFT JOIN `UnidirectionalEntityThrees` AS `u0` ON `u`.`Id` = `u0`.`ReferenceInverseId` +LEFT JOIN ( + SELECT `u2`.`Id`, `u2`.`Name`, `u1`.`TwoSkipSharedId`, `u1`.`UnidirectionalEntityOneId` + FROM `UnidirectionalEntityOneUnidirectionalEntityTwo` AS `u1` + INNER JOIN `UnidirectionalEntityOnes` AS `u2` ON `u1`.`UnidirectionalEntityOneId` = `u2`.`Id` +) AS `t` ON `u`.`Id` = `t`.`TwoSkipSharedId` +ORDER BY `u`.`Id`, `u0`.`Id`, `t`.`TwoSkipSharedId`, `t`.`UnidirectionalEntityOneId` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_unidirectional(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`Id`, `t`.`Name`, `t`.`OneId`, `t`.`ThreeId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`OneId`, `j`.`ThreeId` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId`, `t`.`TwoId` +FROM `UnidirectionalEntityThrees` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`ThreeId`, `u0`.`TwoId` + FROM `UnidirectionalJoinTwoToThree` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` +) AS `t` ON `u`.`Id` = `t`.`ThreeId` +ORDER BY `u`.`Id`, `t`.`Id`, `t`.`ThreeId` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`ExtraId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`SelfSkipSharedRightId`, `t0`.`UnidirectionalEntityTwoId` +FROM `UnidirectionalEntityTwos` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`SelfSkipSharedRightId`, `t`.`UnidirectionalEntityTwoId` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`SelfSkipSharedRightId`, `u0`.`UnidirectionalEntityTwoId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`UnidirectionalEntityTwoId` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalEntityTwoUnidirectionalEntityTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`SelfSkipSharedRightId` = `u1`.`Id` + ) AS `t` + WHERE 2 < `t`.`row` +) AS `t0` ON `u`.`Id` = `t0`.`UnidirectionalEntityTwoId` +ORDER BY `u`.`Id`, `t0`.`UnidirectionalEntityTwoId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`TwoSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`TwoSkipSharedId`, `t`.`UnidirectionalEntityCompositeKeyKey1`, `t`.`UnidirectionalEntityCompositeKeyKey2`, `t`.`UnidirectionalEntityCompositeKeyKey3` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`TwoSkipSharedId`, `u0`.`UnidirectionalEntityCompositeKeyKey1`, `u0`.`UnidirectionalEntityCompositeKeyKey2`, `u0`.`UnidirectionalEntityCompositeKeyKey3`, ROW_NUMBER() OVER(PARTITION BY `u0`.`UnidirectionalEntityCompositeKeyKey1`, `u0`.`UnidirectionalEntityCompositeKeyKey2`, `u0`.`UnidirectionalEntityCompositeKeyKey3` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoSkipSharedId` = `u1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON ((`u`.`Key1` = `t0`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u`.`Key2` = `t0`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u`.`Key3` = `t0`.`UnidirectionalEntityCompositeKeyKey3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_unidirectional(async); + AssertSql( +""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`Id0` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`Id0`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`Id` AS `Id0`, `u0`.`CompositeId1`, `u0`.`CompositeId2`, `u0`.`CompositeId3`, ROW_NUMBER() OVER(PARTITION BY `u0`.`CompositeId1`, `u0`.`CompositeId2`, `u0`.`CompositeId3` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalJoinThreeToCompositeKeyFull` AS `u0` + INNER JOIN `UnidirectionalEntityThrees` AS `u1` ON `u0`.`ThreeId` = `u1`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON ((`u`.`Key1` = `t0`.`CompositeId1`) AND (`u`.`Key2` = `t0`.`CompositeId2`)) AND (`u`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name`, `u`.`Number`, `u`.`IsGreen`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`Name`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId`, `t0`.`TwoSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +FROM `UnidirectionalLeaves` AS `u` +LEFT JOIN ( + SELECT `u1`.`Key1`, `u1`.`Key2`, `u1`.`Key3`, `u1`.`Name`, `u0`.`LeafId`, `u0`.`CompositeId1`, `u0`.`CompositeId2`, `u0`.`CompositeId3`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId`, `t`.`TwoSkipSharedId`, `t`.`UnidirectionalEntityCompositeKeyKey1`, `t`.`UnidirectionalEntityCompositeKeyKey2`, `t`.`UnidirectionalEntityCompositeKeyKey3` + FROM `UnidirectionalJoinCompositeKeyToLeaf` AS `u0` + INNER JOIN `UnidirectionalEntityCompositeKeys` AS `u1` ON ((`u0`.`CompositeId1` = `u1`.`Key1`) AND (`u0`.`CompositeId2` = `u1`.`Key2`)) AND (`u0`.`CompositeId3` = `u1`.`Key3`) + LEFT JOIN ( + SELECT `u3`.`Id`, `u3`.`CollectionInverseId`, `u3`.`ExtraId`, `u3`.`Name`, `u3`.`ReferenceInverseId`, `u2`.`TwoSkipSharedId`, `u2`.`UnidirectionalEntityCompositeKeyKey1`, `u2`.`UnidirectionalEntityCompositeKeyKey2`, `u2`.`UnidirectionalEntityCompositeKeyKey3` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo` AS `u2` + INNER JOIN `UnidirectionalEntityTwos` AS `u3` ON `u2`.`TwoSkipSharedId` = `u3`.`Id` + ) AS `t` ON ((`u1`.`Key1` = `t`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u1`.`Key2` = `t`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u1`.`Key3` = `t`.`UnidirectionalEntityCompositeKeyKey3`) + WHERE `u1`.`Key1` < 5 +) AS `t0` ON `u`.`Id` = `t0`.`LeafId` +ORDER BY `u`.`Id`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`TwoSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined_unidirectional(bool async) + { + await base.Filter_include_on_skip_navigation_combined_unidirectional(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id1`, `t`.`CollectionInverseId0`, `t`.`ExtraId0`, `t`.`Name1`, `t`.`ReferenceInverseId0` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `j`.`OneId`, `j`.`TwoId`, `e2`.`Id` AS `Id1`, `e2`.`CollectionInverseId` AS `CollectionInverseId0`, `e2`.`ExtraId` AS `ExtraId0`, `e2`.`Name` AS `Name1`, `e2`.`ReferenceInverseId` AS `ReferenceInverseId0` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + LEFT JOIN `EntityTwos` AS `e2` ON `e0`.`Id` = `e2`.`CollectionInverseId` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Throws_when_different_filtered_include_unidirectional(bool async) + { + await base.Throws_when_different_filtered_include_unidirectional(async); + + AssertSql(); + } + + public override async Task Includes_accessed_via_different_path_are_merged_unidirectional(bool async) + { + await base.Includes_accessed_via_different_path_are_merged_unidirectional(async); + + AssertSql( +""" +SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[Id0] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[Id0], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[Id] AS [Id0], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], ROW_NUMBER() OVER(PARTITION BY [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 1 < [t].[row] AND [t].[row] <= 3 +) AS [t0] ON [u].[Key1] = [t0].[CompositeId1] AND [u].[Key2] = [t0].[CompositeId2] AND [u].[Key3] = [t0].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id] +"""); + } + + public override async Task Select_many_over_skip_navigation_where_non_equality_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_non_equality_unidirectional(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `UnidirectionalEntityOnes` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`OneId` + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` +) AS `t` ON (`u`.`Id` = `t`.`OneId`) AND (`u`.`Id` <> `t`.`Id`) +"""); + } + + public override async Task Contains_on_skip_collection_navigation_unidirectional(bool async) + { + await base.Contains_on_skip_collection_navigation_unidirectional(async); + + AssertSql( +""" +@__entity_equality_two_0_Id='1' (Nullable = true) + +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE EXISTS ( + SELECT 1 + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` + WHERE (`u`.`Id` = `u0`.`OneId`) AND (`u1`.`Id` = @__entity_equality_two_0_Id)) +"""); + } + + public override async Task GetType_in_hierarchy_in_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_base_type_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'UnidirectionalEntityRoot' AS `Discriminator` +FROM `UnidirectionalRoots` AS `u` +"""); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name`, `u`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` +FROM `UnidirectionalBranches` AS `u` +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_unidirectional(async); + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name`, `u`.`Number`, `u`.`IsGreen`, 'UnidirectionalEntityLeaf' AS `Discriminator` +FROM `UnidirectionalLeaves` AS `u` +"""); + } + + public override async Task GetType_in_hierarchy_in_querying_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_querying_base_type_unidirectional(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator` +FROM ( + SELECT `u`.`Id`, `u`.`Name`, `u`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u` + UNION ALL + SELECT `u0`.`Id`, `u0`.`Name`, `u0`.`Number`, `u0`.`IsGreen`, 'UnidirectionalEntityLeaf' AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u0` +) AS `t` +WHERE FALSE +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyQueryMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyQueryMySqlFixture.cs new file mode 100644 index 000000000..cc451f948 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyQueryMySqlFixture.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCManyToManyQueryMySqlFixture : TPCManyToManyQueryRelationalFixture +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + // We default to mapping DateTime to 'timestamp with time zone', but the seeding data has Unspecified DateTimes which aren't + // supported. + // modelBuilder.Entity().Property(e => e.Key3).HasColumnType("timestamp without time zone"); + // modelBuilder.Entity().Property(e => e.CompositeId3).HasColumnType("timestamp without time zone"); + // modelBuilder.Entity().Property(e => e.Key3).HasColumnType("timestamp without time zone"); + // modelBuilder.Entity().Property(e => e.Payload).HasColumnType("timestamp without time zone"); + // modelBuilder.Entity().Property(e => e.Payload).HasColumnType("timestamp without time zone"); + // modelBuilder.Entity().Property(e => e.CompositeId3).HasColumnType("timestamp without time zone"); + } +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyQueryMySqlTest.cs new file mode 100644 index 000000000..3082118e0 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCManyToManyQueryMySqlTest.cs @@ -0,0 +1,2831 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCManyToManyQueryMySqlTest : TPCManyToManyQueryRelationalTestBase +{ + public TPCManyToManyQueryMySqlTest(TPCManyToManyQueryMySqlFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + Fixture.TestSqlLoggerFactory.Clear(); + //Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + protected override bool CanExecuteQueryString + => true; + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Skip_navigation_all(bool async) + { + await base.Skip_navigation_all(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE NOT EXISTS ( + SELECT 1 + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE (`e`.`Id` = `j`.`OneId`) AND NOT (`e0`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_any_without_predicate(bool async) + { + await base.Skip_navigation_any_without_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE EXISTS ( + SELECT 1 + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + WHERE (`e`.`Id` = `j`.`OneId`) AND (`e0`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_any_with_predicate(bool async) + { + await base.Skip_navigation_any_with_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE EXISTS ( + SELECT 1 + FROM `EntityOneEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + WHERE (`e`.`Id` = `e0`.`OneSkipSharedId`) AND (`e1`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_contains(bool async) + { + await base.Skip_navigation_contains(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE EXISTS ( + SELECT 1 + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + WHERE (`e`.`Id` = `j`.`OneId`) AND (`e0`.`Id` = 1)) +"""); + } + + public override async Task Skip_navigation_count_without_predicate(bool async) + { + await base.Skip_navigation_count_without_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE ( + SELECT COUNT(*) + FROM `JoinOneSelfPayload` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`LeftId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`RightId`) > 0 +"""); + } + + public override async Task Skip_navigation_count_with_predicate(bool async) + { + await base.Skip_navigation_count_with_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +ORDER BY ( + SELECT COUNT(*) + FROM `JoinOneToBranch` AS `j` + INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + ) AS `t` ON `j`.`EntityBranchId` = `t`.`Id` + WHERE (`e`.`Id` = `j`.`EntityOneId`) AND (`t`.`Name` IS NOT NULL AND (`t`.`Name` LIKE 'L%'))), `e`.`Id` +"""); + } + + public override async Task Skip_navigation_long_count_without_predicate(bool async) + { + await base.Skip_navigation_long_count_without_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +WHERE ( + SELECT COUNT(*) + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`TwoId`) > 0 +"""); + } + + public override async Task Skip_navigation_long_count_with_predicate(bool async) + { + await base.Skip_navigation_long_count_with_predicate(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +ORDER BY ( + SELECT COUNT(*) + FROM `EntityTwoEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`SelfSkipSharedLeftId` = `e1`.`Id` + WHERE (`e`.`Id` = `e0`.`SelfSkipSharedRightId`) AND (`e1`.`Name` IS NOT NULL AND (`e1`.`Name` LIKE 'L%'))) DESC, `e`.`Id` +"""); + } + + public override async Task Skip_navigation_select_many_average(bool async) + { + await base.Skip_navigation_select_many_average(async); + + AssertSql( +$""" +SELECT AVG({MySqlTestHelpers.CastAsDouble(@"`t`.`Key1`")}) +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `e1`.`Key1`, `e0`.`TwoSkipSharedId` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityCompositeKeys` AS `e1` ON ((`e0`.`CompositeKeySkipSharedKey1` = `e1`.`Key1`) AND (`e0`.`CompositeKeySkipSharedKey2` = `e1`.`Key2`)) AND (`e0`.`CompositeKeySkipSharedKey3` = `e1`.`Key3`) +) AS `t` ON `e`.`Id` = `t`.`TwoSkipSharedId` +"""); + } + + public override async Task Skip_navigation_select_many_max(bool async) + { + await base.Skip_navigation_select_many_max(async); + + AssertSql( +""" +SELECT MAX(`t`.`Key1`) +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `e0`.`Key1`, `j`.`ThreeId` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`j`.`CompositeId1` = `e0`.`Key1`) AND (`j`.`CompositeId2` = `e0`.`Key2`)) AND (`j`.`CompositeId3` = `e0`.`Key3`) +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +"""); + } + + public override async Task Skip_navigation_select_many_min(bool async) + { + await base.Skip_navigation_select_many_min(async); + + AssertSql( +""" +SELECT MIN(`t0`.`Id`) +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `e0`.`ThreeSkipSharedId` + FROM `EntityRootEntityThree` AS `e0` + INNER JOIN ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` +) AS `t0` ON `e`.`Id` = `t0`.`ThreeSkipSharedId` +"""); + } + + public override async Task Skip_navigation_select_many_sum(bool async) + { + await base.Skip_navigation_select_many_sum(async); + + AssertSql( +""" +SELECT COALESCE(SUM(`t0`.`Key1`), 0) +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e0`.`Key1`, `e`.`RootSkipSharedId` + FROM `EntityCompositeKeyEntityRoot` AS `e` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`e`.`CompositeKeySkipSharedKey1` = `e0`.`Key1`) AND (`e`.`CompositeKeySkipSharedKey2` = `e0`.`Key2`)) AND (`e`.`CompositeKeySkipSharedKey3` = `e0`.`Key3`) +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +"""); + } + + public override async Task Skip_navigation_select_subquery_average(bool async) + { + await base.Skip_navigation_select_subquery_average(async); + + AssertSql( +$""" +SELECT ( + SELECT AVG({MySqlTestHelpers.CastAsDouble(@"`e`.`Key1`")}) + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e` ON ((`j`.`CompositeId1` = `e`.`Key1`) AND (`j`.`CompositeId2` = `e`.`Key2`)) AND (`j`.`CompositeId3` = `e`.`Key3`) + WHERE `l`.`Id` = `j`.`LeafId`) +FROM `Leaves` AS `l` +"""); + } + + public override async Task Skip_navigation_select_subquery_max(bool async) + { + await base.Skip_navigation_select_subquery_max(async); + + AssertSql( +""" +SELECT ( + SELECT MAX(`e0`.`Id`) + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`TwoId`) +FROM `EntityTwos` AS `e` +"""); + } + + public override async Task Skip_navigation_select_subquery_min(bool async) + { + await base.Skip_navigation_select_subquery_min(async); + + AssertSql( +""" +SELECT ( + SELECT MIN(`e0`.`Id`) + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`ThreeId`) +FROM `EntityThrees` AS `e` +"""); + } + + public override async Task Skip_navigation_select_subquery_sum(bool async) + { + await base.Skip_navigation_select_subquery_sum(async); + + AssertSql( +""" +SELECT ( + SELECT COALESCE(SUM(`e1`.`Id`), 0) + FROM `EntityOneEntityTwo` AS `e0` + INNER JOIN `EntityOnes` AS `e1` ON `e0`.`OneSkipSharedId` = `e1`.`Id` + WHERE `e`.`Id` = `e0`.`TwoSkipSharedId`) +FROM `EntityTwos` AS `e` +"""); + } + + public override async Task Skip_navigation_order_by_first_or_default(bool async) + { + await base.Skip_navigation_order_by_first_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`ThreeId` + FROM ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`ThreeId`, ROW_NUMBER() OVER(PARTITION BY `j`.`ThreeId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +"""); + } + + public override async Task Skip_navigation_order_by_single_or_default(bool async) + { + await base.Skip_navigation_order_by_single_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name` +FROM `EntityOnes` AS `e` +LEFT JOIN LATERAL ( + SELECT `t`.`Id`, `t`.`Name` + FROM ( + SELECT `e0`.`Id`, `e0`.`Name` + FROM `JoinOneSelfPayload` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`RightId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`LeftId` + ORDER BY `e0`.`Id` + LIMIT 1 + ) AS `t` + ORDER BY `t`.`Id` + LIMIT 1 +) AS `t0` ON TRUE +"""); + } + + public override async Task Skip_navigation_order_by_last_or_default(bool async) + { + await base.Skip_navigation_order_by_last_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name` +FROM ( + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` +) AS `t` +LEFT JOIN ( + SELECT `t1`.`Id`, `t1`.`Name`, `t1`.`EntityBranchId` + FROM ( + SELECT `e`.`Id`, `e`.`Name`, `j`.`EntityBranchId`, ROW_NUMBER() OVER(PARTITION BY `j`.`EntityBranchId` ORDER BY `e`.`Id` DESC) AS `row` + FROM `JoinOneToBranch` AS `j` + INNER JOIN `EntityOnes` AS `e` ON `j`.`EntityOneId` = `e`.`Id` + ) AS `t1` + WHERE `t1`.`row` <= 1 +) AS `t0` ON `t`.`Id` = `t0`.`EntityBranchId` +"""); + } + + public override async Task Skip_navigation_order_by_reverse_first_or_default(bool async) + { + await base.Skip_navigation_order_by_reverse_first_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`ThreeId`, ROW_NUMBER() OVER(PARTITION BY `j`.`ThreeId` ORDER BY `e0`.`Id` DESC) AS `row` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +"""); + } + + public override async Task Skip_navigation_cast(bool async) + { + await base.Skip_navigation_cast(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `Leaves` AS `l` ON `j`.`LeafId` = `l`.`Id` +) AS `t` ON ((`e`.`Key1` = `t`.`CompositeId1`) AND (`e`.`Key2` = `t`.`CompositeId2`)) AND (`e`.`Key3` = `t`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3` +"""); + } + + public override async Task Skip_navigation_of_type(bool async) + { + await base.Skip_navigation_of_type(async); + + AssertSql( +$""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `e0`.`RootSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityRoot` AS `e0` + INNER JOIN ( + SELECT `r`.`Id`, `r`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityRoot'")} AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityBranch'")} AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityLeaf2'")} AS `Discriminator` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` + WHERE `t`.`Discriminator` = 'EntityLeaf' +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +"""); + } + + public override async Task Join_with_skip_navigation(bool async) + { + await base.Join_with_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +INNER JOIN `EntityTwos` AS `e0` ON `e`.`Id` = ( + SELECT `e2`.`Id` + FROM `EntityTwoEntityTwo` AS `e1` + INNER JOIN `EntityTwos` AS `e2` ON `e1`.`SelfSkipSharedRightId` = `e2`.`Id` + WHERE `e0`.`Id` = `e1`.`SelfSkipSharedLeftId` + ORDER BY `e2`.`Id` + LIMIT 1) +"""); + } + + public override async Task Left_join_with_skip_navigation(bool async) + { + await base.Left_join_with_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e0`.`Name` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN `EntityCompositeKeys` AS `e0` ON ( + SELECT `e2`.`Id` + FROM `EntityCompositeKeyEntityTwo` AS `e1` + INNER JOIN `EntityTwos` AS `e2` ON `e1`.`TwoSkipSharedId` = `e2`.`Id` + WHERE ((`e`.`Key1` = `e1`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `e1`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `e1`.`CompositeKeySkipSharedKey3`) + ORDER BY `e2`.`Id` + LIMIT 1) = ( + SELECT `e3`.`Id` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e3` ON `j`.`ThreeId` = `e3`.`Id` + WHERE ((`e0`.`Key1` = `j`.`CompositeId1`) AND (`e0`.`Key2` = `j`.`CompositeId2`)) AND (`e0`.`Key3` = `j`.`CompositeId3`) + ORDER BY `e3`.`Id` + LIMIT 1) +ORDER BY `e`.`Key1`, `e0`.`Key1`, `e`.`Key2`, `e0`.`Key2` +"""); + } + + public override async Task Select_many_over_skip_navigation(bool async) + { + await base.Select_many_over_skip_navigation(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `e`.`RootSkipSharedId` + FROM `EntityRootEntityThree` AS `e` + INNER JOIN `EntityThrees` AS `e0` ON `e`.`ThreeSkipSharedId` = `e0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +"""); + } + + public override async Task Select_many_over_skip_navigation_where(bool async) + { + await base.Select_many_over_skip_navigation_where(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, ROW_NUMBER() OVER(PARTITION BY `j`.`OneId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + ) AS `t` + WHERE 2 < `t`.`row` +) AS `t0` ON `e`.`Id` = `t0`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_take(bool async) + { + await base.Select_many_over_skip_navigation_order_by_take(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneSkipSharedId` + FROM ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, `e0`.`OneSkipSharedId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`OneSkipSharedId` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityOneEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON `e`.`Id` = `t0`.`OneSkipSharedId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip_take(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip_take(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId` + FROM ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId`, ROW_NUMBER() OVER(PARTITION BY `j`.`OneId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + ) AS `t` + WHERE (2 < `t`.`row`) AND (`t`.`row` <= 5) +) AS `t0` ON `e`.`Id` = `t0`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_of_type(bool async) + { + await base.Select_many_over_skip_navigation_of_type(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `e0`.`ThreeSkipSharedId` + FROM `EntityRootEntityThree` AS `e0` + INNER JOIN ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` + WHERE `t`.`Discriminator` IN ('EntityBranch', 'EntityLeaf') +) AS `t0` ON `e`.`Id` = `t0`.`ThreeSkipSharedId` +"""); + } + + public override async Task Select_many_over_skip_navigation_cast(bool async) + { + await base.Select_many_over_skip_navigation_cast(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `j`.`EntityOneId` + FROM `JoinOneToBranch` AS `j` + INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + ) AS `t` ON `j`.`EntityBranchId` = `t`.`Id` +) AS `t0` ON `e`.`Id` = `t0`.`EntityOneId` +"""); + } + + public override async Task Select_skip_navigation(bool async) + { + await base.Select_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `t`.`Id`, `t`.`Name`, `t`.`LeftId`, `t`.`RightId` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`Name`, `j`.`LeftId`, `j`.`RightId` + FROM `JoinOneSelfPayload` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`LeftId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`RightId` +ORDER BY `e`.`Id`, `t`.`LeftId`, `t`.`RightId` +"""); + } + + public override async Task Select_skip_navigation_multiple(bool async) + { + await base.Select_skip_navigation_multiple(async); + + AssertSql( +""" +SELECT `e`.`Id`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId`, `t`.`TwoId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`SelfSkipSharedLeftId`, `t0`.`SelfSkipSharedRightId`, `t1`.`Key1`, `t1`.`Key2`, `t1`.`Key3`, `t1`.`Name`, `t1`.`TwoSkipSharedId`, `t1`.`CompositeKeySkipSharedKey1`, `t1`.`CompositeKeySkipSharedKey2`, `t1`.`CompositeKeySkipSharedKey3` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`ThreeId`, `j`.`TwoId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`TwoId` +LEFT JOIN ( + SELECT `e2`.`Id`, `e2`.`CollectionInverseId`, `e2`.`ExtraId`, `e2`.`Name`, `e2`.`ReferenceInverseId`, `e1`.`SelfSkipSharedLeftId`, `e1`.`SelfSkipSharedRightId` + FROM `EntityTwoEntityTwo` AS `e1` + INNER JOIN `EntityTwos` AS `e2` ON `e1`.`SelfSkipSharedLeftId` = `e2`.`Id` +) AS `t0` ON `e`.`Id` = `t0`.`SelfSkipSharedRightId` +LEFT JOIN ( + SELECT `e4`.`Key1`, `e4`.`Key2`, `e4`.`Key3`, `e4`.`Name`, `e3`.`TwoSkipSharedId`, `e3`.`CompositeKeySkipSharedKey1`, `e3`.`CompositeKeySkipSharedKey2`, `e3`.`CompositeKeySkipSharedKey3` + FROM `EntityCompositeKeyEntityTwo` AS `e3` + INNER JOIN `EntityCompositeKeys` AS `e4` ON ((`e3`.`CompositeKeySkipSharedKey1` = `e4`.`Key1`) AND (`e3`.`CompositeKeySkipSharedKey2` = `e4`.`Key2`)) AND (`e3`.`CompositeKeySkipSharedKey3` = `e4`.`Key3`) +) AS `t1` ON `e`.`Id` = `t1`.`TwoSkipSharedId` +ORDER BY `e`.`Id`, `t`.`ThreeId`, `t`.`TwoId`, `t`.`Id`, `t0`.`SelfSkipSharedLeftId`, `t0`.`SelfSkipSharedRightId`, `t0`.`Id`, `t1`.`TwoSkipSharedId`, `t1`.`CompositeKeySkipSharedKey1`, `t1`.`CompositeKeySkipSharedKey2`, `t1`.`CompositeKeySkipSharedKey3`, `t1`.`Key1`, `t1`.`Key2` +"""); + } + + public override async Task Select_skip_navigation_first_or_default(bool async) + { + await base.Select_skip_navigation_first_or_default(async); + + AssertSql( +""" +SELECT `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`Name` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `t`.`Key1`, `t`.`Key2`, `t`.`Key3`, `t`.`Name`, `t`.`ThreeId` + FROM ( + SELECT `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e0`.`Name`, `j`.`ThreeId`, ROW_NUMBER() OVER(PARTITION BY `j`.`ThreeId` ORDER BY `e0`.`Key1`, `e0`.`Key2`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`j`.`CompositeId1` = `e0`.`Key1`) AND (`j`.`CompositeId2` = `e0`.`Key2`)) AND (`j`.`CompositeId3` = `e0`.`Key3`) + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +ORDER BY `e`.`Id` +"""); + } + + public override async Task Include_skip_navigation(bool async) + { + await base.Include_skip_navigation(async); + + AssertSql( +$""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`Slumber`, `t0`.`IsGreen`, `t0`.`IsBrown`, `t0`.`Discriminator` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `e0`.`RootSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator` + FROM `EntityCompositeKeyEntityRoot` AS `e0` + INNER JOIN ( + SELECT `r`.`Id`, `r`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Slumber`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsBrown`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityRoot'")} AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Slumber`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsBrown`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityBranch'")} AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `Number`, `l0`.`Slumber`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `IsGreen`, `l0`.`IsBrown`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'EntityLeaf2'")} AS `Discriminator` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +"""); + } + + public override async Task Include_skip_navigation_then_reference(bool async) + { + await base.Include_skip_navigation_then_reference(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`EntityBranchId`, `t0`.`EntityOneId`, `t0`.`Id0`, `t0`.`Name0` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, `t`.`EntityBranchId`, `t`.`EntityOneId`, `t`.`Id` AS `Id0`, `t`.`Name` AS `Name0` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `Leaves` AS `l` ON `j`.`LeafId` = `l`.`Id` + LEFT JOIN ( + SELECT `j0`.`EntityBranchId`, `j0`.`EntityOneId`, `e0`.`Id`, `e0`.`Name` + FROM `JoinOneToBranch` AS `j0` + INNER JOIN `EntityOnes` AS `e0` ON `j0`.`EntityOneId` = `e0`.`Id` + ) AS `t` ON `l`.`Id` = `t`.`EntityBranchId` +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeId1`) AND (`e`.`Key2` = `t0`.`CompositeId2`)) AND (`e`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id`, `t0`.`EntityBranchId`, `t0`.`EntityOneId` +"""); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Payload`, `t0`.`Id`, `t0`.`Name`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId`, `t0`.`LeftId`, `t0`.`RightId`, `t0`.`Payload0`, `t0`.`Id1`, `t0`.`Name1` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `t`.`LeftId`, `t`.`RightId`, `t`.`Payload` AS `Payload0`, `t`.`Id` AS `Id1`, `t`.`Name` AS `Name1` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + LEFT JOIN ( + SELECT `j0`.`LeftId`, `j0`.`RightId`, `j0`.`Payload`, `e2`.`Id`, `e2`.`Name` + FROM `JoinOneSelfPayload` AS `j0` + INNER JOIN `EntityOnes` AS `e2` ON `j0`.`RightId` = `e2`.`Id` + ) AS `t` ON `e0`.`Id` = `t`.`LeftId` +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id`, `t0`.`Id0`, `t0`.`LeftId`, `t0`.`RightId` +"""); + } + + public override async Task Include_skip_navigation_and_reference(bool async) + { + await base.Include_skip_navigation_and_reference(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `e0`.`Id`, `t`.`OneSkipSharedId`, `t`.`TwoSkipSharedId`, `t`.`Id`, `t`.`Name`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +LEFT JOIN `EntityThrees` AS `e0` ON `e`.`Id` = `e0`.`ReferenceInverseId` +LEFT JOIN ( + SELECT `e1`.`OneSkipSharedId`, `e1`.`TwoSkipSharedId`, `e2`.`Id`, `e2`.`Name` + FROM `EntityOneEntityTwo` AS `e1` + INNER JOIN `EntityOnes` AS `e2` ON `e1`.`OneSkipSharedId` = `e2`.`Id` +) AS `t` ON `e`.`Id` = `t`.`TwoSkipSharedId` +ORDER BY `e`.`Id`, `e0`.`Id`, `t`.`OneSkipSharedId`, `t`.`TwoSkipSharedId` +"""); + } + + public override async Task Filtered_include_skip_navigation_where(bool async) + { + await base.Filtered_include_skip_navigation_where(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Payload`, `t`.`Id`, `t`.`Name` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by(bool async) + { + await base.Filtered_include_skip_navigation_order_by(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`ThreeId`, `t`.`TwoId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `j`.`ThreeId`, `j`.`TwoId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`Id`, `t`.`ThreeId` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t0`.`SelfSkipSharedLeftId`, `t0`.`SelfSkipSharedRightId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `t`.`SelfSkipSharedLeftId`, `t`.`SelfSkipSharedRightId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `e0`.`SelfSkipSharedLeftId`, `e0`.`SelfSkipSharedRightId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`SelfSkipSharedLeftId` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityTwoEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`SelfSkipSharedRightId` = `e1`.`Id` + ) AS `t` + WHERE 2 < `t`.`row` +) AS `t0` ON `e`.`Id` = `t0`.`SelfSkipSharedLeftId` +ORDER BY `e`.`Id`, `t0`.`SelfSkipSharedLeftId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_take(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`TwoSkipSharedId`, `t`.`CompositeKeySkipSharedKey1`, `t`.`CompositeKeySkipSharedKey2`, `t`.`CompositeKeySkipSharedKey3`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `e0`.`TwoSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`Id`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`ThreeId`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`ThreeId`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `j`.`Id`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `j`.`ThreeId`, `e0`.`Id` AS `Id0`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeId1`) AND (`e`.`Key2` = `t0`.`CompositeId2`)) AND (`e`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id0` +"""); + } + + public override async Task Filtered_then_include_skip_navigation_where(bool async) + { + await base.Filtered_then_include_skip_navigation_where(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Payload`, `t0`.`Id0`, `t0`.`Name0` +FROM ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `e`.`RootSkipSharedId`, `e`.`ThreeSkipSharedId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `t1`.`OneId`, `t1`.`ThreeId`, `t1`.`Payload`, `t1`.`Id` AS `Id0`, `t1`.`Name` AS `Name0` + FROM `EntityRootEntityThree` AS `e` + INNER JOIN `EntityThrees` AS `e0` ON `e`.`ThreeSkipSharedId` = `e0`.`Id` + LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e1`.`Id`, `e1`.`Name` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e1` ON `j`.`OneId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 + ) AS `t1` ON `e0`.`Id` = `t1`.`ThreeId` +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id`, `t0`.`OneId`, `t0`.`ThreeId` +"""); + } + + public override async Task Filtered_then_include_skip_navigation_order_by_skip_take(bool async) + { + await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator`, `t1`.`RootSkipSharedId`, `t1`.`CompositeKeySkipSharedKey1`, `t1`.`CompositeKeySkipSharedKey2`, `t1`.`CompositeKeySkipSharedKey3`, `t1`.`Key1`, `t1`.`Key2`, `t1`.`Key3`, `t1`.`Name`, `t1`.`Id`, `t1`.`CompositeId1`, `t1`.`CompositeId2`, `t1`.`CompositeId3`, `t1`.`ThreeId`, `t1`.`Id0`, `t1`.`CollectionInverseId`, `t1`.`Name0`, `t1`.`ReferenceInverseId` +FROM ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` +) AS `t` +LEFT JOIN ( + SELECT `e`.`RootSkipSharedId`, `e`.`CompositeKeySkipSharedKey1`, `e`.`CompositeKeySkipSharedKey2`, `e`.`CompositeKeySkipSharedKey3`, `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e0`.`Name`, `t0`.`Id`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`ThreeId`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId` + FROM `EntityCompositeKeyEntityRoot` AS `e` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`e`.`CompositeKeySkipSharedKey1` = `e0`.`Key1`) AND (`e`.`CompositeKeySkipSharedKey2` = `e0`.`Key2`)) AND (`e`.`CompositeKeySkipSharedKey3` = `e0`.`Key3`) + LEFT JOIN ( + SELECT `t2`.`Id`, `t2`.`CompositeId1`, `t2`.`CompositeId2`, `t2`.`CompositeId3`, `t2`.`ThreeId`, `t2`.`Id0`, `t2`.`CollectionInverseId`, `t2`.`Name`, `t2`.`ReferenceInverseId` + FROM ( + SELECT `j`.`Id`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `j`.`ThreeId`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e1` ON `j`.`ThreeId` = `e1`.`Id` + ) AS `t2` + WHERE (1 < `t2`.`row`) AND (`t2`.`row` <= 3) + ) AS `t0` ON ((`e0`.`Key1` = `t0`.`CompositeId1`) AND (`e0`.`Key2` = `t0`.`CompositeId2`)) AND (`e0`.`Key3` = `t0`.`CompositeId3`) +) AS `t1` ON `t`.`Id` = `t1`.`RootSkipSharedId` +ORDER BY `t`.`Id`, `t1`.`RootSkipSharedId`, `t1`.`CompositeKeySkipSharedKey1`, `t1`.`CompositeKeySkipSharedKey2`, `t1`.`CompositeKeySkipSharedKey3`, `t1`.`Key1`, `t1`.`Key2`, `t1`.`Key3`, `t1`.`CompositeId1`, `t1`.`CompositeId2`, `t1`.`CompositeId3`, `t1`.`Id0` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`Name`, `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId` +FROM `Leaves` AS `l` +LEFT JOIN ( + SELECT `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t`.`TwoSkipSharedId`, `t`.`CompositeKeySkipSharedKey1`, `t`.`CompositeKeySkipSharedKey2`, `t`.`CompositeKeySkipSharedKey3`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e` ON ((`j`.`CompositeId1` = `e`.`Key1`) AND (`j`.`CompositeId2` = `e`.`Key2`)) AND (`j`.`CompositeId3` = `e`.`Key3`) + LEFT JOIN ( + SELECT `e0`.`TwoSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` ON ((`e`.`Key1` = `t`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t`.`CompositeKeySkipSharedKey3`) + WHERE `e`.`Key1` < 5 +) AS `t0` ON `l`.`Id` = `t0`.`LeafId` +ORDER BY `l`.`Id`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`JoinOneToTwoExtraId`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`ExtraId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t1`.`ThreeId`, `t1`.`TwoId0`, `t1`.`Id0`, `t1`.`CollectionInverseId0`, `t1`.`Name0`, `t1`.`ReferenceInverseId0` +FROM `EntityOnes` AS `e` +LEFT JOIN LATERAL ( + SELECT `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t0`.`ThreeId`, `t0`.`TwoId` AS `TwoId0`, `t0`.`Id` AS `Id0`, `t0`.`CollectionInverseId` AS `CollectionInverseId0`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId` AS `ReferenceInverseId0` + FROM ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`OneId` + ORDER BY `e0`.`Id` + LIMIT 2 OFFSET 1 + ) AS `t` + LEFT JOIN ( + SELECT `j0`.`ThreeId`, `j0`.`TwoId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 + ) AS `t0` ON `t`.`Id` = `t0`.`TwoId` +) AS `t1` ON TRUE +ORDER BY `e`.`Id`, `t1`.`Id`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`ThreeId`, `t1`.`TwoId0` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`JoinOneToTwoExtraId`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`ExtraId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t1`.`ThreeId`, `t1`.`TwoId0`, `t1`.`Id0`, `t1`.`CollectionInverseId0`, `t1`.`Name0`, `t1`.`ReferenceInverseId0` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `t0`.`ThreeId`, `t0`.`TwoId` AS `TwoId0`, `t0`.`Id` AS `Id0`, `t0`.`CollectionInverseId` AS `CollectionInverseId0`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId` AS `ReferenceInverseId0` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + LEFT JOIN ( + SELECT `t`.`ThreeId`, `t`.`TwoId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `j0`.`ThreeId`, `j0`.`TwoId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j0`.`TwoId` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) + ) AS `t0` ON `e0`.`Id` = `t0`.`TwoId` + WHERE `e0`.`Id` < 10 +) AS `t1` ON `e`.`Id` = `t1`.`OneId` +ORDER BY `e`.`Id`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`Id`, `t1`.`TwoId0`, `t1`.`Id0` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined(bool async) + { + await base.Filter_include_on_skip_navigation_combined(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `t`.`Id1`, `t`.`CollectionInverseId0`, `t`.`ExtraId0`, `t`.`Name1`, `t`.`ReferenceInverseId0` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `e2`.`Id` AS `Id1`, `e2`.`CollectionInverseId` AS `CollectionInverseId0`, `e2`.`ExtraId` AS `ExtraId0`, `e2`.`Name` AS `Name1`, `e2`.`ReferenceInverseId` AS `ReferenceInverseId0` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + LEFT JOIN `EntityTwos` AS `e2` ON `e0`.`Id` = `e2`.`CollectionInverseId` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined_with_filtered_then_includes(bool async) + { + await base.Filter_include_on_skip_navigation_combined_with_filtered_then_includes(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t3`.`OneId`, `t3`.`ThreeId`, `t3`.`Payload`, `t3`.`Id`, `t3`.`Name`, `t3`.`OneId0`, `t3`.`TwoId`, `t3`.`JoinOneToTwoExtraId`, `t3`.`Id0`, `t3`.`CollectionInverseId`, `t3`.`ExtraId`, `t3`.`Name0`, `t3`.`ReferenceInverseId`, `t3`.`EntityBranchId`, `t3`.`EntityOneId`, `t3`.`Id1`, `t3`.`Name1`, `t3`.`Number`, `t3`.`IsGreen`, `t3`.`Discriminator` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name`, `t0`.`OneId` AS `OneId0`, `t0`.`TwoId`, `t0`.`JoinOneToTwoExtraId`, `t0`.`Id` AS `Id0`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId`, `t1`.`EntityBranchId`, `t1`.`EntityOneId`, `t1`.`Id` AS `Id1`, `t1`.`Name` AS `Name1`, `t1`.`Number`, `t1`.`IsGreen`, `t1`.`Discriminator` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN ( + SELECT `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `j0`.`OneId`, `j0`.`TwoId`, `j0`.`JoinOneToTwoExtraId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j0`.`OneId` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinOneToTwo` AS `j0` + INNER JOIN `EntityTwos` AS `e1` ON `j0`.`TwoId` = `e1`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) + ) AS `t0` ON `e0`.`Id` = `t0`.`OneId` + LEFT JOIN ( + SELECT `j1`.`EntityBranchId`, `j1`.`EntityOneId`, `t2`.`Id`, `t2`.`Name`, `t2`.`Number`, `t2`.`IsGreen`, `t2`.`Discriminator` + FROM `JoinOneToBranch` AS `j1` + INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + ) AS `t2` ON `j1`.`EntityBranchId` = `t2`.`Id` + WHERE `t2`.`Id` < 20 + ) AS `t1` ON `e0`.`Id` = `t1`.`EntityOneId` + WHERE `e0`.`Id` < 10 +) AS `t3` ON `e`.`Id` = `t3`.`ThreeId` +ORDER BY `e`.`Id`, `t3`.`OneId`, `t3`.`ThreeId`, `t3`.`Id`, `t3`.`OneId0`, `t3`.`Id0`, `t3`.`TwoId`, `t3`.`EntityBranchId`, `t3`.`EntityOneId` +"""); + } + + public override async Task Filtered_include_on_skip_navigation_then_filtered_include_on_navigation(bool async) + { + await base.Filtered_include_on_skip_navigation_then_filtered_include_on_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Payload`, `t0`.`Id`, `t0`.`Name`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name`, `t`.`Id` AS `Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `EntityTwos` AS `e1` + WHERE `e1`.`Id` < 5 + ) AS `t` ON `e0`.`Id` = `t`.`CollectionInverseId` + WHERE `e0`.`Id` > 15 +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_on_navigation_then_filtered_include_on_skip_navigation(bool async) + { + await base.Filtered_include_on_navigation_then_filtered_include_on_skip_navigation(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t0`.`ThreeId`, `t0`.`TwoId`, `t0`.`Id0`, `t0`.`CollectionInverseId0`, `t0`.`Name0`, `t0`.`ReferenceInverseId0` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `t`.`ThreeId`, `t`.`TwoId`, `t`.`Id` AS `Id0`, `t`.`CollectionInverseId` AS `CollectionInverseId0`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId` AS `ReferenceInverseId0` + FROM `EntityTwos` AS `e0` + LEFT JOIN ( + SELECT `j`.`ThreeId`, `j`.`TwoId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityThrees` AS `e1` ON `j`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 5 + ) AS `t` ON `e0`.`Id` = `t`.`TwoId` + WHERE `e0`.`Id` > 15 +) AS `t0` ON `e`.`Id` = `t0`.`CollectionInverseId` +ORDER BY `e`.`Id`, `t0`.`Id`, `t0`.`ThreeId`, `t0`.`TwoId` +"""); + } + + public override async Task Includes_accessed_via_different_path_are_merged(bool async) + { + await base.Includes_accessed_via_different_path_are_merged(async); + + AssertSql(); + } + + public override async Task Filtered_includes_accessed_via_different_path_are_merged(bool async) + { + await base.Filtered_includes_accessed_via_different_path_are_merged(async); + + AssertSql(); + } + + public override async Task Include_skip_navigation_split(bool async) + { + await base.Include_skip_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` +FROM `EntityCompositeKeys` AS `e` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +""", + // + """ +SELECT `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`Slumber`, `t0`.`IsGreen`, `t0`.`IsBrown`, `t0`.`Discriminator`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `e0`.`RootSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator` + FROM `EntityCompositeKeyEntityRoot` AS `e0` + INNER JOIN ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` + ) AS `t` ON `e0`.`RootSkipSharedId` = `t`.`Id` +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +"""); + } + + public override async Task Include_skip_navigation_then_reference_split(bool async) + { + await base.Include_skip_navigation_then_reference_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation_split(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` +FROM `EntityCompositeKeys` AS `e` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +""", + // + """ +SELECT `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `Leaves` AS `l` ON `j`.`LeafId` = `l`.`Id` +) AS `t` ON ((`e`.`Key1` = `t`.`CompositeId1`) AND (`e`.`Key2` = `t`.`CompositeId2`)) AND (`e`.`Key3` = `t`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Id` +""", + // + """ +SELECT `t0`.`EntityBranchId`, `t0`.`EntityOneId`, `t0`.`Id`, `t0`.`Name`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Id` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `l`.`Id` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `Leaves` AS `l` ON `j`.`LeafId` = `l`.`Id` +) AS `t` ON ((`e`.`Key1` = `t`.`CompositeId1`) AND (`e`.`Key2` = `t`.`CompositeId2`)) AND (`e`.`Key3` = `t`.`CompositeId3`) +INNER JOIN ( + SELECT `j0`.`EntityBranchId`, `j0`.`EntityOneId`, `e0`.`Id`, `e0`.`Name` + FROM `JoinOneToBranch` AS `j0` + INNER JOIN `EntityOnes` AS `e0` ON `j0`.`EntityOneId` = `e0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`EntityBranchId` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation_split(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`OneId`, `t`.`ThreeId`, `t`.`Payload`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id`, `t`.`Id0` +""", + // + """ +SELECT `t0`.`LeftId`, `t0`.`RightId`, `t0`.`Payload`, `t0`.`Id`, `t0`.`Name`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id`, `t`.`Id0` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `e0`.`Id`, `e1`.`Id` AS `Id0` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +INNER JOIN ( + SELECT `j0`.`LeftId`, `j0`.`RightId`, `j0`.`Payload`, `e2`.`Id`, `e2`.`Name` + FROM `JoinOneSelfPayload` AS `j0` + INNER JOIN `EntityOnes` AS `e2` ON `j0`.`RightId` = `e2`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`LeftId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Include_skip_navigation_and_reference_split(bool async) + { + await base.Include_skip_navigation_and_reference_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +LEFT JOIN `EntityThrees` AS `e0` ON `e`.`Id` = `e0`.`ReferenceInverseId` +ORDER BY `e`.`Id`, `e0`.`Id` +""", + // + """ +SELECT `t`.`OneSkipSharedId`, `t`.`TwoSkipSharedId`, `t`.`Id`, `t`.`Name`, `e`.`Id`, `e0`.`Id` +FROM `EntityTwos` AS `e` +LEFT JOIN `EntityThrees` AS `e0` ON `e`.`Id` = `e0`.`ReferenceInverseId` +INNER JOIN ( + SELECT `e1`.`OneSkipSharedId`, `e1`.`TwoSkipSharedId`, `e2`.`Id`, `e2`.`Name` + FROM `EntityOneEntityTwo` AS `e1` + INNER JOIN `EntityOnes` AS `e2` ON `e1`.`OneSkipSharedId` = `e2`.`Id` +) AS `t` ON `e`.`Id` = `t`.`TwoSkipSharedId` +ORDER BY `e`.`Id`, `e0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_split(bool async) + { + await base.Filtered_include_skip_navigation_where_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`OneId`, `t`.`ThreeId`, `t`.`Payload`, `t`.`Id`, `t`.`Name`, `e`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`ThreeId`, `t`.`TwoId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`ThreeId`, `j`.`TwoId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t0`.`SelfSkipSharedLeftId`, `t0`.`SelfSkipSharedRightId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `t`.`SelfSkipSharedLeftId`, `t`.`SelfSkipSharedRightId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `e0`.`SelfSkipSharedLeftId`, `e0`.`SelfSkipSharedRightId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`SelfSkipSharedLeftId` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityTwoEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`SelfSkipSharedRightId` = `e1`.`Id` + ) AS `t` + WHERE 2 < `t`.`row` +) AS `t0` ON `e`.`Id` = `t0`.`SelfSkipSharedLeftId` +ORDER BY `e`.`Id`, `t0`.`SelfSkipSharedLeftId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_split(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` +FROM `EntityCompositeKeys` AS `e` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +""", + // + """ +SELECT `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `t`.`TwoSkipSharedId`, `t`.`CompositeKeySkipSharedKey1`, `t`.`CompositeKeySkipSharedKey2`, `t`.`CompositeKeySkipSharedKey3`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `e0`.`TwoSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_split(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` +FROM `EntityCompositeKeys` AS `e` +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`ThreeId`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3` +FROM `EntityCompositeKeys` AS `e` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`ThreeId`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `j`.`Id`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `j`.`ThreeId`, `e0`.`Id` AS `Id0`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e0` ON `j`.`ThreeId` = `e0`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeId1`) AND (`e`.`Key2` = `t0`.`CompositeId2`)) AND (`e`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id0` +"""); + } + + public override async Task Filtered_then_include_skip_navigation_where_split(bool async) + { + await base.Filtered_then_include_skip_navigation_where_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator` +FROM ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` +) AS `t` +ORDER BY `t`.`Id` +""", + // + """ +SELECT `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `t`.`Id` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e`.`RootSkipSharedId`, `e`.`ThreeSkipSharedId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`Name`, `e0`.`ReferenceInverseId` + FROM `EntityRootEntityThree` AS `e` + INNER JOIN `EntityThrees` AS `e0` ON `e`.`ThreeSkipSharedId` = `e0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id` +""", + // + """ +SELECT `t1`.`OneId`, `t1`.`ThreeId`, `t1`.`Payload`, `t1`.`Id`, `t1`.`Name`, `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e`.`RootSkipSharedId`, `e`.`ThreeSkipSharedId`, `e0`.`Id` + FROM `EntityRootEntityThree` AS `e` + INNER JOIN `EntityThrees` AS `e0` ON `e`.`ThreeSkipSharedId` = `e0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e1`.`Id`, `e1`.`Name` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e1` ON `j`.`OneId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 +) AS `t1` ON `t0`.`Id` = `t1`.`ThreeId` +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`ThreeSkipSharedId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_then_include_skip_navigation_order_by_skip_take_split(bool async) + { + await base.Filtered_then_include_skip_navigation_order_by_skip_take_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`Slumber`, `t`.`IsGreen`, `t`.`IsBrown`, `t`.`Discriminator` +FROM ( + SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id`, `l0`.`Name`, NULL AS `Number`, `l0`.`Slumber`, NULL AS `IsGreen`, `l0`.`IsBrown`, 'EntityLeaf2' AS `Discriminator` + FROM `Leaf2s` AS `l0` +) AS `t` +ORDER BY `t`.`Id` +""", + // + """ +SELECT `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`Name`, `t`.`Id` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e`.`RootSkipSharedId`, `e`.`CompositeKeySkipSharedKey1`, `e`.`CompositeKeySkipSharedKey2`, `e`.`CompositeKeySkipSharedKey3`, `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3`, `e0`.`Name` + FROM `EntityCompositeKeyEntityRoot` AS `e` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`e`.`CompositeKeySkipSharedKey1` = `e0`.`Key1`) AND (`e`.`CompositeKeySkipSharedKey2` = `e0`.`Key2`)) AND (`e`.`CompositeKeySkipSharedKey3` = `e0`.`Key3`) +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3` +""", + // + """ +SELECT `t1`.`Id`, `t1`.`CompositeId1`, `t1`.`CompositeId2`, `t1`.`CompositeId3`, `t1`.`ThreeId`, `t1`.`Id0`, `t1`.`CollectionInverseId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3` +FROM ( + SELECT `r`.`Id` + FROM `Roots` AS `r` + UNION ALL + SELECT `b`.`Id` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id` + FROM `Leaves` AS `l` + UNION ALL + SELECT `l0`.`Id` + FROM `Leaf2s` AS `l0` +) AS `t` +INNER JOIN ( + SELECT `e`.`RootSkipSharedId`, `e`.`CompositeKeySkipSharedKey1`, `e`.`CompositeKeySkipSharedKey2`, `e`.`CompositeKeySkipSharedKey3`, `e0`.`Key1`, `e0`.`Key2`, `e0`.`Key3` + FROM `EntityCompositeKeyEntityRoot` AS `e` + INNER JOIN `EntityCompositeKeys` AS `e0` ON ((`e`.`CompositeKeySkipSharedKey1` = `e0`.`Key1`) AND (`e`.`CompositeKeySkipSharedKey2` = `e0`.`Key2`)) AND (`e`.`CompositeKeySkipSharedKey3` = `e0`.`Key3`) +) AS `t0` ON `t`.`Id` = `t0`.`RootSkipSharedId` +INNER JOIN ( + SELECT `t2`.`Id`, `t2`.`CompositeId1`, `t2`.`CompositeId2`, `t2`.`CompositeId3`, `t2`.`ThreeId`, `t2`.`Id0`, `t2`.`CollectionInverseId`, `t2`.`Name`, `t2`.`ReferenceInverseId` + FROM ( + SELECT `j`.`Id`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `j`.`ThreeId`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinThreeToCompositeKeyFull` AS `j` + INNER JOIN `EntityThrees` AS `e1` ON `j`.`ThreeId` = `e1`.`Id` + ) AS `t2` + WHERE (1 < `t2`.`row`) AND (`t2`.`row` <= 3) +) AS `t1` ON ((`t0`.`Key1` = `t1`.`CompositeId1`) AND (`t0`.`Key2` = `t1`.`CompositeId2`)) AND (`t0`.`Key3` = `t1`.`CompositeId3`) +ORDER BY `t`.`Id`, `t0`.`RootSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t1`.`CompositeId1`, `t1`.`CompositeId2`, `t1`.`CompositeId3`, `t1`.`Id0` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_split(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_split(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen` +FROM `Leaves` AS `l` +ORDER BY `l`.`Id` +""", + // + """ +SELECT `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Key1`, `t`.`Key2`, `t`.`Key3`, `t`.`Name`, `l`.`Id` +FROM `Leaves` AS `l` +INNER JOIN ( + SELECT `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e` ON ((`j`.`CompositeId1` = `e`.`Key1`) AND (`j`.`CompositeId2` = `e`.`Key2`)) AND (`j`.`CompositeId3` = `e`.`Key3`) + WHERE `e`.`Key1` < 5 +) AS `t` ON `l`.`Id` = `t`.`LeafId` +ORDER BY `l`.`Id`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Key1`, `t`.`Key2`, `t`.`Key3` +""", + // + """ +SELECT `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `l`.`Id`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Key1`, `t`.`Key2`, `t`.`Key3` +FROM `Leaves` AS `l` +INNER JOIN ( + SELECT `j`.`LeafId`, `j`.`CompositeId1`, `j`.`CompositeId2`, `j`.`CompositeId3`, `e`.`Key1`, `e`.`Key2`, `e`.`Key3` + FROM `JoinCompositeKeyToLeaf` AS `j` + INNER JOIN `EntityCompositeKeys` AS `e` ON ((`j`.`CompositeId1` = `e`.`Key1`) AND (`j`.`CompositeId2` = `e`.`Key2`)) AND (`j`.`CompositeId3` = `e`.`Key3`) + WHERE `e`.`Key1` < 5 +) AS `t` ON `l`.`Id` = `t`.`LeafId` +INNER JOIN ( + SELECT `e0`.`TwoSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` +) AS `t0` ON ((`t`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`t`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`t`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `l`.`Id`, `t`.`LeafId`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`Key1`, `t`.`Key2`, `t`.`Key3` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_split(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t0`.`OneId`, `t0`.`TwoId`, `t0`.`JoinOneToTwoExtraId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j`.`OneId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON `e`.`Id` = `t0`.`OneId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`Id`, `t0`.`TwoId` +""", + // + """ +SELECT `t1`.`ThreeId`, `t1`.`TwoId`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `e`.`Id`, `t0`.`OneId`, `t0`.`TwoId`, `t0`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `t`.`OneId`, `t`.`TwoId`, `t`.`Id` + FROM ( + SELECT `j`.`OneId`, `j`.`TwoId`, `e0`.`Id`, ROW_NUMBER() OVER(PARTITION BY `j`.`OneId` ORDER BY `e0`.`Id`) AS `row` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON `e`.`Id` = `t0`.`OneId` +INNER JOIN ( + SELECT `j0`.`ThreeId`, `j0`.`TwoId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 +) AS `t1` ON `t0`.`Id` = `t1`.`TwoId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`Id`, `t0`.`TwoId` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take_split(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`OneId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id` +""", + // + """ +SELECT `t0`.`ThreeId`, `t0`.`TwoId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `e0`.`Id` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`OneId` +INNER JOIN ( + SELECT `t1`.`ThreeId`, `t1`.`TwoId`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`Name`, `t1`.`ReferenceInverseId` + FROM ( + SELECT `j0`.`ThreeId`, `j0`.`TwoId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j0`.`TwoId` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + ) AS `t1` + WHERE (1 < `t1`.`row`) AND (`t1`.`row` <= 3) +) AS `t0` ON `t`.`Id` = `t0`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t0`.`TwoId`, `t0`.`Id` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined_split(bool async) + { + await base.Filter_include_on_skip_navigation_combined_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityTwos` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +""", + // + """ +SELECT `e2`.`Id`, `e2`.`CollectionInverseId`, `e2`.`ExtraId`, `e2`.`Name`, `e2`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +FROM `EntityTwos` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `e0`.`Id`, `e1`.`Id` AS `Id0` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`TwoId` +INNER JOIN `EntityTwos` AS `e2` ON `t`.`Id` = `e2`.`CollectionInverseId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined_with_filtered_then_includes_split(bool async) + { + await base.Filter_include_on_skip_navigation_combined_with_filtered_then_includes_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`OneId`, `t`.`ThreeId`, `t`.`Payload`, `t`.`Id`, `t`.`Name`, `e`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +""", + // + """ +SELECT `t0`.`OneId`, `t0`.`TwoId`, `t0`.`JoinOneToTwoExtraId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `e0`.`Id` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +INNER JOIN ( + SELECT `t1`.`OneId`, `t1`.`TwoId`, `t1`.`JoinOneToTwoExtraId`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`ExtraId`, `t1`.`Name`, `t1`.`ReferenceInverseId` + FROM ( + SELECT `j0`.`OneId`, `j0`.`TwoId`, `j0`.`JoinOneToTwoExtraId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `j0`.`OneId` ORDER BY `e1`.`Id`) AS `row` + FROM `JoinOneToTwo` AS `j0` + INNER JOIN `EntityTwos` AS `e1` ON `j0`.`TwoId` = `e1`.`Id` + ) AS `t1` + WHERE (1 < `t1`.`row`) AND (`t1`.`row` <= 3) +) AS `t0` ON `t`.`Id` = `t0`.`OneId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id`, `t0`.`OneId`, `t0`.`Id` +""", + // + """ +SELECT `t0`.`EntityBranchId`, `t0`.`EntityOneId`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `e0`.`Id` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +INNER JOIN ( + SELECT `j0`.`EntityBranchId`, `j0`.`EntityOneId`, `t1`.`Id`, `t1`.`Name`, `t1`.`Number`, `t1`.`IsGreen`, `t1`.`Discriminator` + FROM `JoinOneToBranch` AS `j0` + INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` + ) AS `t1` ON `j0`.`EntityBranchId` = `t1`.`Id` + WHERE `t1`.`Id` < 20 +) AS `t0` ON `t`.`Id` = `t0`.`EntityOneId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +"""); + } + + public override async Task Filtered_include_on_skip_navigation_then_filtered_include_on_navigation_split(bool async) + { + await base.Filtered_include_on_skip_navigation_then_filtered_include_on_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`OneId`, `t`.`ThreeId`, `t`.`Payload`, `t`.`Id`, `t`.`Name`, `e`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` > 15 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +FROM `EntityThrees` AS `e` +INNER JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `e0`.`Id` + FROM `JoinOneToThreePayloadFull` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` > 15 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +INNER JOIN ( + SELECT `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `EntityTwos` AS `e1` + WHERE `e1`.`Id` < 5 +) AS `t0` ON `t`.`Id` = `t0`.`CollectionInverseId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Id` +"""); + } + + public override async Task Filtered_include_on_navigation_then_filtered_include_on_skip_navigation_split(bool async) + { + await base.Filtered_include_on_navigation_then_filtered_include_on_skip_navigation_split(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +ORDER BY `e`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `e`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` + FROM `EntityTwos` AS `e0` + WHERE `e0`.`Id` > 15 +) AS `t` ON `e`.`Id` = `t`.`CollectionInverseId` +ORDER BY `e`.`Id`, `t`.`Id` +""", + // + """ +SELECT `t0`.`ThreeId`, `t0`.`TwoId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId`, `e`.`Id`, `t`.`Id` +FROM `EntityOnes` AS `e` +INNER JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId` + FROM `EntityTwos` AS `e0` + WHERE `e0`.`Id` > 15 +) AS `t` ON `e`.`Id` = `t`.`CollectionInverseId` +INNER JOIN ( + SELECT `j`.`ThreeId`, `j`.`TwoId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `JoinTwoToThree` AS `j` + INNER JOIN `EntityThrees` AS `e1` ON `j`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 5 +) AS `t0` ON `t`.`Id` = `t0`.`TwoId` +ORDER BY `e`.`Id`, `t`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_inverse_works_for_tracking_query(bool async) + { + await base.Include_skip_navigation_then_include_inverse_works_for_tracking_query(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Payload`, `t0`.`Id`, `t0`.`Name`, `t0`.`OneId0`, `t0`.`ThreeId0`, `t0`.`Payload0`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`Name0`, `t0`.`ReferenceInverseId` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name`, `t`.`OneId` AS `OneId0`, `t`.`ThreeId` AS `ThreeId0`, `t`.`Payload` AS `Payload0`, `t`.`Id` AS `Id0`, `t`.`CollectionInverseId`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN ( + SELECT `j0`.`OneId`, `j0`.`ThreeId`, `j0`.`Payload`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `JoinOneToThreePayloadFullShared` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + ) AS `t` ON `e0`.`Id` = `t`.`OneId` +) AS `t0` ON `e`.`Id` = `t0`.`ThreeId` +ORDER BY `e`.`Id`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id`, `t0`.`OneId0`, `t0`.`ThreeId0` +"""); + } + + public override async Task Throws_when_different_filtered_include(bool async) + { + await base.Throws_when_different_filtered_include(async); + + AssertSql(); + } + + public override async Task Throws_when_different_filtered_then_include(bool async) + { + await base.Throws_when_different_filtered_then_include(async); + + AssertSql(); + } + + public override async Task Throws_when_different_filtered_then_include_via_different_paths(bool async) + { + await base.Throws_when_different_filtered_then_include_via_different_paths(async); + + AssertSql(); + } + + public override async Task Select_many_over_skip_navigation_where_non_equality(bool async) + { + await base.Select_many_over_skip_navigation_where_non_equality(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `EntityOnes` AS `e` +LEFT JOIN ( + SELECT `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId`, `j`.`OneId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` +) AS `t` ON (`e`.`Id` = `t`.`OneId`) AND (`e`.`Id` <> `t`.`Id`) +"""); + } + + public override async Task Contains_on_skip_collection_navigation(bool async) + { + await base.Contains_on_skip_collection_navigation(async); + + AssertSql( +""" +@__entity_equality_two_0_Id='1' (Nullable = true) + +SELECT `e`.`Id`, `e`.`Name` +FROM `EntityOnes` AS `e` +WHERE EXISTS ( + SELECT 1 + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE (`e`.`Id` = `j`.`OneId`) AND (`e0`.`Id` = @__entity_equality_two_0_Id)) +"""); + } + + public override async Task GetType_in_hierarchy_in_base_type(bool async) + { + await base.GetType_in_hierarchy_in_base_type(async); + + AssertSql( +""" +SELECT `r`.`Id`, `r`.`Name`, NULL AS `Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityRoot' AS `Discriminator` +FROM `Roots` AS `r` +"""); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type(async); + + AssertSql( +""" +SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `Slumber`, NULL AS `IsGreen`, NULL AS `IsBrown`, 'EntityBranch' AS `Discriminator` +FROM `Branches` AS `b` +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type(async); + + AssertSql( +""" +SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, NULL AS `Slumber`, `l`.`IsGreen`, NULL AS `IsBrown`, 'EntityLeaf' AS `Discriminator` +FROM `Leaves` AS `l` +"""); + } + + public override async Task GetType_in_hierarchy_in_querying_base_type(bool async) + { + await base.GetType_in_hierarchy_in_querying_base_type(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`Number`, NULL AS `IsGreen`, 'EntityBranch' AS `Discriminator` + FROM `Branches` AS `b` + UNION ALL + SELECT `l`.`Id`, `l`.`Name`, `l`.`Number`, `l`.`IsGreen`, 'EntityLeaf' AS `Discriminator` + FROM `Leaves` AS `l` +) AS `t` +WHERE FALSE +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_EF_Property(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_EF_Property(async); + + AssertSql( +""" +SELECT `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `e`.`Name`, `t0`.`TwoSkipSharedId`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `EntityCompositeKeys` AS `e` +LEFT JOIN ( + SELECT `t`.`TwoSkipSharedId`, `t`.`CompositeKeySkipSharedKey1`, `t`.`CompositeKeySkipSharedKey2`, `t`.`CompositeKeySkipSharedKey3`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `e0`.`TwoSkipSharedId`, `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name`, `e1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `e0`.`CompositeKeySkipSharedKey1`, `e0`.`CompositeKeySkipSharedKey2`, `e0`.`CompositeKeySkipSharedKey3` ORDER BY `e1`.`Id`) AS `row` + FROM `EntityCompositeKeyEntityTwo` AS `e0` + INNER JOIN `EntityTwos` AS `e1` ON `e0`.`TwoSkipSharedId` = `e1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON ((`e`.`Key1` = `t0`.`CompositeKeySkipSharedKey1`) AND (`e`.`Key2` = `t0`.`CompositeKeySkipSharedKey2`)) AND (`e`.`Key3` = `t0`.`CompositeKeySkipSharedKey3`) +ORDER BY `e`.`Key1`, `e`.`Key2`, `e`.`Key3`, `t0`.`CompositeKeySkipSharedKey1`, `t0`.`CompositeKeySkipSharedKey2`, `t0`.`CompositeKeySkipSharedKey3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property( + bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`Name`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`JoinOneToTwoExtraId`, `t1`.`Id`, `t1`.`CollectionInverseId`, `t1`.`ExtraId`, `t1`.`Name`, `t1`.`ReferenceInverseId`, `t1`.`ThreeId`, `t1`.`TwoId0`, `t1`.`Id0`, `t1`.`CollectionInverseId0`, `t1`.`Name0`, `t1`.`ReferenceInverseId0` +FROM `EntityOnes` AS `e` +LEFT JOIN LATERAL ( + SELECT `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t0`.`ThreeId`, `t0`.`TwoId` AS `TwoId0`, `t0`.`Id` AS `Id0`, `t0`.`CollectionInverseId` AS `CollectionInverseId0`, `t0`.`Name` AS `Name0`, `t0`.`ReferenceInverseId` AS `ReferenceInverseId0` + FROM ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`CollectionInverseId`, `e0`.`ExtraId`, `e0`.`Name`, `e0`.`ReferenceInverseId` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityTwos` AS `e0` ON `j`.`TwoId` = `e0`.`Id` + WHERE `e`.`Id` = `j`.`OneId` + ORDER BY `e0`.`Id` + LIMIT 2 OFFSET 1 + ) AS `t` + LEFT JOIN ( + SELECT `j0`.`ThreeId`, `j0`.`TwoId`, `e1`.`Id`, `e1`.`CollectionInverseId`, `e1`.`Name`, `e1`.`ReferenceInverseId` + FROM `JoinTwoToThree` AS `j0` + INNER JOIN `EntityThrees` AS `e1` ON `j0`.`ThreeId` = `e1`.`Id` + WHERE `e1`.`Id` < 10 + ) AS `t0` ON `t`.`Id` = `t0`.`TwoId` +) AS `t1` ON TRUE +ORDER BY `e`.`Id`, `t1`.`Id`, `t1`.`OneId`, `t1`.`TwoId`, `t1`.`ThreeId`, `t1`.`TwoId0` +"""); + } + + public override async Task Skip_navigation_all_unidirectional(bool async) + { + await base.Skip_navigation_all_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE NOT EXISTS ( + SELECT 1 + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` + WHERE (`u`.`Id` = `u0`.`OneId`) AND NOT (`u1`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_any_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_any_with_predicate_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE EXISTS ( + SELECT 1 + FROM `UnidirectionalEntityOneUnidirectionalEntityTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoSkipSharedId` = `u1`.`Id` + WHERE (`u`.`Id` = `u0`.`UnidirectionalEntityOneId`) AND (`u1`.`Name` LIKE '%B%')) +"""); + } + + public override async Task Skip_navigation_contains_unidirectional(bool async) + { + await base.Skip_navigation_contains_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE EXISTS ( + SELECT 1 + FROM `UnidirectionalJoinOneToThreePayloadFullShared` AS `u0` + INNER JOIN `UnidirectionalEntityThrees` AS `u1` ON `u0`.`ThreeId` = `u1`.`Id` + WHERE (`u`.`Id` = `u0`.`OneId`) AND (`u1`.`Id` = 1)) +"""); + } + + public override async Task Skip_navigation_count_without_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_without_predicate_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE ( + SELECT COUNT(*) + FROM `UnidirectionalJoinOneSelfPayload` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`LeftId` = `u1`.`Id` + WHERE `u`.`Id` = `u0`.`RightId`) > 0 +"""); + } + + public override async Task Skip_navigation_count_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_with_predicate_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +ORDER BY ( + SELECT COUNT(*) + FROM `UnidirectionalJoinOneToBranch` AS `u0` + INNER JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u1`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u1` + UNION ALL + SELECT `u2`.`Id`, `u2`.`Name`, `u2`.`Number`, `u2`.`IsGreen`, 'UnidirectionalEntityLeaf' AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u2` + ) AS `t` ON `u0`.`UnidirectionalEntityBranchId` = `t`.`Id` + WHERE (`u`.`Id` = `u0`.`UnidirectionalEntityOneId`) AND (`t`.`Name` IS NOT NULL AND (`t`.`Name` LIKE 'L%'))), `u`.`Id` +"""); + } + + public override async Task Skip_navigation_select_subquery_average_unidirectional(bool async) + { + await base.Skip_navigation_select_subquery_average_unidirectional(async); + + AssertSql( +$""" +SELECT ( + SELECT AVG({MySqlTestHelpers.CastAsDouble(@"`u1`.`Key1`")}) + FROM `UnidirectionalJoinCompositeKeyToLeaf` AS `u0` + INNER JOIN `UnidirectionalEntityCompositeKeys` AS `u1` ON ((`u0`.`CompositeId1` = `u1`.`Key1`) AND (`u0`.`CompositeId2` = `u1`.`Key2`)) AND (`u0`.`CompositeId3` = `u1`.`Key3`) + WHERE `u`.`Id` = `u0`.`LeafId`) +FROM `UnidirectionalLeaves` AS `u` +"""); + } + + public override async Task Skip_navigation_order_by_reverse_first_or_default_unidirectional(bool async) + { + await base.Skip_navigation_order_by_reverse_first_or_default_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityThrees` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`ThreeId` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`ThreeId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`ThreeId` ORDER BY `u1`.`Id` DESC) AS `row` + FROM `UnidirectionalJoinTwoToThree` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 1 +) AS `t0` ON `u`.`Id` = `t0`.`ThreeId` +"""); + } + + public override async Task Skip_navigation_of_type_unidirectional(bool async) + { + await base.Skip_navigation_of_type_unidirectional(async); + + AssertSql( +$""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator`, `t0`.`RootSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `u0`.`RootSkipSharedId`, `u0`.`UnidirectionalEntityCompositeKeyKey1`, `u0`.`UnidirectionalEntityCompositeKeyKey2`, `u0`.`UnidirectionalEntityCompositeKeyKey3` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot` AS `u0` + INNER JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'UnidirectionalEntityRoot' AS `Discriminator` + FROM `UnidirectionalRoots` AS `u1` + UNION ALL + SELECT `u2`.`Id`, `u2`.`Name`, `u2`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u2` + UNION ALL + SELECT `u3`.`Id`, `u3`.`Name`, `u3`.`Number`, `u3`.`IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'UnidirectionalEntityLeaf'")} AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u3` + ) AS `t` ON `u0`.`RootSkipSharedId` = `t`.`Id` + WHERE `t`.`Discriminator` = 'UnidirectionalEntityLeaf' +) AS `t0` ON ((`u`.`Key1` = `t0`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u`.`Key2` = `t0`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u`.`Key3` = `t0`.`UnidirectionalEntityCompositeKeyKey3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`RootSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +"""); + } + + public override async Task Join_with_skip_navigation_unidirectional(bool async) + { + await base.Join_with_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`ExtraId`, `u`.`Name`, `u`.`ReferenceInverseId`, `u0`.`Id`, `u0`.`CollectionInverseId`, `u0`.`ExtraId`, `u0`.`Name`, `u0`.`ReferenceInverseId` +FROM `UnidirectionalEntityTwos` AS `u` +INNER JOIN `UnidirectionalEntityTwos` AS `u0` ON `u`.`Id` = ( + SELECT `u2`.`Id` + FROM `UnidirectionalEntityTwoUnidirectionalEntityTwo` AS `u1` + INNER JOIN `UnidirectionalEntityTwos` AS `u2` ON `u1`.`SelfSkipSharedRightId` = `u2`.`Id` + WHERE `u0`.`Id` = `u1`.`UnidirectionalEntityTwoId` + ORDER BY `u2`.`Id` + LIMIT 1) +"""); + } + + public override async Task Left_join_with_skip_navigation_unidirectional(bool async) + { + await base.Left_join_with_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `u0`.`Key1`, `u0`.`Key2`, `u0`.`Key3`, `u0`.`Name` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN `UnidirectionalEntityCompositeKeys` AS `u0` ON ( + SELECT `u2`.`Id` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo` AS `u1` + INNER JOIN `UnidirectionalEntityTwos` AS `u2` ON `u1`.`TwoSkipSharedId` = `u2`.`Id` + WHERE ((`u`.`Key1` = `u1`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u`.`Key2` = `u1`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u`.`Key3` = `u1`.`UnidirectionalEntityCompositeKeyKey3`) + ORDER BY `u2`.`Id` + LIMIT 1) = ( + SELECT `u4`.`Id` + FROM `UnidirectionalJoinThreeToCompositeKeyFull` AS `u3` + INNER JOIN `UnidirectionalEntityThrees` AS `u4` ON `u3`.`ThreeId` = `u4`.`Id` + WHERE ((`u0`.`Key1` = `u3`.`CompositeId1`) AND (`u0`.`Key2` = `u3`.`CompositeId2`)) AND (`u0`.`Key3` = `u3`.`CompositeId3`) + ORDER BY `u4`.`Id` + LIMIT 1) +ORDER BY `u`.`Key1`, `u0`.`Key1`, `u`.`Key2`, `u0`.`Key2` +"""); + } + + public override async Task Select_many_over_skip_navigation_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM ( + SELECT `u1`.`Id` + FROM `UnidirectionalRoots` AS `u1` + UNION ALL + SELECT `u2`.`Id` + FROM `UnidirectionalBranches` AS `u2` + UNION ALL + SELECT `u3`.`Id` + FROM `UnidirectionalLeaves` AS `u3` +) AS `t` +INNER JOIN ( + SELECT `u0`.`Id`, `u0`.`CollectionInverseId`, `u0`.`Name`, `u0`.`ReferenceInverseId`, `u`.`UnidirectionalEntityRootId` + FROM `UnidirectionalEntityRootUnidirectionalEntityThree` AS `u` + INNER JOIN `UnidirectionalEntityThrees` AS `u0` ON `u`.`ThreeSkipSharedId` = `u0`.`Id` +) AS `t0` ON `t`.`Id` = `t0`.`UnidirectionalEntityRootId` +"""); + } + + public override async Task Select_many_over_skip_navigation_where_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_unidirectional(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `UnidirectionalEntityOnes` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`OneId` + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` +) AS `t` ON `u`.`Id` = `t`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityOnes` AS `u` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`UnidirectionalEntityOneId` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`UnidirectionalEntityOneId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`UnidirectionalEntityOneId` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalEntityOneUnidirectionalEntityTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoSkipSharedId` = `u1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON `u`.`Id` = `t0`.`UnidirectionalEntityOneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityOnes` AS `u` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId`, `t`.`OneId` + FROM ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`OneId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`OneId` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalJoinOneToThreePayloadFullShared` AS `u0` + INNER JOIN `UnidirectionalEntityThrees` AS `u1` ON `u0`.`ThreeId` = `u1`.`Id` + ) AS `t` + WHERE (2 < `t`.`row`) AND (`t`.`row` <= 5) +) AS `t0` ON `u`.`Id` = `t0`.`OneId` +"""); + } + + public override async Task Select_many_over_skip_navigation_cast_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_cast_unidirectional(async); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator` +FROM `UnidirectionalEntityOnes` AS `u` +INNER JOIN ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator`, `u0`.`UnidirectionalEntityOneId` + FROM `UnidirectionalJoinOneToBranch` AS `u0` + INNER JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u1`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u1` + UNION ALL + SELECT `u2`.`Id`, `u2`.`Name`, `u2`.`Number`, `u2`.`IsGreen`, 'UnidirectionalEntityLeaf' AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u2` + ) AS `t` ON `u0`.`UnidirectionalEntityBranchId` = `t`.`Id` +) AS `t0` ON `u`.`Id` = `t0`.`UnidirectionalEntityOneId` +"""); + } + + public override async Task Select_skip_navigation_unidirectional(bool async) + { + await base.Select_skip_navigation_unidirectional(async); + AssertSql( +""" +SELECT `u`.`Id`, `t`.`Id`, `t`.`Name`, `t`.`LeftId`, `t`.`RightId` +FROM `UnidirectionalEntityOnes` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, `u0`.`LeftId`, `u0`.`RightId` + FROM `UnidirectionalJoinOneSelfPayload` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`LeftId` = `u1`.`Id` +) AS `t` ON `u`.`Id` = `t`.`RightId` +ORDER BY `u`.`Id`, `t`.`LeftId`, `t`.`RightId` +"""); + } + + public override async Task Include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_unidirectional(async); + + AssertSql( +$""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `t0`.`RootSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`Discriminator` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `u0`.`RootSkipSharedId`, `u0`.`UnidirectionalEntityCompositeKeyKey1`, `u0`.`UnidirectionalEntityCompositeKeyKey2`, `u0`.`UnidirectionalEntityCompositeKeyKey3`, `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot` AS `u0` + INNER JOIN ( + SELECT `u1`.`Id`, `u1`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'UnidirectionalEntityRoot' AS `Discriminator` + FROM `UnidirectionalRoots` AS `u1` + UNION ALL + SELECT `u2`.`Id`, `u2`.`Name`, `u2`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u2` + UNION ALL + SELECT `u3`.`Id`, `u3`.`Name`, `u3`.`Number`, `u3`.`IsGreen`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'UnidirectionalEntityLeaf'")} AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u3` + ) AS `t` ON `u0`.`RootSkipSharedId` = `t`.`Id` +) AS `t0` ON ((`u`.`Key1` = `t0`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u`.`Key2` = `t0`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u`.`Key3` = `t0`.`UnidirectionalEntityCompositeKeyKey3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`RootSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +"""); + } + + public override async Task Include_skip_navigation_then_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_then_reference_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`ExtraId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId`, `t`.`UnidirectionalJoinOneToTwoExtraId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId` +FROM `UnidirectionalEntityTwos` AS `u` +LEFT JOIN ( + SELECT `u0`.`OneId`, `u0`.`TwoId`, `u0`.`UnidirectionalJoinOneToTwoExtraId`, `u1`.`Id`, `u1`.`Name`, `u2`.`Id` AS `Id0`, `u2`.`CollectionInverseId`, `u2`.`ExtraId`, `u2`.`Name` AS `Name0`, `u2`.`ReferenceInverseId` + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`OneId` = `u1`.`Id` + LEFT JOIN `UnidirectionalEntityTwos` AS `u2` ON `u1`.`Id` = `u2`.`ReferenceInverseId` +) AS `t` ON `u`.`Id` = `t`.`TwoId` +ORDER BY `u`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id` +"""); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id`, `t0`.`Name`, `t0`.`Number`, `t0`.`IsGreen`, `t0`.`UnidirectionalEntityBranchId`, `t0`.`UnidirectionalEntityOneId`, `t0`.`Id0`, `t0`.`Name0` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `u0`.`LeafId`, `u0`.`CompositeId1`, `u0`.`CompositeId2`, `u0`.`CompositeId3`, `u1`.`Id`, `u1`.`Name`, `u1`.`Number`, `u1`.`IsGreen`, `t`.`UnidirectionalEntityBranchId`, `t`.`UnidirectionalEntityOneId`, `t`.`Id` AS `Id0`, `t`.`Name` AS `Name0` + FROM `UnidirectionalJoinCompositeKeyToLeaf` AS `u0` + INNER JOIN `UnidirectionalLeaves` AS `u1` ON `u0`.`LeafId` = `u1`.`Id` + LEFT JOIN ( + SELECT `u2`.`UnidirectionalEntityBranchId`, `u2`.`UnidirectionalEntityOneId`, `u3`.`Id`, `u3`.`Name` + FROM `UnidirectionalJoinOneToBranch` AS `u2` + INNER JOIN `UnidirectionalEntityOnes` AS `u3` ON `u2`.`UnidirectionalEntityOneId` = `u3`.`Id` + ) AS `t` ON `u1`.`Id` = `t`.`UnidirectionalEntityBranchId` +) AS `t0` ON ((`u`.`Key1` = `t0`.`CompositeId1`) AND (`u`.`Key2` = `t0`.`CompositeId2`)) AND (`u`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id`, `t0`.`UnidirectionalEntityBranchId`, `t0`.`UnidirectionalEntityOneId` +"""); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Payload`, `t0`.`Id`, `t0`.`Name`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId`, `t0`.`LeftId`, `t0`.`RightId`, `t0`.`Payload0`, `t0`.`Id1`, `t0`.`Name1` +FROM `UnidirectionalEntityThrees` AS `u` +LEFT JOIN ( + SELECT `u0`.`OneId`, `u0`.`ThreeId`, `u0`.`Payload`, `u1`.`Id`, `u1`.`Name`, `u2`.`Id` AS `Id0`, `u2`.`CollectionInverseId`, `u2`.`ExtraId`, `u2`.`Name` AS `Name0`, `u2`.`ReferenceInverseId`, `t`.`LeftId`, `t`.`RightId`, `t`.`Payload` AS `Payload0`, `t`.`Id` AS `Id1`, `t`.`Name` AS `Name1` + FROM `UnidirectionalJoinOneToThreePayloadFull` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`OneId` = `u1`.`Id` + LEFT JOIN `UnidirectionalEntityTwos` AS `u2` ON `u1`.`Id` = `u2`.`ReferenceInverseId` + LEFT JOIN ( + SELECT `u3`.`LeftId`, `u3`.`RightId`, `u3`.`Payload`, `u4`.`Id`, `u4`.`Name` + FROM `UnidirectionalJoinOneSelfPayload` AS `u3` + INNER JOIN `UnidirectionalEntityOnes` AS `u4` ON `u3`.`RightId` = `u4`.`Id` + ) AS `t` ON `u1`.`Id` = `t`.`LeftId` +) AS `t0` ON `u`.`Id` = `t0`.`ThreeId` +ORDER BY `u`.`Id`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id`, `t0`.`Id0`, `t0`.`LeftId`, `t0`.`RightId` +"""); + } + + public override async Task Include_skip_navigation_and_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_and_reference_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`ExtraId`, `u`.`Name`, `u`.`ReferenceInverseId`, `u0`.`Id`, `t`.`TwoSkipSharedId`, `t`.`UnidirectionalEntityOneId`, `t`.`Id`, `t`.`Name`, `u0`.`CollectionInverseId`, `u0`.`Name`, `u0`.`ReferenceInverseId` +FROM `UnidirectionalEntityTwos` AS `u` +LEFT JOIN `UnidirectionalEntityThrees` AS `u0` ON `u`.`Id` = `u0`.`ReferenceInverseId` +LEFT JOIN ( + SELECT `u1`.`TwoSkipSharedId`, `u1`.`UnidirectionalEntityOneId`, `u2`.`Id`, `u2`.`Name` + FROM `UnidirectionalEntityOneUnidirectionalEntityTwo` AS `u1` + INNER JOIN `UnidirectionalEntityOnes` AS `u2` ON `u1`.`UnidirectionalEntityOneId` = `u2`.`Id` +) AS `t` ON `u`.`Id` = `t`.`TwoSkipSharedId` +ORDER BY `u`.`Id`, `u0`.`Id`, `t`.`TwoSkipSharedId`, `t`.`UnidirectionalEntityOneId` +"""); + } + + public override async Task Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Payload`, `t0`.`Id`, `t0`.`Name`, `t0`.`OneId0`, `t0`.`ThreeId0`, `t0`.`Payload0`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`Name0`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityThrees` AS `u` +LEFT JOIN ( + SELECT `u0`.`OneId`, `u0`.`ThreeId`, `u0`.`Payload`, `u1`.`Id`, `u1`.`Name`, `t`.`OneId` AS `OneId0`, `t`.`ThreeId` AS `ThreeId0`, `t`.`Payload` AS `Payload0`, `t`.`Id` AS `Id0`, `t`.`CollectionInverseId`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId` + FROM `UnidirectionalJoinOneToThreePayloadFullShared` AS `u0` + INNER JOIN `UnidirectionalEntityOnes` AS `u1` ON `u0`.`OneId` = `u1`.`Id` + LEFT JOIN ( + SELECT `u2`.`OneId`, `u2`.`ThreeId`, `u2`.`Payload`, `u3`.`Id`, `u3`.`CollectionInverseId`, `u3`.`Name`, `u3`.`ReferenceInverseId` + FROM `UnidirectionalJoinOneToThreePayloadFullShared` AS `u2` + INNER JOIN `UnidirectionalEntityThrees` AS `u3` ON `u2`.`ThreeId` = `u3`.`Id` + ) AS `t` ON `u1`.`Id` = `t`.`OneId` +) AS `t0` ON `u`.`Id` = `t0`.`ThreeId` +ORDER BY `u`.`Id`, `t0`.`OneId`, `t0`.`ThreeId`, `t0`.`Id`, `t0`.`OneId0`, `t0`.`ThreeId0` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_unidirectional(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`OneId`, `t`.`ThreeId`, `t`.`Payload`, `t`.`Id`, `t`.`Name` +FROM `EntityThrees` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`ThreeId`, `j`.`Payload`, `e0`.`Id`, `e0`.`Name` + FROM `JoinOneToThreePayloadFullShared` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`ThreeId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`ThreeId` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t`.`ThreeId`, `t`.`TwoId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `UnidirectionalEntityThrees` AS `u` +LEFT JOIN ( + SELECT `u0`.`ThreeId`, `u0`.`TwoId`, `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId` + FROM `UnidirectionalJoinTwoToThree` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` +) AS `t` ON `u`.`Id` = `t`.`ThreeId` +ORDER BY `u`.`Id`, `t`.`Id`, `t`.`ThreeId` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`CollectionInverseId`, `u`.`ExtraId`, `u`.`Name`, `u`.`ReferenceInverseId`, `t0`.`SelfSkipSharedRightId`, `t0`.`UnidirectionalEntityTwoId`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityTwos` AS `u` +LEFT JOIN ( + SELECT `t`.`SelfSkipSharedRightId`, `t`.`UnidirectionalEntityTwoId`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `u0`.`SelfSkipSharedRightId`, `u0`.`UnidirectionalEntityTwoId`, `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`UnidirectionalEntityTwoId` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalEntityTwoUnidirectionalEntityTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`SelfSkipSharedRightId` = `u1`.`Id` + ) AS `t` + WHERE 2 < `t`.`row` +) AS `t0` ON `u`.`Id` = `t0`.`UnidirectionalEntityTwoId` +ORDER BY `u`.`Id`, `t0`.`UnidirectionalEntityTwoId`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `t0`.`TwoSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `t`.`TwoSkipSharedId`, `t`.`UnidirectionalEntityCompositeKeyKey1`, `t`.`UnidirectionalEntityCompositeKeyKey2`, `t`.`UnidirectionalEntityCompositeKeyKey3`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `u0`.`TwoSkipSharedId`, `u0`.`UnidirectionalEntityCompositeKeyKey1`, `u0`.`UnidirectionalEntityCompositeKeyKey2`, `u0`.`UnidirectionalEntityCompositeKeyKey3`, `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`UnidirectionalEntityCompositeKeyKey1`, `u0`.`UnidirectionalEntityCompositeKeyKey2`, `u0`.`UnidirectionalEntityCompositeKeyKey3` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoSkipSharedId` = `u1`.`Id` + ) AS `t` + WHERE `t`.`row` <= 2 +) AS `t0` ON ((`u`.`Key1` = `t0`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u`.`Key2` = `t0`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u`.`Key3` = `t0`.`UnidirectionalEntityCompositeKeyKey3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3`, `t0`.`Id` +"""); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `u`.`Name`, `t0`.`Id`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`ThreeId`, `t0`.`Id0`, `t0`.`CollectionInverseId`, `t0`.`Name`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalEntityCompositeKeys` AS `u` +LEFT JOIN ( + SELECT `t`.`Id`, `t`.`CompositeId1`, `t`.`CompositeId2`, `t`.`CompositeId3`, `t`.`ThreeId`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`Name`, `t`.`ReferenceInverseId` + FROM ( + SELECT `u0`.`Id`, `u0`.`CompositeId1`, `u0`.`CompositeId2`, `u0`.`CompositeId3`, `u0`.`ThreeId`, `u1`.`Id` AS `Id0`, `u1`.`CollectionInverseId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, ROW_NUMBER() OVER(PARTITION BY `u0`.`CompositeId1`, `u0`.`CompositeId2`, `u0`.`CompositeId3` ORDER BY `u1`.`Id`) AS `row` + FROM `UnidirectionalJoinThreeToCompositeKeyFull` AS `u0` + INNER JOIN `UnidirectionalEntityThrees` AS `u1` ON `u0`.`ThreeId` = `u1`.`Id` + ) AS `t` + WHERE (1 < `t`.`row`) AND (`t`.`row` <= 3) +) AS `t0` ON ((`u`.`Key1` = `t0`.`CompositeId1`) AND (`u`.`Key2` = `t0`.`CompositeId2`)) AND (`u`.`Key3` = `t0`.`CompositeId3`) +ORDER BY `u`.`Key1`, `u`.`Key2`, `u`.`Key3`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Id0` +"""); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name`, `u`.`Number`, `u`.`IsGreen`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`Name`, `t0`.`TwoSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3`, `t0`.`Id`, `t0`.`CollectionInverseId`, `t0`.`ExtraId`, `t0`.`Name0`, `t0`.`ReferenceInverseId` +FROM `UnidirectionalLeaves` AS `u` +LEFT JOIN ( + SELECT `u0`.`LeafId`, `u0`.`CompositeId1`, `u0`.`CompositeId2`, `u0`.`CompositeId3`, `u1`.`Key1`, `u1`.`Key2`, `u1`.`Key3`, `u1`.`Name`, `t`.`TwoSkipSharedId`, `t`.`UnidirectionalEntityCompositeKeyKey1`, `t`.`UnidirectionalEntityCompositeKeyKey2`, `t`.`UnidirectionalEntityCompositeKeyKey3`, `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name` AS `Name0`, `t`.`ReferenceInverseId` + FROM `UnidirectionalJoinCompositeKeyToLeaf` AS `u0` + INNER JOIN `UnidirectionalEntityCompositeKeys` AS `u1` ON ((`u0`.`CompositeId1` = `u1`.`Key1`) AND (`u0`.`CompositeId2` = `u1`.`Key2`)) AND (`u0`.`CompositeId3` = `u1`.`Key3`) + LEFT JOIN ( + SELECT `u2`.`TwoSkipSharedId`, `u2`.`UnidirectionalEntityCompositeKeyKey1`, `u2`.`UnidirectionalEntityCompositeKeyKey2`, `u2`.`UnidirectionalEntityCompositeKeyKey3`, `u3`.`Id`, `u3`.`CollectionInverseId`, `u3`.`ExtraId`, `u3`.`Name`, `u3`.`ReferenceInverseId` + FROM `UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo` AS `u2` + INNER JOIN `UnidirectionalEntityTwos` AS `u3` ON `u2`.`TwoSkipSharedId` = `u3`.`Id` + ) AS `t` ON ((`u1`.`Key1` = `t`.`UnidirectionalEntityCompositeKeyKey1`) AND (`u1`.`Key2` = `t`.`UnidirectionalEntityCompositeKeyKey2`)) AND (`u1`.`Key3` = `t`.`UnidirectionalEntityCompositeKeyKey3`) + WHERE `u1`.`Key1` < 5 +) AS `t0` ON `u`.`Id` = `t0`.`LeafId` +ORDER BY `u`.`Id`, `t0`.`LeafId`, `t0`.`CompositeId1`, `t0`.`CompositeId2`, `t0`.`CompositeId3`, `t0`.`Key1`, `t0`.`Key2`, `t0`.`Key3`, `t0`.`TwoSkipSharedId`, `t0`.`UnidirectionalEntityCompositeKeyKey1`, `t0`.`UnidirectionalEntityCompositeKeyKey2`, `t0`.`UnidirectionalEntityCompositeKeyKey3` +"""); + } + + public override async Task Filter_include_on_skip_navigation_combined_unidirectional(bool async) + { + await base.Filter_include_on_skip_navigation_combined_unidirectional(async); + + AssertSql( +""" +SELECT `e`.`Id`, `e`.`CollectionInverseId`, `e`.`ExtraId`, `e`.`Name`, `e`.`ReferenceInverseId`, `t`.`OneId`, `t`.`TwoId`, `t`.`JoinOneToTwoExtraId`, `t`.`Id`, `t`.`Name`, `t`.`Id0`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name0`, `t`.`ReferenceInverseId`, `t`.`Id1`, `t`.`CollectionInverseId0`, `t`.`ExtraId0`, `t`.`Name1`, `t`.`ReferenceInverseId0` +FROM `EntityTwos` AS `e` +LEFT JOIN ( + SELECT `j`.`OneId`, `j`.`TwoId`, `j`.`JoinOneToTwoExtraId`, `e0`.`Id`, `e0`.`Name`, `e1`.`Id` AS `Id0`, `e1`.`CollectionInverseId`, `e1`.`ExtraId`, `e1`.`Name` AS `Name0`, `e1`.`ReferenceInverseId`, `e2`.`Id` AS `Id1`, `e2`.`CollectionInverseId` AS `CollectionInverseId0`, `e2`.`ExtraId` AS `ExtraId0`, `e2`.`Name` AS `Name1`, `e2`.`ReferenceInverseId` AS `ReferenceInverseId0` + FROM `JoinOneToTwo` AS `j` + INNER JOIN `EntityOnes` AS `e0` ON `j`.`OneId` = `e0`.`Id` + LEFT JOIN `EntityTwos` AS `e1` ON `e0`.`Id` = `e1`.`ReferenceInverseId` + LEFT JOIN `EntityTwos` AS `e2` ON `e0`.`Id` = `e2`.`CollectionInverseId` + WHERE `e0`.`Id` < 10 +) AS `t` ON `e`.`Id` = `t`.`TwoId` +ORDER BY `e`.`Id`, `t`.`OneId`, `t`.`TwoId`, `t`.`Id`, `t`.`Id0` +"""); + } + + public override async Task Throws_when_different_filtered_include_unidirectional(bool async) + { + await base.Throws_when_different_filtered_include_unidirectional(async); + + AssertSql(); + } + + public override async Task Includes_accessed_via_different_path_are_merged_unidirectional(bool async) + { + await base.Includes_accessed_via_different_path_are_merged_unidirectional(async); + + AssertSql( +""" +SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id], [t0].[Name], [t0].[OneId0], [t0].[ThreeId0], [t0].[Payload0], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name0], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u0].[OneId], [u0].[ThreeId], [u0].[Payload], [u1].[Id], [u1].[Name], [t].[OneId] AS [OneId0], [t].[ThreeId] AS [ThreeId0], [t].[Payload] AS [Payload0], [t].[Id] AS [Id0], [t].[CollectionInverseId], [t].[Name] AS [Name0], [t].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN ( + SELECT [u2].[OneId], [u2].[ThreeId], [u2].[Payload], [u3].[Id], [u3].[CollectionInverseId], [u3].[Name], [u3].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u2] + INNER JOIN [UnidirectionalEntityThrees] AS [u3] ON [u2].[ThreeId] = [u3].[Id] + ) AS [t] ON [u1].[Id] = [t].[OneId] +) AS [t0] ON [u].[Id] = [t0].[ThreeId] +ORDER BY [u].[Id], [t0].[OneId], [t0].[ThreeId], [t0].[Id], [t0].[OneId0], [t0].[ThreeId0] +"""); + } + + public override async Task Select_many_over_skip_navigation_where_non_equality_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_non_equality_unidirectional(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`CollectionInverseId`, `t`.`ExtraId`, `t`.`Name`, `t`.`ReferenceInverseId` +FROM `UnidirectionalEntityOnes` AS `u` +LEFT JOIN ( + SELECT `u1`.`Id`, `u1`.`CollectionInverseId`, `u1`.`ExtraId`, `u1`.`Name`, `u1`.`ReferenceInverseId`, `u0`.`OneId` + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` +) AS `t` ON (`u`.`Id` = `t`.`OneId`) AND (`u`.`Id` <> `t`.`Id`) +"""); + } + + public override async Task Contains_on_skip_collection_navigation_unidirectional(bool async) + { + await base.Contains_on_skip_collection_navigation_unidirectional(async); + + AssertSql( +""" +@__entity_equality_two_0_Id='1' (Nullable = true) + +SELECT `u`.`Id`, `u`.`Name` +FROM `UnidirectionalEntityOnes` AS `u` +WHERE EXISTS ( + SELECT 1 + FROM `UnidirectionalJoinOneToTwo` AS `u0` + INNER JOIN `UnidirectionalEntityTwos` AS `u1` ON `u0`.`TwoId` = `u1`.`Id` + WHERE (`u`.`Id` = `u0`.`OneId`) AND (`u1`.`Id` = @__entity_equality_two_0_Id)) +"""); + } + + public override async Task GetType_in_hierarchy_in_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_base_type_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name`, NULL AS `Number`, NULL AS `IsGreen`, 'UnidirectionalEntityRoot' AS `Discriminator` +FROM `UnidirectionalRoots` AS `u` +"""); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type_unidirectional(async); + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name`, `u`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` +FROM `UnidirectionalBranches` AS `u` +"""); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_unidirectional(async); + + AssertSql( +""" +SELECT `u`.`Id`, `u`.`Name`, `u`.`Number`, `u`.`IsGreen`, 'UnidirectionalEntityLeaf' AS `Discriminator` +FROM `UnidirectionalLeaves` AS `u` +"""); + } + + public override async Task GetType_in_hierarchy_in_querying_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_querying_base_type_unidirectional(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`Number`, `t`.`IsGreen`, `t`.`Discriminator` +FROM ( + SELECT `u`.`Id`, `u`.`Name`, `u`.`Number`, NULL AS `IsGreen`, 'UnidirectionalEntityBranch' AS `Discriminator` + FROM `UnidirectionalBranches` AS `u` + UNION ALL + SELECT `u0`.`Id`, `u0`.`Name`, `u0`.`Number`, `u0`.`IsGreen`, 'UnidirectionalEntityLeaf' AS `Discriminator` + FROM `UnidirectionalLeaves` AS `u0` +) AS `t` +WHERE FALSE +"""); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCRelationshipsQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCRelationshipsQueryMySqlTest.cs new file mode 100644 index 000000000..43bacab8c --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCRelationshipsQueryMySqlTest.cs @@ -0,0 +1,2728 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Xunit; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class TPCRelationshipsQueryMySqlTest + : TPCRelationshipsQueryTestBase +{ + public TPCRelationshipsQueryMySqlTest( + TPCRelationshipsQueryMySqlFixture fixture, + ITestOutputHelper testOutputHelper) + : base(fixture) + { + fixture.TestSqlLoggerFactory.Clear(); + //fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override void Changes_in_derived_related_entities_are_detected() + { + base.Changes_in_derived_related_entities_are_detected(); + + AssertSql( +""" +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`BaseId`, `t0`.`Discriminator`, `t0`.`BaseInheritanceRelationshipEntityId`, `t0`.`Id1`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t0`.`Id0`, `t0`.`Name0`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t0`.`OwnedReferenceOnDerived_Id`, `t0`.`OwnedReferenceOnDerived_Name`, `t1`.`Id`, `t1`.`BaseParentId`, `t1`.`Name`, `t1`.`DerivedProperty`, `t1`.`Discriminator` +FROM ( + SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `o`.`Id` AS `Id0`, `o`.`Name` AS `Name0`, `d`.`Id` AS `Id1`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` + FROM ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` + ) AS `t` + LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` + LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` + WHERE `t`.`Name` = 'Derived1(4)' + LIMIT 2 +) AS `t0` +LEFT JOIN `OwnedCollections` AS `o0` ON `t0`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t0`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t1` ON `t0`.`Id` = `t1`.`BaseParentId` +ORDER BY `t0`.`Id`, `t0`.`BaseInheritanceRelationshipEntityId`, `t0`.`Id1`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_without_inheritance(bool async) + { + await base.Include_collection_without_inheritance(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `c`.`Id`, `c`.`Name`, `c`.`ParentId` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN `CollectionsOnBase` AS `c` ON `t`.`Id` = `c`.`ParentId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_without_inheritance_reverse(bool async) + { + await base.Include_collection_without_inheritance_reverse(async); + + AssertSql( +""" +SELECT `c`.`Id`, `c`.`Name`, `c`.`ParentId`, `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `CollectionsOnBase` AS `c` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` ON `c`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_collection_without_inheritance_with_filter(bool async) + { + await base.Include_collection_without_inheritance_with_filter(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `c`.`Id`, `c`.`Name`, `c`.`ParentId` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN `CollectionsOnBase` AS `c` ON `t`.`Id` = `c`.`ParentId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_without_inheritance_with_filter_reverse(bool async) + { + await base.Include_collection_without_inheritance_with_filter_reverse(async); + + AssertSql( +""" +SELECT `c`.`Id`, `c`.`Name`, `c`.`ParentId`, `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `CollectionsOnBase` AS `c` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` ON `c`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`c`.`Name` <> 'Bar') OR `c`.`Name` IS NULL +ORDER BY `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_collection_with_inheritance(bool async) + { + await base.Include_collection_with_inheritance(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId`, `d2`.`Name`, `d2`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d2` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_on_derived1(bool async) + { + await base.Include_collection_with_inheritance_on_derived1(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedProperty`, `t`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_on_derived2(bool async) + { + await base.Include_collection_with_inheritance_on_derived2(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`Id`, `t`.`Name`, `t`.`ParentId`, `t`.`DerivedInheritanceRelationshipEntityId`, `t`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`ParentId`, NULL AS `DerivedInheritanceRelationshipEntityId`, 'BaseCollectionOnDerived' AS `Discriminator` + FROM `BaseCollectionsOnDerived` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`ParentId`, `d1`.`DerivedInheritanceRelationshipEntityId`, 'DerivedCollectionOnDerived' AS `Discriminator` + FROM `DerivedCollectionsOnDerived` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`ParentId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_on_derived3(bool async) + { + await base.Include_collection_with_inheritance_on_derived3(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `d1`.`Id`, `d1`.`Name`, `d1`.`ParentId`, `d1`.`DerivedInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN `DerivedCollectionsOnDerived` AS `d1` ON `d`.`Id` = `d1`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_on_derived_reverse(bool async) + { + await base.Include_collection_with_inheritance_on_derived_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentId`, `t`.`DerivedInheritanceRelationshipEntityId`, `t`.`Discriminator`, `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`ParentId`, NULL AS `DerivedInheritanceRelationshipEntityId`, 'BaseCollectionOnDerived' AS `Discriminator` + FROM `BaseCollectionsOnDerived` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`ParentId`, `d1`.`DerivedInheritanceRelationshipEntityId`, 'DerivedCollectionOnDerived' AS `Discriminator` + FROM `DerivedCollectionsOnDerived` AS `d1` +) AS `t` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`ParentId` = `d`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_collection_with_inheritance_reverse(bool async) + { + await base.Include_collection_with_inheritance_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedProperty`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`Name`, `t0`.`BaseId`, `t0`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t0`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t0`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_collection_with_inheritance_with_filter(bool async) + { + await base.Include_collection_with_inheritance_with_filter(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId`, `d2`.`Name`, `d2`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d2` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_with_filter_reverse(bool async) + { + await base.Include_collection_with_inheritance_with_filter_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedProperty`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`Name`, `t0`.`BaseId`, `t0`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t0`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t0`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_without_inheritance(bool async) + { + await base.Include_reference_without_inheritance(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `r`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `r`.`Name`, `r`.`ParentId` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `ReferencesOnBase` AS `r` ON `t`.`Id` = `r`.`ParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `r`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_without_inheritance_on_derived1(bool async) + { + await base.Include_reference_without_inheritance_on_derived1(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `r`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `r`.`Name`, `r`.`ParentId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `ReferencesOnBase` AS `r` ON `d`.`Id` = `r`.`ParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `r`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_without_inheritance_on_derived2(bool async) + { + await base.Include_reference_without_inheritance_on_derived2(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `r`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `r`.`Name`, `r`.`ParentId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `ReferencesOnDerived` AS `r` ON `d`.`Id` = `r`.`ParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `r`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_without_inheritance_on_derived_reverse(bool async) + { + await base.Include_reference_without_inheritance_on_derived_reverse(async); + + AssertSql( +""" +SELECT `r`.`Id`, `r`.`Name`, `r`.`ParentId`, `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `ReferencesOnDerived` AS `r` +LEFT JOIN `DerivedEntities` AS `d` ON `r`.`ParentId` = `d`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `r`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_without_inheritance_reverse(bool async) + { + await base.Include_reference_without_inheritance_reverse(async); + + AssertSql( +""" +SELECT `r`.`Id`, `r`.`Name`, `r`.`ParentId`, `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `ReferencesOnBase` AS `r` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` ON `r`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `r`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_without_inheritance_with_filter(bool async) + { + await base.Include_reference_without_inheritance_with_filter(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `r`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `r`.`Name`, `r`.`ParentId` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `ReferencesOnBase` AS `r` ON `t`.`Id` = `r`.`ParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `r`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_without_inheritance_with_filter_reverse(bool async) + { + await base.Include_reference_without_inheritance_with_filter_reverse(async); + + AssertSql( +""" +SELECT `r`.`Id`, `r`.`Name`, `r`.`ParentId`, `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `ReferencesOnBase` AS `r` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` ON `r`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`r`.`Name` <> 'Bar') OR `r`.`Name` IS NULL +ORDER BY `r`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance(bool async) + { + await base.Include_reference_with_inheritance(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId`, `d2`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d2` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_on_derived1(bool async) + { + await base.Include_reference_with_inheritance_on_derived1(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`BaseParentId`, `t`.`Name`, `t`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_on_derived2(bool async) + { + await base.Include_reference_with_inheritance_on_derived2(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedInheritanceRelationshipEntityId`, `t`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedInheritanceRelationshipEntityId`, 'BaseReferenceOnDerived' AS `Discriminator` + FROM `BaseReferencesOnDerived` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedInheritanceRelationshipEntityId`, 'DerivedReferenceOnDerived' AS `Discriminator` + FROM `DerivedReferencesOnDerived` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_on_derived4(bool async) + { + await base.Include_reference_with_inheritance_on_derived4(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `d0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d1`.`DerivedInheritanceRelationshipEntityId`, `d1`.`Id`, `d1`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `DerivedReferencesOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d1` ON `d`.`Id` = `d1`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `d0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d1`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_on_derived_reverse(bool async) + { + await base.Include_reference_with_inheritance_on_derived_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedInheritanceRelationshipEntityId`, `t`.`Discriminator`, `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedInheritanceRelationshipEntityId`, 'BaseReferenceOnDerived' AS `Discriminator` + FROM `BaseReferencesOnDerived` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedInheritanceRelationshipEntityId`, 'DerivedReferenceOnDerived' AS `Discriminator` + FROM `DerivedReferencesOnDerived` AS `d1` +) AS `t` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`BaseParentId` = `d`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_on_derived_with_filter1(bool async) + { + await base.Include_reference_with_inheritance_on_derived_with_filter1(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`BaseParentId`, `t`.`Name`, `t`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`d`.`Name` <> 'Bar') OR `d`.`Name` IS NULL +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_on_derived_with_filter2(bool async) + { + await base.Include_reference_with_inheritance_on_derived_with_filter2(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedInheritanceRelationshipEntityId`, `t`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedInheritanceRelationshipEntityId`, 'BaseReferenceOnDerived' AS `Discriminator` + FROM `BaseReferencesOnDerived` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedInheritanceRelationshipEntityId`, 'DerivedReferenceOnDerived' AS `Discriminator` + FROM `DerivedReferencesOnDerived` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`d`.`Name` <> 'Bar') OR `d`.`Name` IS NULL +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_on_derived_with_filter4(bool async) + { + await base.Include_reference_with_inheritance_on_derived_with_filter4(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `d0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d1`.`DerivedInheritanceRelationshipEntityId`, `d1`.`Id`, `d1`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `DerivedReferencesOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d1` ON `d`.`Id` = `d1`.`DerivedInheritanceRelationshipEntityId` +WHERE (`d`.`Name` <> 'Bar') OR `d`.`Name` IS NULL +ORDER BY `d`.`Id`, `d0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d1`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_on_derived_with_filter_reverse(bool async) + { + await base.Include_reference_with_inheritance_on_derived_with_filter_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedInheritanceRelationshipEntityId`, `t`.`Discriminator`, `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedInheritanceRelationshipEntityId`, 'BaseReferenceOnDerived' AS `Discriminator` + FROM `BaseReferencesOnDerived` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedInheritanceRelationshipEntityId`, 'DerivedReferenceOnDerived' AS `Discriminator` + FROM `DerivedReferencesOnDerived` AS `d1` +) AS `t` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`BaseParentId` = `d`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_reverse(bool async) + { + await base.Include_reference_with_inheritance_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`Name`, `t0`.`BaseId`, `t0`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t0`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t0`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_with_filter(bool async) + { + await base.Include_reference_with_inheritance_with_filter(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId`, `d2`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d2` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_reference_with_inheritance_with_filter_reverse(bool async) + { + await base.Include_reference_with_inheritance_with_filter_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`Name`, `t0`.`BaseId`, `t0`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t0`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t0`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_self_reference_with_inheritance(bool async) + { + await base.Include_self_reference_with_inheritance(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d0`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o1`.`BaseInheritanceRelationshipEntityId`, `o1`.`Id`, `o1`.`Name`, `o`.`Id`, `o`.`Name`, `d1`.`DerivedInheritanceRelationshipEntityId`, `d1`.`Id`, `d1`.`Name`, `d0`.`OwnedReferenceOnDerived_Id`, `d0`.`OwnedReferenceOnDerived_Name`, `d`.`Name`, `d`.`BaseId`, `o2`.`BaseInheritanceRelationshipEntityId`, `o2`.`Id`, `o2`.`Name`, `o0`.`Id`, `o0`.`Name`, `d2`.`DerivedInheritanceRelationshipEntityId`, `d2`.`Id`, `d2`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d3`.`Id`, `d3`.`Name`, `d3`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d3` +) AS `t` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`BaseId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d0` ON `t`.`Id` = `d0`.`Id` +LEFT JOIN `OwnedReferences` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o1` ON `t`.`Id` = `o1`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d1` ON `t`.`Id` = `d1`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o2` ON `d`.`Id` = `o2`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d2` ON `d`.`Id` = `d2`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d0`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o1`.`BaseInheritanceRelationshipEntityId`, `o1`.`Id`, `d1`.`DerivedInheritanceRelationshipEntityId`, `d1`.`Id`, `o2`.`BaseInheritanceRelationshipEntityId`, `o2`.`Id`, `d2`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_self_reference_with_inheritance_reverse(bool async) + { + await base.Include_self_reference_with_inheritance_reverse(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `d0`.`Id`, `o1`.`BaseInheritanceRelationshipEntityId`, `o1`.`Id`, `o1`.`Name`, `o`.`Id`, `o`.`Name`, `d1`.`DerivedInheritanceRelationshipEntityId`, `d1`.`Id`, `d1`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o2`.`BaseInheritanceRelationshipEntityId`, `o2`.`Id`, `o2`.`Name`, `o0`.`Id`, `o0`.`Name`, `d2`.`DerivedInheritanceRelationshipEntityId`, `d2`.`Id`, `d2`.`Name`, `d0`.`OwnedReferenceOnDerived_Id`, `d0`.`OwnedReferenceOnDerived_Name` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d3`.`Id`, `d3`.`Name`, `d3`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d3` +) AS `t` ON `d`.`BaseId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedReferences` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d0` ON `t`.`Id` = `d0`.`Id` +LEFT JOIN `OwnedCollections` AS `o1` ON `d`.`Id` = `o1`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d1` ON `d`.`Id` = `d1`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o2` ON `t`.`Id` = `o2`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d2` ON `t`.`Id` = `d2`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `d0`.`Id`, `o1`.`BaseInheritanceRelationshipEntityId`, `o1`.`Id`, `d1`.`DerivedInheritanceRelationshipEntityId`, `d1`.`Id`, `o2`.`BaseInheritanceRelationshipEntityId`, `o2`.`Id`, `d2`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Nested_include_collection_reference_on_non_entity_base(bool async) + { + await base.Nested_include_collection_reference_on_non_entity_base(async); + + AssertSql( +""" +SELECT `r`.`Id`, `r`.`Name`, `t`.`Id`, `t`.`Name`, `t`.`ReferenceId`, `t`.`ReferencedEntityId`, `t`.`Id0`, `t`.`Name0` +FROM `ReferencedEntities` AS `r` +LEFT JOIN ( + SELECT `p`.`Id`, `p`.`Name`, `p`.`ReferenceId`, `p`.`ReferencedEntityId`, `r0`.`Id` AS `Id0`, `r0`.`Name` AS `Name0` + FROM `PrincipalEntities` AS `p` + LEFT JOIN `ReferencedEntities` AS `r0` ON `p`.`ReferenceId` = `r0`.`Id` +) AS `t` ON `r`.`Id` = `t`.`ReferencedEntityId` +ORDER BY `r`.`Id`, `t`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_collection_collection(bool async) + { + await base.Nested_include_with_inheritance_collection_collection(async); + + AssertSql( +$""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t1`.`Id`, `t1`.`BaseParentId`, `t1`.`Name`, `t1`.`DerivedProperty`, `t1`.`Discriminator`, `t1`.`Id0`, `t1`.`Name0`, `t1`.`ParentCollectionId`, `t1`.`ParentReferenceId`, `t1`.`Discriminator0` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t2`.`Id` AS `Id0`, `t2`.`Name` AS `Name0`, `t2`.`ParentCollectionId`, `t2`.`ParentReferenceId`, `t2`.`Discriminator` AS `Discriminator0` + FROM ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `DerivedProperty`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'BaseCollectionOnBase'")} AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId`, `d2`.`Name`, `d2`.`DerivedProperty`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'DerivedCollectionOnBase'")} AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d2` + ) AS `t0` + LEFT JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'NestedCollectionBase'")} AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'NestedCollectionDerived'")} AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` + ) AS `t2` ON `t0`.`Id` = `t2`.`ParentCollectionId` +) AS `t1` ON `t`.`Id` = `t1`.`BaseParentId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `t1`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_collection_collection_reverse(bool async) + { + await base.Nested_include_with_inheritance_collection_collection_reverse(async); + + AssertSql( +$""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentCollectionId`, `t`.`ParentReferenceId`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`Name`, `t1`.`BaseId`, `t1`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t0` ON `t`.`ParentCollectionId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t1`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t1`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Nested_include_with_inheritance_collection_reference(bool async) + { + await base.Nested_include_with_inheritance_collection_reference(async); + + AssertSql( +$""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t1`.`Id`, `t1`.`BaseParentId`, `t1`.`Name`, `t1`.`DerivedProperty`, `t1`.`Discriminator`, `t1`.`Id0`, `t1`.`Name0`, `t1`.`ParentCollectionId`, `t1`.`ParentReferenceId`, `t1`.`Discriminator0` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t2`.`Id` AS `Id0`, `t2`.`Name` AS `Name0`, `t2`.`ParentCollectionId`, `t2`.`ParentReferenceId`, `t2`.`Discriminator` AS `Discriminator0` + FROM ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, {MySqlTestHelpers.MySqlBug96947Workaround(@"NULL", "signed")} AS `DerivedProperty`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'BaseCollectionOnBase'")} AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId`, `d2`.`Name`, `d2`.`DerivedProperty`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'DerivedCollectionOnBase'")} AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d2` + ) AS `t0` + LEFT JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'NestedReferenceBase'")} AS `Discriminator` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, {MySqlTestHelpers.MySqlBug96947Workaround(@"'NestedReferenceDerived'")} AS `Discriminator` + FROM `NestedReferencesDerived` AS `n0` + ) AS `t2` ON `t0`.`Id` = `t2`.`ParentCollectionId` +) AS `t1` ON `t`.`Id` = `t1`.`BaseParentId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `t1`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_collection_reference_reverse(bool async) + { + await base.Nested_include_with_inheritance_collection_reference_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentCollectionId`, `t`.`ParentReferenceId`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`Name`, `t1`.`BaseId`, `t1`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedReferenceBase' AS `Discriminator` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedReferenceDerived' AS `Discriminator` + FROM `NestedReferencesDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t0` ON `t`.`ParentCollectionId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t1`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t1`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_collection(bool async) + { + await base.Nested_include_with_inheritance_reference_collection(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`Name`, `t1`.`ParentCollectionId`, `t1`.`ParentReferenceId`, `t1`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId`, `d2`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d2` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t1` ON `t0`.`Id` = `t1`.`ParentReferenceId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_collection_on_base(bool async) + { + await base.Nested_include_with_inheritance_reference_collection_on_base(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`BaseParentId`, `t`.`Name`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`Name`, `t0`.`ParentCollectionId`, `t0`.`ParentReferenceId`, `t0`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t0` ON `t`.`Id` = `t0`.`ParentReferenceId` +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_collection_reverse(bool async) + { + await base.Nested_include_with_inheritance_reference_collection_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentCollectionId`, `t`.`ParentReferenceId`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`Name`, `t1`.`BaseId`, `t1`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t0` ON `t`.`ParentReferenceId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t1`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t1`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_reference(bool async) + { + await base.Nested_include_with_inheritance_reference_reference(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`Discriminator`, `t1`.`Name`, `t1`.`ParentCollectionId`, `t1`.`ParentReferenceId`, `t1`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId`, `d2`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d2` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +LEFT JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedReferenceBase' AS `Discriminator` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedReferenceDerived' AS `Discriminator` + FROM `NestedReferencesDerived` AS `n0` +) AS `t1` ON `t0`.`Id` = `t1`.`ParentReferenceId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_reference_on_base(bool async) + { + await base.Nested_include_with_inheritance_reference_reference_on_base(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`BaseParentId`, `t`.`Name`, `t`.`Discriminator`, `t0`.`Name`, `t0`.`ParentCollectionId`, `t0`.`ParentReferenceId`, `t0`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedReferenceBase' AS `Discriminator` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedReferenceDerived' AS `Discriminator` + FROM `NestedReferencesDerived` AS `n0` +) AS `t0` ON `t`.`Id` = `t0`.`ParentReferenceId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_reference_reverse(bool async) + { + await base.Nested_include_with_inheritance_reference_reference_reverse(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentCollectionId`, `t`.`ParentReferenceId`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`Name`, `t1`.`BaseId`, `t1`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedReferenceBase' AS `Discriminator` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedReferenceDerived' AS `Discriminator` + FROM `NestedReferencesDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t0` ON `t`.`ParentReferenceId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t1`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t1`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId` +"""); + } + + public override async Task Collection_projection_on_base_type(bool async) + { + await base.Collection_projection_on_base_type(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d`.`Id` + FROM `DerivedEntities` AS `d` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +ORDER BY `t`.`Id` +"""); + } + + public override async Task Include_on_derived_type_with_queryable_Cast(bool async) + { + await base.Include_on_derived_type_with_queryable_Cast(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `o`.`Id`, `o`.`Name`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `d1`.`Id`, `d1`.`Name`, `d1`.`ParentId`, `d1`.`DerivedInheritanceRelationshipEntityId` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d2`.`Id`, `d2`.`Name`, `d2`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d2` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +LEFT JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +LEFT JOIN `DerivedCollectionsOnDerived` AS `d1` ON `t`.`Id` = `d1`.`DerivedInheritanceRelationshipEntityId` +WHERE `t`.`Id` >= 4 +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_split(bool async) + { + await base.Include_collection_with_inheritance_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_reverse_split(bool async) + { + await base.Include_collection_with_inheritance_reverse_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedProperty`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`Name`, `t0`.`BaseId`, `t0`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t0`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id` + FROM `DerivedEntities` AS `d2` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t0`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_with_filter_split(bool async) + { + await base.Include_collection_with_inheritance_with_filter_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`Name` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`Name` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`Name` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_with_filter_reverse_split(bool async) + { + await base.Include_collection_with_inheritance_with_filter_reverse_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedProperty`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`Name`, `t0`.`BaseId`, `t0`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t0`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id` + FROM `DerivedEntities` AS `d2` +) AS `t0` ON `t`.`BaseParentId` = `t0`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t0`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t0`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t0`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Include_collection_without_inheritance_split(bool async) + { + await base.Include_collection_without_inheritance_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `c`.`Id`, `c`.`Name`, `c`.`ParentId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `CollectionsOnBase` AS `c` ON `t`.`Id` = `c`.`ParentId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Include_collection_without_inheritance_reverse_split(bool async) + { + await base.Include_collection_without_inheritance_reverse_split(async); + + AssertSql( +""" +SELECT `c`.`Id`, `c`.`Name`, `c`.`ParentId`, `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `CollectionsOnBase` AS `c` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` ON `c`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +ORDER BY `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM `CollectionsOnBase` AS `c` +LEFT JOIN ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` ON `c`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM `CollectionsOnBase` AS `c` +LEFT JOIN ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` ON `c`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Include_collection_without_inheritance_with_filter_split(bool async) + { + await base.Include_collection_without_inheritance_with_filter_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`Name` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`Name` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `c`.`Id`, `c`.`Name`, `c`.`ParentId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id`, `b`.`Name` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `CollectionsOnBase` AS `c` ON `t`.`Id` = `c`.`ParentId` +WHERE (`t`.`Name` <> 'Bar') OR `t`.`Name` IS NULL +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Include_collection_without_inheritance_with_filter_reverse_split(bool async) + { + await base.Include_collection_without_inheritance_with_filter_reverse_split(async); + + AssertSql( +""" +SELECT `c`.`Id`, `c`.`Name`, `c`.`ParentId`, `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `CollectionsOnBase` AS `c` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` ON `c`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +WHERE (`c`.`Name` <> 'Bar') OR `c`.`Name` IS NULL +ORDER BY `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM `CollectionsOnBase` AS `c` +LEFT JOIN ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` ON `c`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +WHERE (`c`.`Name` <> 'Bar') OR `c`.`Name` IS NULL +ORDER BY `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM `CollectionsOnBase` AS `c` +LEFT JOIN ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` ON `c`.`ParentId` = `t`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE (`c`.`Name` <> 'Bar') OR `c`.`Name` IS NULL +ORDER BY `c`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Include_collection_with_inheritance_on_derived1_split(bool async) + { + await base.Include_collection_with_inheritance_on_derived1_split(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o`.`Id`, `o`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `t`.`Id`, `t`.`BaseParentId`, `t`.`Name`, `t`.`DerivedProperty`, `t`.`Discriminator`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_collection_with_inheritance_on_derived2_split(bool async) + { + await base.Include_collection_with_inheritance_on_derived2_split(async); + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o`.`Id`, `o`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentId`, `t`.`DerivedInheritanceRelationshipEntityId`, `t`.`Discriminator`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`ParentId`, NULL AS `DerivedInheritanceRelationshipEntityId`, 'BaseCollectionOnDerived' AS `Discriminator` + FROM `BaseCollectionsOnDerived` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`ParentId`, `d0`.`DerivedInheritanceRelationshipEntityId`, 'DerivedCollectionOnDerived' AS `Discriminator` + FROM `DerivedCollectionsOnDerived` AS `d0` +) AS `t` ON `d`.`Id` = `t`.`ParentId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_collection_with_inheritance_on_derived3_split(bool async) + { + await base.Include_collection_with_inheritance_on_derived3_split(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o`.`Id`, `o`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`ParentId`, `d0`.`DerivedInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `DerivedCollectionsOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +"""); + } + + public override async Task Include_collection_with_inheritance_on_derived_reverse_split(bool async) + { + await base.Include_collection_with_inheritance_on_derived_reverse_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentId`, `t`.`DerivedInheritanceRelationshipEntityId`, `t`.`Discriminator`, `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `o`.`BaseInheritanceRelationshipEntityId`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, `b`.`ParentId`, NULL AS `DerivedInheritanceRelationshipEntityId`, 'BaseCollectionOnDerived' AS `Discriminator` + FROM `BaseCollectionsOnDerived` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`ParentId`, `d0`.`DerivedInheritanceRelationshipEntityId`, 'DerivedCollectionOnDerived' AS `Discriminator` + FROM `DerivedCollectionsOnDerived` AS `d0` +) AS `t` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`ParentId` = `d`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM ( + SELECT `b`.`Id`, `b`.`ParentId` + FROM `BaseCollectionsOnDerived` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`ParentId` + FROM `DerivedCollectionsOnDerived` AS `d0` +) AS `t` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`ParentId` = `d`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM ( + SELECT `b`.`Id`, `b`.`ParentId` + FROM `BaseCollectionsOnDerived` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`ParentId` + FROM `DerivedCollectionsOnDerived` AS `d1` +) AS `t` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`ParentId` = `d`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `d`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_collection_split(bool async) + { + await base.Nested_include_with_inheritance_reference_collection_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`Discriminator` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId` + FROM `BaseReferencesOnBase` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId` + FROM `BaseReferencesOnBase` AS `b0` + UNION ALL + SELECT `d2`.`Id`, `d2`.`BaseParentId` + FROM `DerivedReferencesOnBase` AS `d2` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `t1`.`Id`, `t1`.`Name`, `t1`.`ParentCollectionId`, `t1`.`ParentReferenceId`, `t1`.`Discriminator`, `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId` + FROM `BaseReferencesOnBase` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t1` ON `t0`.`Id` = `t1`.`ParentReferenceId` +ORDER BY `t`.`Id`, `t0`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_collection_on_base_split(bool async) + { + await base.Nested_include_with_inheritance_reference_collection_on_base_split(async); + + AssertSql( +""" +SELECT `d`.`Id`, `d`.`Name`, `d`.`BaseId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `o`.`Id`, `o`.`Name`, `d`.`Id`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name`, `t`.`BaseParentId`, `t`.`Name`, `t`.`Discriminator` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d0` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId` + FROM `DerivedReferencesOnBase` AS `d0` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `OwnedCollections` AS `o0` ON `d`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `d`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`Name`, `t0`.`ParentCollectionId`, `t0`.`ParentReferenceId`, `t0`.`Discriminator`, `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +FROM `DerivedEntities` AS `d` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId` + FROM `DerivedReferencesOnBase` AS `d0` +) AS `t` ON `d`.`Id` = `t`.`BaseParentId` +LEFT JOIN `OwnedReferences` AS `o` ON `d`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +INNER JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t0` ON `t`.`Id` = `t0`.`ParentReferenceId` +ORDER BY `d`.`Id`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId` +"""); + } + + public override async Task Nested_include_with_inheritance_reference_collection_reverse_split(bool async) + { + await base.Nested_include_with_inheritance_reference_collection_reverse_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentCollectionId`, `t`.`ParentReferenceId`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`Name`, `t1`.`BaseId`, `t1`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, 'BaseReferenceOnBase' AS `Discriminator` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, 'DerivedReferenceOnBase' AS `Discriminator` + FROM `DerivedReferencesOnBase` AS `d0` +) AS `t0` ON `t`.`ParentReferenceId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `n`.`Id`, `n`.`ParentReferenceId` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`ParentReferenceId` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId` + FROM `DerivedReferencesOnBase` AS `d0` +) AS `t0` ON `t`.`ParentReferenceId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t1`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `n`.`Id`, `n`.`ParentReferenceId` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`ParentReferenceId` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseReferencesOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId` + FROM `DerivedReferencesOnBase` AS `d1` +) AS `t0` ON `t`.`ParentReferenceId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id` + FROM `DerivedEntities` AS `d2` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t1`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_collection_reference_split(bool async) + { + await base.Nested_include_with_inheritance_collection_reference_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `t1`.`Id`, `t1`.`BaseParentId`, `t1`.`Name`, `t1`.`DerivedProperty`, `t1`.`Discriminator`, `t1`.`Id0`, `t1`.`Name0`, `t1`.`ParentCollectionId`, `t1`.`ParentReferenceId`, `t1`.`Discriminator0` AS `Discriminator`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN ( + SELECT `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t2`.`Id` AS `Id0`, `t2`.`Name` AS `Name0`, `t2`.`ParentCollectionId`, `t2`.`ParentReferenceId`, `t2`.`Discriminator` AS `Discriminator0` + FROM ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` + ) AS `t0` + LEFT JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedReferenceBase' AS `Discriminator` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedReferenceDerived' AS `Discriminator` + FROM `NestedReferencesDerived` AS `n0` + ) AS `t2` ON `t0`.`Id` = `t2`.`ParentCollectionId` +) AS `t1` ON `t`.`Id` = `t1`.`BaseParentId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_collection_reference_reverse_split(bool async) + { + await base.Nested_include_with_inheritance_collection_reference_reverse_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentCollectionId`, `t`.`ParentReferenceId`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`Name`, `t1`.`BaseId`, `t1`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedReferenceBase' AS `Discriminator` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedReferenceDerived' AS `Discriminator` + FROM `NestedReferencesDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t0` ON `t`.`ParentCollectionId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `n`.`Id`, `n`.`ParentCollectionId` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`ParentCollectionId` + FROM `NestedReferencesDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t0` ON `t`.`ParentCollectionId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t1`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `n`.`Id`, `n`.`ParentCollectionId` + FROM `NestedReferences` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`ParentCollectionId` + FROM `NestedReferencesDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t0` ON `t`.`ParentCollectionId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id` + FROM `DerivedEntities` AS `d2` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t1`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_collection_collection_split(bool async) + { + await base.Nested_include_with_inheritance_collection_collection_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId`, `d1`.`Name`, `d1`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `t0`.`Id` +""", + // + """ +SELECT `t1`.`Id`, `t1`.`Name`, `t1`.`ParentCollectionId`, `t1`.`ParentReferenceId`, `t1`.`Discriminator`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `t0`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +INNER JOIN ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t1` ON `t0`.`Id` = `t1`.`ParentCollectionId` +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `t0`.`Id` +"""); + } + + public override async Task Nested_include_with_inheritance_collection_collection_reverse_split(bool async) + { + await base.Nested_include_with_inheritance_collection_collection_reverse_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`ParentCollectionId`, `t`.`ParentReferenceId`, `t`.`Discriminator`, `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t1`.`Id`, `t1`.`Name`, `t1`.`BaseId`, `t1`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `n`.`Id`, `n`.`Name`, `n`.`ParentCollectionId`, `n`.`ParentReferenceId`, 'NestedCollectionBase' AS `Discriminator` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`Name`, `n0`.`ParentCollectionId`, `n0`.`ParentReferenceId`, 'NestedCollectionDerived' AS `Discriminator` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId`, `b`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t0` ON `t`.`ParentCollectionId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id`, `b0`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id`, `d1`.`Name`, `d1`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d1` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `n`.`Id`, `n`.`ParentCollectionId` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`ParentCollectionId` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t0` ON `t`.`ParentCollectionId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t1`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `n`.`Id`, `n`.`ParentCollectionId` + FROM `NestedCollections` AS `n` + UNION ALL + SELECT `n0`.`Id`, `n0`.`ParentCollectionId` + FROM `NestedCollectionsDerived` AS `n0` +) AS `t` +LEFT JOIN ( + SELECT `b`.`Id`, `b`.`BaseParentId` + FROM `BaseCollectionsOnBase` AS `b` + UNION ALL + SELECT `d1`.`Id`, `d1`.`BaseParentId` + FROM `DerivedCollectionsOnBase` AS `d1` +) AS `t0` ON `t`.`ParentCollectionId` = `t0`.`Id` +LEFT JOIN ( + SELECT `b0`.`Id` + FROM `BaseEntities` AS `b0` + UNION ALL + SELECT `d2`.`Id` + FROM `DerivedEntities` AS `d2` +) AS `t1` ON `t0`.`BaseParentId` = `t1`.`Id` +LEFT JOIN `OwnedReferences` AS `o` ON `t1`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t1`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t1`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +ORDER BY `t`.`Id`, `t0`.`Id`, `t1`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override async Task Nested_include_collection_reference_on_non_entity_base_split(bool async) + { + await base.Nested_include_collection_reference_on_non_entity_base_split(async); + + AssertSql( +""" +SELECT `r`.`Id`, `r`.`Name` +FROM `ReferencedEntities` AS `r` +ORDER BY `r`.`Id` +""", + // + """ +SELECT `t`.`Id`, `t`.`Name`, `t`.`ReferenceId`, `t`.`ReferencedEntityId`, `t`.`Id0`, `t`.`Name0`, `r`.`Id` +FROM `ReferencedEntities` AS `r` +INNER JOIN ( + SELECT `p`.`Id`, `p`.`Name`, `p`.`ReferenceId`, `p`.`ReferencedEntityId`, `r0`.`Id` AS `Id0`, `r0`.`Name` AS `Name0` + FROM `PrincipalEntities` AS `p` + LEFT JOIN `ReferencedEntities` AS `r0` ON `p`.`ReferenceId` = `r0`.`Id` +) AS `t` ON `r`.`Id` = `t`.`ReferencedEntityId` +ORDER BY `r`.`Id` +"""); + } + + public override async Task Collection_projection_on_base_type_split(bool async) + { + await base.Collection_projection_on_base_type_split(async); + + AssertSql( +""" +SELECT `t`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d`.`Id` + FROM `DerivedEntities` AS `d` +) AS `t` +ORDER BY `t`.`Id` +""", + // + """ +SELECT `t0`.`Id`, `t0`.`BaseParentId`, `t0`.`Name`, `t0`.`DerivedProperty`, `t0`.`Discriminator`, `t`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d`.`Id` + FROM `DerivedEntities` AS `d` +) AS `t` +INNER JOIN ( + SELECT `b0`.`Id`, `b0`.`BaseParentId`, `b0`.`Name`, NULL AS `DerivedProperty`, 'BaseCollectionOnBase' AS `Discriminator` + FROM `BaseCollectionsOnBase` AS `b0` + UNION ALL + SELECT `d0`.`Id`, `d0`.`BaseParentId`, `d0`.`Name`, `d0`.`DerivedProperty`, 'DerivedCollectionOnBase' AS `Discriminator` + FROM `DerivedCollectionsOnBase` AS `d0` +) AS `t0` ON `t`.`Id` = `t0`.`BaseParentId` +ORDER BY `t`.`Id` +"""); + } + + public override async Task Include_on_derived_type_with_queryable_Cast_split(bool async) + { + await base.Include_on_derived_type_with_queryable_Cast_split(async); + + AssertSql( +""" +SELECT `t`.`Id`, `t`.`Name`, `t`.`BaseId`, `t`.`Discriminator`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id`, `o`.`Id`, `o`.`Name`, `d`.`OwnedReferenceOnDerived_Id`, `d`.`OwnedReferenceOnDerived_Name` +FROM ( + SELECT `b`.`Id`, `b`.`Name`, NULL AS `BaseId`, 'BaseInheritanceRelationshipEntity' AS `Discriminator` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`BaseId`, 'DerivedInheritanceRelationshipEntity' AS `Discriminator` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +WHERE `t`.`Id` >= 4 +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `o0`.`BaseInheritanceRelationshipEntityId`, `o0`.`Id`, `o0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d0`.`Id` + FROM `DerivedEntities` AS `d0` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `OwnedCollections` AS `o0` ON `t`.`Id` = `o0`.`BaseInheritanceRelationshipEntityId` +WHERE `t`.`Id` >= 4 +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`DerivedInheritanceRelationshipEntityId`, `d0`.`Id`, `d0`.`Name`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedEntities_OwnedCollectionOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE `t`.`Id` >= 4 +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +""", + // + """ +SELECT `d0`.`Id`, `d0`.`Name`, `d0`.`ParentId`, `d0`.`DerivedInheritanceRelationshipEntityId`, `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +FROM ( + SELECT `b`.`Id` + FROM `BaseEntities` AS `b` + UNION ALL + SELECT `d1`.`Id` + FROM `DerivedEntities` AS `d1` +) AS `t` +LEFT JOIN `OwnedReferences` AS `o` ON `t`.`Id` = `o`.`BaseInheritanceRelationshipEntityId` +LEFT JOIN `DerivedEntities` AS `d` ON `t`.`Id` = `d`.`Id` +INNER JOIN `DerivedCollectionsOnDerived` AS `d0` ON `t`.`Id` = `d0`.`DerivedInheritanceRelationshipEntityId` +WHERE `t`.`Id` >= 4 +ORDER BY `t`.`Id`, `o`.`BaseInheritanceRelationshipEntityId`, `d`.`Id` +"""); + } + + public override void Entity_can_make_separate_relationships_with_base_type_and_derived_type_both() + { + base.Entity_can_make_separate_relationships_with_base_type_and_derived_type_both(); + + AssertSql(); + } + + private void AssertSql(params string[] expected) + => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + + public class TPCRelationshipsQueryMySqlFixture : TPCRelationshipsQueryRelationalFixture + { + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + } +} diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPTGearsOfWarQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPTGearsOfWarQueryMySqlTest.cs index 37fae90d8..5326d7566 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/TPTGearsOfWarQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/TPTGearsOfWarQueryMySqlTest.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; using Xunit; @@ -27,7 +28,7 @@ protected override bool CanExecuteQueryString public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool async) { - var dto = GearsOfWarQueryMySqlFixture.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); + var dto = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); var start = dto.AddDays(-1); var end = dto.AddDays(1); var dates = new[] { dto }; @@ -40,7 +41,7 @@ public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool async) public override Task Where_datetimeoffset_milliseconds_parameter_and_constant(bool async) { - var dateTimeOffset = GearsOfWarQueryMySqlFixture.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); + var dateTimeOffset = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); // Literal where clause var p = Expression.Parameter(typeof(Mission), "i"); @@ -56,6 +57,25 @@ public override Task Where_datetimeoffset_milliseconds_parameter_and_constant(bo ss => ss.Set().Where(m => m.Timeline == dateTimeOffset)); } + [ConditionalTheory(Skip = "TODO: Does not work as expected, probably due to some test definition issues.")] + public override async Task DateTimeOffsetNow_minus_timespan(bool async) + { + var timeSpan = new TimeSpan(10000); // <-- changed from 1000 to 10000 ticks + + await AssertQuery( + async, + ss => ss.Set().Where(e => e.Timeline > DateTimeOffset.Now - timeSpan)); + + AssertSql( +""" +@__timeSpan_0='00:00:00.0010000' (DbType = DateTimeOffset) + +SELECT `m`.`Id`, `m`.`CodeName`, `m`.`Date`, `m`.`Duration`, `m`.`Rating`, `m`.`Time`, `m`.`Timeline` +FROM `Missions` AS `m` +WHERE `m`.`Timeline` > (UTC_TIMESTAMP() - @__timeSpan_0) +"""); + } + // TODO: Implement strategy as discussed with @roji (including emails) for EF Core 5. [ConditionalTheory(Skip = "#996")] public override Task Client_member_and_unsupported_string_Equals_in_the_same_query(bool async) @@ -212,5 +232,18 @@ public override Task Subquery_projecting_non_nullable_scalar_contains_non_nullab { return base.Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion(async); } + + [ConditionalTheory(Skip = "Another LATERAL JOIN bug in MySQL. Grouping leads to unexpected result set.")] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(bool async) + { + return base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); + } + + private string AssertSql(string expected) + { + Fixture.TestSqlLoggerFactory.AssertBaseline(new[] {expected}); + return expected; + } } } diff --git a/test/EFCore.MySql.FunctionalTests/Query/ToSqlQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/ToSqlQueryMySqlTest.cs new file mode 100644 index 000000000..6f0e1108e --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Query/ToSqlQueryMySqlTest.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Query; + +public class ToSqlQueryMySqlTest : ToSqlQueryTestBase +{ + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + [ConditionalFact] + public virtual void Check_all_tests_overridden() + => TestHelpers.AssertAllMethodsOverridden(GetType()); + + public override async Task Entity_type_with_navigation_mapped_to_SqlQuery(bool async) + { + await base.Entity_type_with_navigation_mapped_to_SqlQuery(async); + + AssertSql( +""" +SELECT `a`.`Id`, `a`.`Name`, `a`.`PostStatAuthorId`, `m`.`Count` AS `PostCount` +FROM `Authors` AS `a` +LEFT JOIN ( + SELECT * FROM PostStats +) AS `m` ON `a`.`PostStatAuthorId` = `m`.`AuthorId` +"""); + } + + private void AssertSql(params string[] expected) + => TestSqlLoggerFactory.AssertBaseline(expected); +} diff --git a/test/EFCore.MySql.FunctionalTests/QueryExpressionInterceptionNpgsqlTestBase.cs b/test/EFCore.MySql.FunctionalTests/QueryExpressionInterceptionNpgsqlTestBase.cs new file mode 100644 index 000000000..9acda278d --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/QueryExpressionInterceptionNpgsqlTestBase.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.Extensions.DependencyInjection; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Storage.Internal; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests; + +public abstract class QueryExpressionInterceptionMySqlTestBase : QueryExpressionInterceptionTestBase +{ + protected QueryExpressionInterceptionMySqlTestBase(InterceptionMySqlFixtureBase fixture) + : base(fixture) + { + } + + public abstract class InterceptionMySqlFixtureBase : InterceptionFixtureBase + { + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + protected override IServiceCollection InjectInterceptors( + IServiceCollection serviceCollection, + IEnumerable injectedInterceptors) + => base.InjectInterceptors(serviceCollection.AddEntityFrameworkMySql(), injectedInterceptors); + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + { + new MySqlDbContextOptionsBuilder(base.AddOptions(builder)) + .ExecutionStrategy(d => new MySqlExecutionStrategy(d)); + return builder; + } + } + + public class QueryExpressionInterceptionMySqlTest + : QueryExpressionInterceptionMySqlTestBase, IClassFixture + { + public QueryExpressionInterceptionMySqlTest(InterceptionMySqlFixture fixture) + : base(fixture) + { + } + + public class InterceptionMySqlFixture : InterceptionMySqlFixtureBase + { + protected override string StoreName + => "QueryExpressionInterception"; + + protected override bool ShouldSubscribeToDiagnosticListener + => false; + } + } + + public class QueryExpressionInterceptionWithDiagnosticsMySqlTest + : QueryExpressionInterceptionMySqlTestBase, + IClassFixture + { + public QueryExpressionInterceptionWithDiagnosticsMySqlTest(InterceptionMySqlFixture fixture) + : base(fixture) + { + } + + public class InterceptionMySqlFixture : InterceptionMySqlFixtureBase + { + protected override string StoreName + => "QueryExpressionInterceptionWithDiagnostics"; + + protected override bool ShouldSubscribeToDiagnosticListener + => true; + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/StoreGeneratedMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/StoreGeneratedMySqlTest.cs index 5ce40ef2d..49ad910ce 100644 --- a/test/EFCore.MySql.FunctionalTests/StoreGeneratedMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/StoreGeneratedMySqlTest.cs @@ -122,6 +122,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().Property(e => e.HasTemp).HasDefaultValue(777); + modelBuilder.Entity().Property(e => e.Id).UseMySqlIdentityColumn(); + base.OnModelCreating(modelBuilder, context); } } diff --git a/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlDatabaseCleaner.cs b/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlDatabaseCleaner.cs index 5944e2af0..2d6a52d3b 100644 --- a/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlDatabaseCleaner.cs +++ b/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlDatabaseCleaner.cs @@ -1,13 +1,20 @@ -using Pomelo.EntityFrameworkCore.MySql.Scaffolding.Internal; +using System; +using System.Collections.Generic; +using Pomelo.EntityFrameworkCore.MySql.Scaffolding.Internal; using Microsoft.EntityFrameworkCore.Scaffolding; using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.Extensions.Logging; using Pomelo.EntityFrameworkCore.MySql.Diagnostics.Internal; using System.Diagnostics; +using System.Linq; +using System.Text; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics.Internal; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Storage; using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; @@ -24,6 +31,57 @@ public MySqlDatabaseCleaner(IMySqlOptions options, IRelationalTypeMappingSource _relationalTypeMappingSource = relationalTypeMappingSource; } + public override void Clean(DatabaseFacade facade) + { + var creator = facade.GetService(); + var connection = facade.GetService(); + + if (creator.Exists()) + { + OpenConnection(connection); + + try + { + var commands = new StringBuilder(); + + var getRoutinesSql = $@" +SELECT `ROUTINE_SCHEMA`, `ROUTINE_NAME`, `ROUTINE_TYPE` +FROM `INFORMATION_SCHEMA`.`ROUTINES` +WHERE `ROUTINE_SCHEMA` = SCHEMA();"; + + using var command = connection.DbConnection.CreateCommand(); + command.CommandText = getRoutinesSql; + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + if (string.Equals(reader["ROUTINE_TYPE"] as string, "PROCEDURE", StringComparison.OrdinalIgnoreCase)) + { + commands.AppendLine($"DROP PROCEDURE IF EXISTS `{reader["ROUTINE_SCHEMA"]}`.`{reader["ROUTINE_NAME"]}`;"); + } + else if (string.Equals(reader["ROUTINE_TYPE"] as string, "FUNCTION", StringComparison.OrdinalIgnoreCase)) + { + commands.AppendLine($"DROP FUNCTION IF EXISTS `{reader["ROUTINE_SCHEMA"]}`.`{reader["ROUTINE_NAME"]}`;"); + } + } + } + + if (commands.Length > 0) + { + command.CommandText = commands.ToString(); + command.ExecuteNonQuery(); + } + } + finally + { + connection.Close(); + } + } + + base.Clean(facade); + } + protected override IDatabaseModelFactory CreateDatabaseModelFactory(ILoggerFactory loggerFactory) => new MySqlDatabaseModelFactory( new DiagnosticsLogger( diff --git a/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestHelpers.cs b/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestHelpers.cs index cd883275b..7dbc797fc 100644 --- a/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestHelpers.cs +++ b/test/EFCore.MySql.FunctionalTests/TestUtilities/MySqlTestHelpers.cs @@ -12,7 +12,7 @@ //ReSharper disable once CheckNamespace namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities { - public class MySqlTestHelpers : TestHelpers + public class MySqlTestHelpers : RelationalTestHelpers { protected MySqlTestHelpers() { @@ -23,7 +23,7 @@ protected MySqlTestHelpers() public override IServiceCollection AddProviderServices(IServiceCollection services) => services.AddEntityFrameworkMySql(); - public override void UseProviderOptions(DbContextOptionsBuilder optionsBuilder) + public override DbContextOptionsBuilder UseProviderOptions(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseMySql("Database=DummyDatabase", AppConfig.ServerVersion); public IServiceProvider CreateContextServices(ServerVersion serverVersion) @@ -94,5 +94,27 @@ public void EnsureSufficientKeySpace(IMutableModel model, TestStore testStore = public int GetIndexedStringPropertyDefaultLength => Math.Min(AppConfig.ServerVersion.MaxKeyLength / (CharSet.Utf8Mb4.MaxBytesPerChar * 2), 255); + + public static DateTimeOffset GetExpectedValue(DateTimeOffset value) + { + const int mySqlMaxMillisecondDecimalPlaces = 6; + var decimalPlacesFactor = (decimal)Math.Pow(10, 7 - mySqlMaxMillisecondDecimalPlaces); + + // Change DateTimeOffset values, because MySQL does not preserve offsets and has a maximum of 6 decimal places, in contrast to + // .NET which has 7. + return new DateTimeOffset( + (long)(Math.Truncate(value.UtcTicks / decimalPlacesFactor) * decimalPlacesFactor), + TimeSpan.Zero); + } + + public static string CastAsDouble(string innerSql) + => AppConfig.ServerVersion.Supports.DoubleCast + ? $@"CAST({innerSql} AS double)" + : $@"(CAST({innerSql} AS decimal(65,30)) + 0e0)"; + + public static string MySqlBug96947Workaround(string innerSql, string type = "char") + => AppConfig.ServerVersion.Supports.MySqlBug96947Workaround + ? $@"CAST({innerSql} AS {type})" + : innerSql; } } diff --git a/test/EFCore.MySql.FunctionalTests/TestUtilities/Xunit/MySqlXunitTestRunner.cs b/test/EFCore.MySql.FunctionalTests/TestUtilities/Xunit/MySqlXunitTestRunner.cs index 58dd87eb4..bf51cb1f4 100644 --- a/test/EFCore.MySql.FunctionalTests/TestUtilities/Xunit/MySqlXunitTestRunner.cs +++ b/test/EFCore.MySql.FunctionalTests/TestUtilities/Xunit/MySqlXunitTestRunner.cs @@ -142,7 +142,8 @@ innerException is not InvalidOperationException || skip &= !supports.OuterApply && innerException.Message.Contains("OUTER APPLY") || !supports.CrossApply && innerException.Message.Contains("CROSS APPLY") || - !supports.WindowFunctions && innerException.Message.Contains("ROW_NUMBER() OVER"); + !supports.WindowFunctions && innerException.Message.Contains("ROW_NUMBER() OVER") || + !supports.ExceptIntercept && (innerException.Message.Contains("EXCEPT") || innerException.Message.Contains("INTERSECT")); } return skip; diff --git a/test/EFCore.MySql.FunctionalTests/TwoDatabasesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/TwoDatabasesMySqlTest.cs index 92d3e0848..774791eef 100644 --- a/test/EFCore.MySql.FunctionalTests/TwoDatabasesMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/TwoDatabasesMySqlTest.cs @@ -16,9 +16,13 @@ public TwoDatabasesMySqlTest(MySqlFixture fixture) => (MySqlFixture)base.Fixture; protected override DbContextOptionsBuilder CreateTestOptions( - DbContextOptionsBuilder optionsBuilder, bool withConnectionString = false) + DbContextOptionsBuilder optionsBuilder, + bool withConnectionString = false, + bool withNullConnectionString = false) => withConnectionString - ? optionsBuilder.UseMySql(DummyConnectionString, AppConfig.ServerVersion) + ? withNullConnectionString + ? optionsBuilder.UseMySql((string)null, AppConfig.ServerVersion) + : optionsBuilder.UseMySql(DummyConnectionString, AppConfig.ServerVersion) : optionsBuilder.UseMySql(AppConfig.ServerVersion); protected override TwoDatabasesWithDataContext CreateBackingContext(string databaseName) diff --git a/test/EFCore.MySql.FunctionalTests/Update/MySqlUpdateSqlGeneratorTest.cs b/test/EFCore.MySql.FunctionalTests/Update/MySqlUpdateSqlGeneratorTest.cs index 23c2121c1..6a5945074 100644 --- a/test/EFCore.MySql.FunctionalTests/Update/MySqlUpdateSqlGeneratorTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Update/MySqlUpdateSqlGeneratorTest.cs @@ -1,11 +1,20 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Text; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.EntityFrameworkCore.Update; +using Microsoft.Extensions.DependencyInjection; using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; using Pomelo.EntityFrameworkCore.MySql.Internal; using Pomelo.EntityFrameworkCore.MySql.Storage.Internal; +using Pomelo.EntityFrameworkCore.MySql.Tests; using Pomelo.EntityFrameworkCore.MySql.Update.Internal; using Xunit; @@ -16,7 +25,8 @@ public class MySqlUpdateSqlGeneratorTest : UpdateSqlGeneratorTestBase { protected override IUpdateSqlGenerator CreateSqlGenerator() { - var options = new MySqlOptions(); + var options = GetOptions(); + return new MySqlUpdateSqlGenerator( new UpdateSqlGeneratorDependencies( new MySqlSqlGenerationHelper( @@ -25,12 +35,140 @@ protected override IUpdateSqlGenerator CreateSqlGenerator() new MySqlTypeMappingSource( TestServiceFactory.Instance.Create(), TestServiceFactory.Instance.Create(), - options))); + options)), + options); + } + + private static MySqlOptions GetOptions() + { + var optionsBuilder = new DbContextOptionsBuilder(); + + var extension = new MySqlOptionsExtension() + .WithServerVersion(AppConfig.ServerVersion); + + ((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension); + + var options = new MySqlOptions(); + options.Initialize(optionsBuilder.Options); + return options; } protected override TestHelpers TestHelpers => MySqlTestHelpers.Instance; + #region Methods, that depend on RETURNING clause or OnAdd + + protected new IModificationCommand CreateInsertCommand(bool identityKey = true, bool isComputed = true, bool defaultsOnly = false) + { + var model = GetDuckModel(); + var stateManager = TestHelpers.CreateContextServices(model).GetRequiredService(); + var entry = stateManager.GetOrCreateEntry(new Duck()); + entry.SetEntityState(EntityState.Added); + var generator = new ParameterNameGenerator(); + + var duckType = model.FindEntityType(typeof(Duck)); + var idProperty = duckType.FindProperty(nameof(Duck.Id)); + var nameProperty = duckType.FindProperty(nameof(Duck.Name)); + var quacksProperty = duckType.FindProperty(nameof(Duck.Quacks)); + var computedProperty = duckType.FindProperty(nameof(Duck.Computed)); + var concurrencyProperty = duckType.FindProperty(nameof(Duck.ConcurrencyToken)); + + var columnModifications = new[] + { + new ColumnModificationParameters( + entry, idProperty, idProperty.GetTableColumnMappings().Single().Column, generator.GenerateNext, + idProperty.GetTableColumnMappings().Single().TypeMapping, identityKey, !identityKey, true, false, true), + new ColumnModificationParameters( + entry, nameProperty, nameProperty.GetTableColumnMappings().Single().Column, generator.GenerateNext, + nameProperty.GetTableColumnMappings().Single().TypeMapping, false, true, false, false, true), + new ColumnModificationParameters( + entry, quacksProperty, quacksProperty.GetTableColumnMappings().Single().Column, generator.GenerateNext, + quacksProperty.GetTableColumnMappings().Single().TypeMapping, false, true, false, false, true), + new ColumnModificationParameters( + entry, computedProperty, computedProperty.GetTableColumnMappings().Single().Column, generator.GenerateNext, + computedProperty.GetTableColumnMappings().Single().TypeMapping, isComputed, false, false, false, true), + new ColumnModificationParameters( + entry, concurrencyProperty, concurrencyProperty.GetTableColumnMappings().Single().Column, generator.GenerateNext, + concurrencyProperty.GetTableColumnMappings().Single().TypeMapping, false, true, false, false, true) + }; + + if (defaultsOnly) + { + columnModifications = columnModifications.Where(c => !c.IsWrite).ToArray(); + } + + return CreateModificationCommand(entry, columnModifications, false); + } + + private IModificationCommand CreateModificationCommand( + InternalEntityEntry entry, + IReadOnlyList columnModifications, + bool sensitiveLoggingEnabled) + { + var modificationCommandParameters = new ModificationCommandParameters( + entry.EntityType.GetTableMappings().Single().Table, sensitiveLoggingEnabled); + var modificationCommand = CreateMutableModificationCommandFactory().CreateModificationCommand( + modificationCommandParameters); + + modificationCommand.AddEntry(entry, mainEntry: true); + + foreach (var columnModification in columnModifications) + { + ((INonTrackedModificationCommand)modificationCommand).AddColumnModification(columnModification); + } + + return modificationCommand; + } + + private IModel GetDuckModel() + { + var modelBuilder = TestHelpers.CreateConventionBuilder(); + modelBuilder.Entity().ToTable("Ducks", Schema).Property(e => e.Id)/*.ValueGeneratedNever()*/; + return modelBuilder.Model.FinalizeModel(); + } + + public override void AppendInsertOperation_for_only_identity() + { + var stringBuilder = new StringBuilder(); + var command = CreateInsertCommand(true, false); + + CreateSqlGenerator().AppendInsertOperation(stringBuilder, command, 0); + + AppendInsertOperation_for_only_identity_verification(stringBuilder); + } + + public override void AppendInsertOperation_for_all_store_generated_columns() + { + var stringBuilder = new StringBuilder(); + var command = CreateInsertCommand(true, true, true); + + CreateSqlGenerator().AppendInsertOperation(stringBuilder, command, 0); + + AppendInsertOperation_for_all_store_generated_columns_verification(stringBuilder); + } + + public override void AppendInsertOperation_for_only_single_identity_columns() + { + var stringBuilder = new StringBuilder(); + var command = CreateInsertCommand(identityKey: true, isComputed: false, defaultsOnly: true); + + CreateSqlGenerator().AppendInsertOperation(stringBuilder, command, 0); + + AppendInsertOperation_for_only_single_identity_columns_verification(stringBuilder); + } + + public override void AppendInsertOperation_insert_if_store_generated_columns_exist() + { + var stringBuilder = new StringBuilder(); + var command = CreateInsertCommand(); + + CreateSqlGenerator().AppendInsertOperation(stringBuilder, command, 0); + + AppendInsertOperation_insert_if_store_generated_columns_exist_verification(stringBuilder); + } + + #endregion + [ConditionalFact] public void AppendBulkInsertOperation_appends_insert_if_store_generated_columns_exist() { @@ -38,10 +176,24 @@ public void AppendBulkInsertOperation_appends_insert_if_store_generated_columns_ var command = CreateInsertCommand(); var sqlGenerator = (IMySqlUpdateSqlGenerator)CreateSqlGenerator(); - var grouping = sqlGenerator.AppendBulkInsertOperation(stringBuilder, new[] { command, command }, 0); + var grouping = sqlGenerator.AppendBulkInsertOperation(stringBuilder, new[] { command, command }, 0, out _); - AssertBaseline( - @"INSERT INTO `Ducks` (`Name`, `Quacks`, `ConcurrencyToken`) + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertBaseline( + @"INSERT INTO `Ducks` (`Name`, `Quacks`, `ConcurrencyToken`) +VALUES (@p0, @p1, @p2) +RETURNING `Id`, `Computed`; +INSERT INTO `Ducks` (`Name`, `Quacks`, `ConcurrencyToken`) +VALUES (@p0, @p1, @p2) +RETURNING `Id`, `Computed`; +", + stringBuilder.ToString()); + } + else + { + AssertBaseline( + @"INSERT INTO `Ducks` (`Name`, `Quacks`, `ConcurrencyToken`) VALUES (@p0, @p1, @p2); SELECT `Id`, `Computed` FROM `Ducks` @@ -54,7 +206,9 @@ public void AppendBulkInsertOperation_appends_insert_if_store_generated_columns_ WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); ", - stringBuilder.ToString()); + stringBuilder.ToString()); + } + Assert.Equal(ResultSetMapping.LastInResultSet, grouping); } @@ -65,7 +219,7 @@ public void AppendBulkInsertOperation_appends_insert_if_no_store_generated_colum var command = CreateInsertCommand(identityKey: false, isComputed: false); var sqlGenerator = (IMySqlUpdateSqlGenerator)CreateSqlGenerator(); - var grouping = sqlGenerator.AppendBulkInsertOperation(stringBuilder, new[] { command, command }, 0); + var grouping = sqlGenerator.AppendBulkInsertOperation(stringBuilder, new[] { command, command }, 0, out _); AssertBaseline( @"INSERT INTO `Ducks` (`Id`, `Name`, `Quacks`, `ConcurrencyToken`) @@ -73,7 +227,7 @@ public void AppendBulkInsertOperation_appends_insert_if_no_store_generated_colum (@p0, @p1, @p2, @p3); ", stringBuilder.ToString()); - Assert.Equal(ResultSetMapping.NoResultSet, grouping); + Assert.Equal(ResultSetMapping.NoResults, grouping); } [ConditionalFact] @@ -83,10 +237,24 @@ public void AppendBulkInsertOperation_appends_insert_if_store_generated_columns_ var command = CreateInsertCommand(identityKey: true, isComputed: true, defaultsOnly: true); var sqlGenerator = (IMySqlUpdateSqlGenerator)CreateSqlGenerator(); - var grouping = sqlGenerator.AppendBulkInsertOperation(stringBuilder, new[] { command, command }, 0); + var grouping = sqlGenerator.AppendBulkInsertOperation(stringBuilder, new[] { command, command }, 0, out _); - AssertBaseline( - @"INSERT INTO `Ducks` () + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertBaseline( + @"INSERT INTO `Ducks` () +VALUES () +RETURNING `Id`, `Computed`; +INSERT INTO `Ducks` () +VALUES () +RETURNING `Id`, `Computed`; +", + stringBuilder.ToString()); + } + else + { + AssertBaseline( + @"INSERT INTO `Ducks` () VALUES (); SELECT `Id`, `Computed` FROM `Ducks` @@ -99,7 +267,8 @@ public void AppendBulkInsertOperation_appends_insert_if_store_generated_columns_ WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); ", - stringBuilder.ToString()); + stringBuilder.ToString()); + } Assert.Equal(ResultSetMapping.LastInResultSet, grouping); } @@ -110,25 +279,142 @@ public void AppendBulkInsertOperation_appends_insert_if_no_store_generated_colum var command = CreateInsertCommand(identityKey: false, isComputed: false, defaultsOnly: true); var sqlGenerator = (IMySqlUpdateSqlGenerator)CreateSqlGenerator(); - var grouping = sqlGenerator.AppendBulkInsertOperation(stringBuilder, new[] { command, command }, 0); - - var expectedText = @"INSERT INTO " - + SchemaPrefix - + OpenDelimiter - + "Ducks" - + CloseDelimiter - + NoColumns - + Environment.NewLine - + DefaultValues - + ";" - + Environment.NewLine; + var grouping = sqlGenerator.AppendBulkInsertOperation(stringBuilder, new[] { command, command }, 0, out _); + + var expectedText = @"INSERT INTO `Ducks` () +VALUES (), +(); +"; AssertBaseline( - expectedText + expectedText, + expectedText, stringBuilder.ToString()); - Assert.Equal(ResultSetMapping.NoResultSet, grouping); + Assert.Equal(ResultSetMapping.NoResults, grouping); + } + + protected override void AppendDeleteOperation_creates_full_delete_command_text_verification(StringBuilder stringBuilder) + { + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertBaseline( + @"DELETE FROM `Ducks` +WHERE `Id` = @p0 +RETURNING 1; +", + stringBuilder.ToString()); + } + else + { + AssertBaseline( + @"DELETE FROM `Ducks` +WHERE `Id` = @p0; +SELECT ROW_COUNT(); + +", + stringBuilder.ToString()); + } + } + + protected override void AppendDeleteOperation_creates_full_delete_command_text_with_concurrency_check_verification( + StringBuilder stringBuilder) + { + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertBaseline( + @"DELETE FROM `Ducks` +WHERE `Id` = @p0 AND `ConcurrencyToken` IS NULL +RETURNING 1; +", + stringBuilder.ToString()); + } + else + { + AssertBaseline( + @"DELETE FROM `Ducks` +WHERE `Id` = @p0 AND `ConcurrencyToken` IS NULL; +SELECT ROW_COUNT(); + +", + stringBuilder.ToString()); + } } - protected override void AppendInsertOperation_appends_insert_and_select_for_all_store_generated_columns_verification( + protected override void AppendInsertOperation_insert_if_store_generated_columns_exist_verification(StringBuilder stringBuilder) + { + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertBaseline( + @"INSERT INTO `Ducks` (`Name`, `Quacks`, `ConcurrencyToken`) +VALUES (@p0, @p1, @p2) +RETURNING `Id`, `Computed`; +", + stringBuilder.ToString()); + } + else + { + AssertBaseline( + @"INSERT INTO `Ducks` (`Name`, `Quacks`, `ConcurrencyToken`) +VALUES (@p0, @p1, @p2); +SELECT `Id`, `Computed` +FROM `Ducks` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); + +", + stringBuilder.ToString()); + } + } + + protected override void AppendInsertOperation_for_store_generated_columns_but_no_identity_verification( + StringBuilder stringBuilder) + { + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertBaseline( + @"INSERT INTO `Ducks` (`Id`, `Name`, `Quacks`, `ConcurrencyToken`) +VALUES (@p0, @p1, @p2, @p3) +RETURNING `Computed`; +", + stringBuilder.ToString()); + } + else + { + AssertBaseline( + @"INSERT INTO `Ducks` (`Id`, `Name`, `Quacks`, `ConcurrencyToken`) +VALUES (@p0, @p1, @p2, @p3); +SELECT `Computed` +FROM `Ducks` +WHERE ROW_COUNT() = 1 AND `Id` = @p0; + +", + stringBuilder.ToString()); + + } + } + + protected override void AppendInsertOperation_for_only_identity_verification(StringBuilder stringBuilder) + { + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertBaseline( + @"INSERT INTO `Ducks` (`Name`, `Quacks`, `ConcurrencyToken`) +VALUES (@p0, @p1, @p2) +RETURNING `Id`;", + stringBuilder.ToString()); + } + else + { + AssertBaseline( + @"INSERT INTO `Ducks` (`Name`, `Quacks`, `ConcurrencyToken`) +VALUES (@p0, @p1, @p2); +SELECT `Id` +FROM `Ducks` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); + +", + stringBuilder.ToString()); + } + } + + protected override void AppendInsertOperation_for_all_store_generated_columns_verification( StringBuilder stringBuilder) { Assert.Equal( @@ -139,37 +425,41 @@ protected override void AppendInsertOperation_appends_insert_and_select_for_all_ + CloseDelimiter + NoColumns // added + Environment.NewLine - + DefaultValues // changed from - + ";" // "DEFAULT VALUES;" - + Environment.NewLine - + "SELECT " - + OpenDelimiter - + "Id" - + CloseDelimiter - + ", " - + OpenDelimiter - + "Computed" - + CloseDelimiter - + "" - + Environment.NewLine - + "FROM " - + SchemaPrefix - + OpenDelimiter - + "Ducks" - + CloseDelimiter - + "" - + Environment.NewLine - + "WHERE " - + RowsAffected - + " = 1 AND " - + GetIdentityWhereCondition("Id") - + ";" - + Environment.NewLine - + Environment.NewLine, + + DefaultValues // changed from "DEFAULT VALUES;" + + (AppConfig.ServerVersion.Supports.Returning + ? Environment.NewLine + + "RETURNING `Id`, `Computed`;" + + Environment.NewLine + : ";" + + Environment.NewLine + + "SELECT " + + OpenDelimiter + + "Id" + + CloseDelimiter + + ", " + + OpenDelimiter + + "Computed" + + CloseDelimiter + + "" + + Environment.NewLine + + "FROM " + + SchemaPrefix + + OpenDelimiter + + "Ducks" + + CloseDelimiter + + "" + + Environment.NewLine + + "WHERE " + + RowsAffected + + " = 1 AND " + + GetIdentityWhereCondition("Id") + + ";" + + Environment.NewLine + + Environment.NewLine), stringBuilder.ToString()); } - protected override void AppendInsertOperation_appends_insert_and_select_for_only_single_identity_columns_verification( + protected override void AppendInsertOperation_for_only_single_identity_columns_verification( StringBuilder stringBuilder) { Assert.Equal( @@ -180,32 +470,80 @@ protected override void AppendInsertOperation_appends_insert_and_select_for_only + CloseDelimiter + NoColumns // added + Environment.NewLine - + DefaultValues // changed from - + ";" // "DEFAULT VALUES;" - + Environment.NewLine - + "SELECT " - + OpenDelimiter - + "Id" - + CloseDelimiter - + "" - + Environment.NewLine - + "FROM " - + SchemaPrefix - + OpenDelimiter - + "Ducks" - + CloseDelimiter - + "" - + Environment.NewLine - + "WHERE " - + RowsAffected - + " = 1 AND " - + GetIdentityWhereCondition("Id") - + ";" - + Environment.NewLine - + Environment.NewLine, + + DefaultValues // changed from "DEFAULT VALUES;" + + (AppConfig.ServerVersion.Supports.Returning + ? Environment.NewLine + + "RETURNING `Id`;" + + Environment.NewLine + : ";" + + Environment.NewLine + + "SELECT " + + OpenDelimiter + + "Id" + + CloseDelimiter + + "" + + Environment.NewLine + + "FROM " + + SchemaPrefix + + OpenDelimiter + + "Ducks" + + CloseDelimiter + + "" + + Environment.NewLine + + "WHERE " + + RowsAffected + + " = 1 AND " + + GetIdentityWhereCondition("Id") + + ";" + + Environment.NewLine + + Environment.NewLine), stringBuilder.ToString()); } + protected override void AppendUpdateOperation_if_store_generated_columns_exist_verification( + StringBuilder stringBuilder) + => AssertBaseline( + @"UPDATE `Ducks` SET `Name` = @p0, `Quacks` = @p1, `ConcurrencyToken` = @p2 +WHERE `Id` = @p3 AND `ConcurrencyToken` IS NULL; +SELECT `Computed` +FROM `Ducks` +WHERE ROW_COUNT() = 1 AND `Id` = @p3; + +", + stringBuilder.ToString()); + + protected override void AppendUpdateOperation_if_store_generated_columns_dont_exist_verification( + StringBuilder stringBuilder) + => AssertBaseline( + @"UPDATE `Ducks` SET `Name` = @p0, `Quacks` = @p1, `ConcurrencyToken` = @p2 +WHERE `Id` = @p3; +SELECT ROW_COUNT(); + +", + stringBuilder.ToString()); + + protected override void AppendUpdateOperation_appends_where_for_concurrency_token_verification(StringBuilder stringBuilder) + => AssertBaseline( + @"UPDATE `Ducks` SET `Name` = @p0, `Quacks` = @p1, `ConcurrencyToken` = @p2 +WHERE `Id` = @p3 AND `ConcurrencyToken` IS NULL; +SELECT ROW_COUNT(); + +", + stringBuilder.ToString()); + + protected override void AppendUpdateOperation_for_computed_property_verification(StringBuilder stringBuilder) + => AssertBaseline( + @"UPDATE `Ducks` SET `Name` = @p0, `Quacks` = @p1, `ConcurrencyToken` = @p2 +WHERE `Id` = @p3; +SELECT `Computed` +FROM `Ducks` +WHERE ROW_COUNT() = 1 AND `Id` = @p3; + +", + stringBuilder.ToString()); + + + protected override string RowsAffected => "ROW_COUNT()"; @@ -228,8 +566,6 @@ protected override string CloseDelimiter => "`"; private void AssertBaseline(string expected, string actual) - { - Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); - } + => Assert.Equal(expected.TrimEnd(), actual.TrimEnd(), ignoreLineEndingDifferences: true); } } diff --git a/test/EFCore.MySql.FunctionalTests/Update/NonSharedModelUpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Update/NonSharedModelUpdatesMySqlTest.cs new file mode 100644 index 000000000..4a27367c4 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Update/NonSharedModelUpdatesMySqlTest.cs @@ -0,0 +1,166 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.EntityFrameworkCore.Update; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Tests; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Update; + +public class NonSharedModelUpdatesMySqlTest : NonSharedModelUpdatesTestBase +{ + public override async Task Principal_and_dependent_roundtrips_with_cycle_breaking(bool async) + { + await base.Principal_and_dependent_roundtrips_with_cycle_breaking(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +@p0='AC South' (Size = 4000) + +INSERT INTO `AuthorsClub` (`Name`) +VALUES (@p0) +RETURNING `Id`; +""", + // + """ +@p1='1' +@p2='Alice' (Size = 4000) + +INSERT INTO `Author` (`AuthorsClubId`, `Name`) +VALUES (@p1, @p2) +RETURNING `Id`; +""", + // + """ +@p3='1' +@p4=NULL (Size = 4000) + +INSERT INTO `Book` (`AuthorId`, `Title`) +VALUES (@p3, @p4) +RETURNING `Id`; +""", + // + """ +SELECT `b`.`Id`, `b`.`AuthorId`, `b`.`Title`, `a`.`Id`, `a`.`AuthorsClubId`, `a`.`Name` +FROM `Book` AS `b` +INNER JOIN `Author` AS `a` ON `b`.`AuthorId` = `a`.`Id` +LIMIT 2 +""", + // + """ +@p0='AC North' (Size = 4000) + +INSERT INTO `AuthorsClub` (`Name`) +VALUES (@p0) +RETURNING `Id`; +""", + // + """ +@p1='2' +@p2='Author of the year 2023' (Size = 4000) + +INSERT INTO `Author` (`AuthorsClubId`, `Name`) +VALUES (@p1, @p2) +RETURNING `Id`; +""", + // + """ +@p4='1' +@p3='2' +@p5='1' + +UPDATE `Book` SET `AuthorId` = @p3 +WHERE `Id` = @p4; +SELECT ROW_COUNT(); + +DELETE FROM `Author` +WHERE `Id` = @p5 +RETURNING 1; +"""); + } + else + { + AssertSql( + """ +@p0='AC South' (Size = 4000) + +INSERT INTO `AuthorsClub` (`Name`) +VALUES (@p0); +SELECT `Id` +FROM `AuthorsClub` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +""", + // + """ +@p1='1' +@p2='Alice' (Size = 4000) + +INSERT INTO `Author` (`AuthorsClubId`, `Name`) +VALUES (@p1, @p2); +SELECT `Id` +FROM `Author` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +""", + // + """ +@p3='1' +@p4=NULL (Size = 4000) + +INSERT INTO `Book` (`AuthorId`, `Title`) +VALUES (@p3, @p4); +SELECT `Id` +FROM `Book` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +""", + // + """ +SELECT `b`.`Id`, `b`.`AuthorId`, `b`.`Title`, `a`.`Id`, `a`.`AuthorsClubId`, `a`.`Name` +FROM `Book` AS `b` +INNER JOIN `Author` AS `a` ON `b`.`AuthorId` = `a`.`Id` +LIMIT 2 +""", + // + """ +@p0='AC North' (Size = 4000) + +INSERT INTO `AuthorsClub` (`Name`) +VALUES (@p0); +SELECT `Id` +FROM `AuthorsClub` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +""", + // + """ +@p1='2' +@p2='Author of the year 2023' (Size = 4000) + +INSERT INTO `Author` (`AuthorsClubId`, `Name`) +VALUES (@p1, @p2); +SELECT `Id` +FROM `Author` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +""", + // + """ +@p4='1' +@p3='2' +@p5='1' + +UPDATE `Book` SET `AuthorId` = @p3 +WHERE `Id` = @p4; +SELECT ROW_COUNT(); + +DELETE FROM `Author` +WHERE `Id` = @p5; +SELECT ROW_COUNT(); +"""); + } + } + + private void AssertSql(params string[] expected) + => TestSqlLoggerFactory.AssertBaseline(expected); + + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.MySql.FunctionalTests/Update/StoreValueGenerationMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Update/StoreValueGenerationMySqlTest.cs new file mode 100644 index 000000000..c1ade3900 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Update/StoreValueGenerationMySqlTest.cs @@ -0,0 +1,673 @@ +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.EntityFrameworkCore.Update; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Tests; +using Xunit.Abstractions; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Update; + +public class StoreValueGenerationMySqlTest : StoreValueGenerationTestBase< + StoreValueGenerationMySqlTest.StoreValueGenerationMySqlFixture> +{ + public StoreValueGenerationMySqlTest(StoreValueGenerationMySqlFixture fixture, ITestOutputHelper testOutputHelper) + : base(fixture) + { + fixture.TestSqlLoggerFactory.Clear(); + // fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); + } + + protected override bool ShouldCreateImplicitTransaction( + EntityState firstOperationType, + EntityState? secondOperationType, + GeneratedValues generatedValues, + bool withSameEntityType) + { + if (AppConfig.ServerVersion.Supports.Returning) + { + return generatedValues != GeneratedValues.None && firstOperationType == EntityState.Modified || + secondOperationType is not null && !(firstOperationType == secondOperationType && + (firstOperationType == EntityState.Added && withSameEntityType && generatedValues == GeneratedValues.None)); + } + else + { + return generatedValues != GeneratedValues.None && firstOperationType != EntityState.Deleted || + secondOperationType is not null && !(firstOperationType == secondOperationType && + (firstOperationType == EntityState.Added && withSameEntityType)); + } + } + + protected override int ShouldExecuteInNumberOfCommands( + EntityState firstOperationType, + EntityState? secondOperationType, + GeneratedValues generatedValues, + bool withDatabaseGenerated) + => 1; + + #region Single operation + + public override async Task Add_with_generated_values(bool async) + { + await base.Add_with_generated_values(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + """ +@p0='1000' + +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p0) +RETURNING `Id`, `Data1`; +"""); + } + else + { + AssertSql( + """ +@p0='1000' + +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p0); +SELECT `Id`, `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +"""); + } + } + + public override async Task Add_with_no_generated_values(bool async) + { + await base.Add_with_no_generated_values(async); + + AssertSql( +""" +@p0='100' +@p1='1000' +@p2='1000' + +INSERT INTO `WithNoDatabaseGenerated` (`Id`, `Data1`, `Data2`) +VALUES (@p0, @p1, @p2); +"""); + } + + public override async Task Add_with_all_generated_values(bool async) + { + await base.Add_with_all_generated_values(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + """ +INSERT INTO `WithAllDatabaseGenerated` () +VALUES () +RETURNING `Id`, `Data1`, `Data2`; +"""); + } + else + { + AssertSql( + """ +INSERT INTO `WithAllDatabaseGenerated` () +VALUES (); +SELECT `Id`, `Data1`, `Data2` +FROM `WithAllDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +"""); + } + } + + public override async Task Modify_with_generated_values(bool async) + { + await base.Modify_with_generated_values(async); + + AssertSql( +""" +@p1='1' +@p0='1000' + +UPDATE `WithSomeDatabaseGenerated` SET `Data2` = @p0 +WHERE `Id` = @p1; +SELECT `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = @p1; +"""); + } + + public override async Task Modify_with_no_generated_values(bool async) + { + await base.Modify_with_no_generated_values(async); + + AssertSql( +""" +@p2='1' +@p0='1000' +@p1='1000' + +UPDATE `WithNoDatabaseGenerated` SET `Data1` = @p0, `Data2` = @p1 +WHERE `Id` = @p2; +SELECT ROW_COUNT(); +"""); + } + + public override async Task Delete(bool async) + { + await base.Delete(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +@p0='1' + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p0 +RETURNING 1; +"""); + } + else + { + AssertSql( +""" +@p0='1' + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p0; +SELECT ROW_COUNT(); +"""); + } + } + + #endregion Single operation + + #region Two operations with same entity type + + public override async Task Add_Add_with_same_entity_type_and_generated_values(bool async) + { + await base.Add_Add_with_same_entity_type_and_generated_values(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + """ +@p0='1000' +@p1='1001' + +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p0) +RETURNING `Id`, `Data1`; +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p1) +RETURNING `Id`, `Data1`; +"""); + } + else + { + AssertSql( + """ +@p0='1000' +@p1='1001' + +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p0); +SELECT `Id`, `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); + +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p1); +SELECT `Id`, `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +"""); + } + } + + public override async Task Add_Add_with_same_entity_type_and_no_generated_values(bool async) + { + await base.Add_Add_with_same_entity_type_and_no_generated_values(async); + + AssertSql( +""" +@p0='100' +@p1='1000' +@p2='1000' +@p3='101' +@p4='1001' +@p5='1001' + +INSERT INTO `WithNoDatabaseGenerated` (`Id`, `Data1`, `Data2`) +VALUES (@p0, @p1, @p2), +(@p3, @p4, @p5); +"""); + } + + public override async Task Add_Add_with_same_entity_type_and_all_generated_values(bool async) + { + await base.Add_Add_with_same_entity_type_and_all_generated_values(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + """ +INSERT INTO `WithAllDatabaseGenerated` () +VALUES () +RETURNING `Id`, `Data1`, `Data2`; +INSERT INTO `WithAllDatabaseGenerated` () +VALUES () +RETURNING `Id`, `Data1`, `Data2`; +"""); + } + else + { + AssertSql( + """ +INSERT INTO `WithAllDatabaseGenerated` () +VALUES (); +SELECT `Id`, `Data1`, `Data2` +FROM `WithAllDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); + +INSERT INTO `WithAllDatabaseGenerated` () +VALUES (); +SELECT `Id`, `Data1`, `Data2` +FROM `WithAllDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +"""); + } + } + + public override async Task Modify_Modify_with_same_entity_type_and_generated_values(bool async) + { + await base.Modify_Modify_with_same_entity_type_and_generated_values(async); + + AssertSql( +""" +@p1='1' +@p0='1000' +@p3='2' +@p2='1001' + +UPDATE `WithSomeDatabaseGenerated` SET `Data2` = @p0 +WHERE `Id` = @p1; +SELECT `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = @p1; + +UPDATE `WithSomeDatabaseGenerated` SET `Data2` = @p2 +WHERE `Id` = @p3; +SELECT `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = @p3; +"""); + } + + public override async Task Modify_Modify_with_same_entity_type_and_no_generated_values(bool async) + { + await base.Modify_Modify_with_same_entity_type_and_no_generated_values(async); + + AssertSql( +""" +@p2='1' +@p0='1000' +@p1='1000' +@p5='2' +@p3='1001' +@p4='1001' + +UPDATE `WithNoDatabaseGenerated` SET `Data1` = @p0, `Data2` = @p1 +WHERE `Id` = @p2; +SELECT ROW_COUNT(); + +UPDATE `WithNoDatabaseGenerated` SET `Data1` = @p3, `Data2` = @p4 +WHERE `Id` = @p5; +SELECT ROW_COUNT(); +"""); + } + + public override async Task Delete_Delete_with_same_entity_type(bool async) + { + await base.Delete_Delete_with_same_entity_type(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + """ +@p0='1' +@p1='2' + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p0 +RETURNING 1; +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p1 +RETURNING 1; +"""); + } + else + { + AssertSql( +""" +@p0='1' +@p1='2' + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p0; +SELECT ROW_COUNT(); + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p1; +SELECT ROW_COUNT(); +"""); + } + } + + #endregion Two operations with same entity type + + #region Two operations with different entity types + + public override async Task Add_Add_with_different_entity_types_and_generated_values(bool async) + { + await base.Add_Add_with_different_entity_types_and_generated_values(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + """ +@p0='1000' +@p1='1001' + +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p0) +RETURNING `Id`, `Data1`; +INSERT INTO `WithSomeDatabaseGenerated2` (`Data2`) +VALUES (@p1) +RETURNING `Id`, `Data1`; +"""); + } + else + { + AssertSql( + """ +@p0='1000' +@p1='1001' + +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p0); +SELECT `Id`, `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); + +INSERT INTO `WithSomeDatabaseGenerated2` (`Data2`) +VALUES (@p1); +SELECT `Id`, `Data1` +FROM `WithSomeDatabaseGenerated2` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +"""); + } + } + + public override async Task Add_Add_with_different_entity_types_and_no_generated_values(bool async) + { + await base.Add_Add_with_different_entity_types_and_no_generated_values(async); + + AssertSql( +""" +@p0='100' +@p1='1000' +@p2='1000' +@p3='101' +@p4='1001' +@p5='1001' + +INSERT INTO `WithNoDatabaseGenerated` (`Id`, `Data1`, `Data2`) +VALUES (@p0, @p1, @p2); +INSERT INTO `WithNoDatabaseGenerated2` (`Id`, `Data1`, `Data2`) +VALUES (@p3, @p4, @p5); +"""); + } + + public override async Task Add_Add_with_different_entity_types_and_all_generated_values(bool async) + { + await base.Add_Add_with_different_entity_types_and_all_generated_values(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( + """ +INSERT INTO `WithAllDatabaseGenerated` () +VALUES () +RETURNING `Id`, `Data1`, `Data2`; +INSERT INTO `WithAllDatabaseGenerated2` () +VALUES () +RETURNING `Id`, `Data1`, `Data2`; +"""); + } + else + { + AssertSql( + """ +INSERT INTO `WithAllDatabaseGenerated` () +VALUES (); +SELECT `Id`, `Data1`, `Data2` +FROM `WithAllDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); + +INSERT INTO `WithAllDatabaseGenerated2` () +VALUES (); +SELECT `Id`, `Data1`, `Data2` +FROM `WithAllDatabaseGenerated2` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +"""); + } + } + + public override async Task Modify_Modify_with_different_entity_types_and_generated_values(bool async) + { + await base.Modify_Modify_with_different_entity_types_and_generated_values(async); + + AssertSql( +""" +@p1='1' +@p0='1000' +@p3='2' +@p2='1001' + +UPDATE `WithSomeDatabaseGenerated` SET `Data2` = @p0 +WHERE `Id` = @p1; +SELECT `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = @p1; + +UPDATE `WithSomeDatabaseGenerated2` SET `Data2` = @p2 +WHERE `Id` = @p3; +SELECT `Data1` +FROM `WithSomeDatabaseGenerated2` +WHERE ROW_COUNT() = 1 AND `Id` = @p3; +"""); + } + + public override async Task Modify_Modify_with_different_entity_types_and_no_generated_values(bool async) + { + await base.Modify_Modify_with_different_entity_types_and_no_generated_values(async); + + AssertSql( +""" +@p2='1' +@p0='1000' +@p1='1000' +@p5='2' +@p3='1001' +@p4='1001' + +UPDATE `WithNoDatabaseGenerated` SET `Data1` = @p0, `Data2` = @p1 +WHERE `Id` = @p2; +SELECT ROW_COUNT(); + +UPDATE `WithNoDatabaseGenerated2` SET `Data1` = @p3, `Data2` = @p4 +WHERE `Id` = @p5; +SELECT ROW_COUNT(); +"""); + } + + public override async Task Delete_Delete_with_different_entity_types(bool async) + { + await base.Delete_Delete_with_different_entity_types(async); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +@p0='1' +@p1='2' + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p0 +RETURNING 1; +DELETE FROM `WithSomeDatabaseGenerated2` +WHERE `Id` = @p1 +RETURNING 1; +"""); + } + else + { + AssertSql( + """ +@p0='1' +@p1='2' + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p0; +SELECT ROW_COUNT(); + +DELETE FROM `WithSomeDatabaseGenerated2` +WHERE `Id` = @p1; +SELECT ROW_COUNT(); +"""); + } + } + + #endregion Two operations with different entity types + + #region Different two operations + + public override async Task Delete_Add_with_same_entity_types(bool async) + { + await Test(EntityState.Deleted, EntityState.Added, GeneratedValues.Some, async, withSameEntityType: true); + + if (AppConfig.ServerVersion.Supports.Returning) + { + AssertSql( +""" +@p0='1' +@p1='1001' + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p0 +RETURNING 1; +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p1) +RETURNING `Id`, `Data1`; +"""); + } + else + { + AssertSql( + """ +@p0='1' +@p1='1001' + +DELETE FROM `WithSomeDatabaseGenerated` +WHERE `Id` = @p0; +SELECT ROW_COUNT(); + +INSERT INTO `WithSomeDatabaseGenerated` (`Data2`) +VALUES (@p1); +SELECT `Id`, `Data1` +FROM `WithSomeDatabaseGenerated` +WHERE ROW_COUNT() = 1 AND `Id` = LAST_INSERT_ID(); +"""); + } + } + + #endregion Different two operations + + public class StoreValueGenerationMySqlFixture : StoreValueGenerationFixtureBase + { + private string _cleanDataSql; + + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; + + // protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + // { + // base.OnModelCreating(modelBuilder, context); + // + // foreach (var name in new[] + // { + // nameof(StoreValueGenerationContext.WithSomeDatabaseGenerated), + // nameof(StoreValueGenerationContext.WithSomeDatabaseGenerated2), + // nameof(StoreValueGenerationContext.WithAllDatabaseGenerated), + // nameof(StoreValueGenerationContext.WithAllDatabaseGenerated2) + // }) + // { + // ConfigureComputedColumn(modelBuilder.SharedTypeEntity(name).Property(w => w.Data1)); + // } + // + // foreach (var name in new[] + // { + // nameof(StoreValueGenerationContext.WithAllDatabaseGenerated), + // nameof(StoreValueGenerationContext.WithAllDatabaseGenerated2) + // }) + // { + // ConfigureComputedColumn(modelBuilder.SharedTypeEntity(name).Property(w => w.Data2)); + // } + // + // void ConfigureComputedColumn(PropertyBuilder builder) + // { + // if (TestEnvironment.PostgresVersion >= new Version(12, 0)) + // { + // // PG 12+ supports computed columns, but only stored (must be explicitly specified) + // builder.Metadata.SetIsStored(true); + // } + // else + // { + // // Before PG 12, disable computed columns (but leave OnAddOrUpdate) + // builder + // .HasComputedColumnSql(null) + // .HasDefaultValue(100) + // .Metadata + // .ValueGenerated = ValueGenerated.OnAddOrUpdate; + // } + // } + // } + + public override void CleanData() + { + using var context = CreateContext(); + context.Database.ExecuteSqlRaw(_cleanDataSql ??= GetCleanDataSql()); + } + + private string GetCleanDataSql() + { + var context = CreateContext(); + var builder = new StringBuilder(); + + var helper = context.GetService(); + var tables = context.Model.GetEntityTypes() + .SelectMany(e => e.GetTableMappings().Select(m => helper.DelimitIdentifier(m.Table.Name, m.Table.Schema))); + + foreach (var table in tables) + { + builder.AppendLine($"TRUNCATE TABLE {table};"); + } + + return builder.ToString(); + } + } +} diff --git a/test/EFCore.MySql.FunctionalTests/Update/StoredProcedureUpdateMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Update/StoredProcedureUpdateMySqlTest.cs new file mode 100644 index 000000000..1a25920f9 --- /dev/null +++ b/test/EFCore.MySql.FunctionalTests/Update/StoredProcedureUpdateMySqlTest.cs @@ -0,0 +1,619 @@ +using System; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.EntityFrameworkCore.Update; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Internal; +using Xunit; + +namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests.Update; + +public class StoredProcedureUpdateMySqlTest : StoredProcedureUpdateTestBase +{ + public override async Task Insert_with_output_parameter(bool async) + { + await base.Insert_with_output_parameter( + async, +""" +CREATE PROCEDURE Entity_Insert(pName varchar(255), OUT pId int) +BEGIN + INSERT INTO `Entity` (`Name`) VALUES (pName); + SET pId = LAST_INSERT_ID(); +END +"""); + + AssertSql( +""" +@p1='New' (Size = 4000) + +SET @_out_p0 = NULL; +CALL `Entity_Insert`(@p1, @_out_p0); +SELECT @_out_p0; +"""); + } + + public override async Task Insert_twice_with_output_parameter(bool async) + { + await base.Insert_twice_with_output_parameter( + async, +""" +CREATE PROCEDURE Entity_Insert(pName varchar(255), OUT pId int) +BEGIN + INSERT INTO `Entity` (`Name`) VALUES (pName); + SET pId = LAST_INSERT_ID(); +END +"""); + + AssertSql( +""" +@p1='New1' (Size = 4000) +@p3='New2' (Size = 4000) + +SET @_out_p0 = NULL; +CALL `Entity_Insert`(@p1, @_out_p0); +SELECT @_out_p0; +SET @_out_p2 = NULL; +CALL `Entity_Insert`(@p3, @_out_p2); +SELECT @_out_p2; +"""); + } + + public override async Task Insert_with_result_column(bool async) + { + var exception = + await Assert.ThrowsAsync(() => base.Insert_with_result_column(async, createSprocSql: "")); + + Assert.Equal(MySqlStrings.StoredProcedureResultColumnsNotSupported(nameof(Entity), nameof(Entity) + "_Insert"), exception.Message); + } + + public override async Task Insert_with_two_result_columns(bool async) + { + var exception = + await Assert.ThrowsAsync(() => base.Insert_with_two_result_columns(async, createSprocSql: "")); + + Assert.Equal( + MySqlStrings.StoredProcedureResultColumnsNotSupported( + nameof(EntityWithAdditionalProperty), nameof(EntityWithAdditionalProperty) + "_Insert"), exception.Message); + } + + public override async Task Insert_with_output_parameter_and_result_column(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Insert_with_output_parameter_and_result_column(async, createSprocSql: "")); + + Assert.Equal(MySqlStrings.StoredProcedureResultColumnsNotSupported(nameof(EntityWithAdditionalProperty), nameof(EntityWithAdditionalProperty) + "_Insert"), exception.Message); + } + + public override async Task Update(bool async) + { + await base.Update( + async, +""" +CREATE PROCEDURE Entity_Update(pId int, pName varchar(255)) +UPDATE `Entity` SET `Name` = pName WHERE `Id` = pid +"""); + + AssertSql( +""" +@p0='1' +@p1='Updated' (Size = 4000) + +CALL `Entity_Update`(@p0, @p1); +"""); + } + + public override async Task Update_partial(bool async) + { + await base.Update_partial( + async, +""" +CREATE PROCEDURE EntityWithAdditionalProperty_Update(pId int, pName varchar(255), pAdditionalProperty int) +UPDATE `EntityWithAdditionalProperty` SET `Name` = pName, `AdditionalProperty` = pAdditionalProperty WHERE `Id` = pid +"""); + + AssertSql( +""" +@p0='1' +@p1='Updated' (Size = 4000) +@p2='8' + +CALL `EntityWithAdditionalProperty_Update`(@p0, @p1, @p2); +"""); + } + + public override async Task Update_with_output_parameter_and_rows_affected_result_column(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Update_with_output_parameter_and_rows_affected_result_column(async, createSprocSql: "")); + + Assert.Equal( + MySqlStrings.StoredProcedureResultColumnsNotSupported( + nameof(EntityWithAdditionalProperty), nameof(EntityWithAdditionalProperty) + "_Update"), exception.Message); + } + + public override async Task Update_with_output_parameter_and_rows_affected_result_column_concurrency_failure(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Update_with_output_parameter_and_rows_affected_result_column_concurrency_failure(async, createSprocSql: "")); + + Assert.Equal( + MySqlStrings.StoredProcedureResultColumnsNotSupported( + nameof(EntityWithAdditionalProperty), nameof(EntityWithAdditionalProperty) + "_Update"), exception.Message); + } + + public override async Task Delete(bool async) + { + await base.Delete( + async, +""" +CREATE PROCEDURE Entity_Delete(pId int) +DELETE FROM `Entity` WHERE `Id` = pId +"""); + + AssertSql( +""" +@p0='1' + +CALL `Entity_Delete`(@p0); +"""); + } + + public override async Task Delete_and_insert(bool async) + { + await base.Delete_and_insert( + async, +""" +CREATE PROCEDURE Entity_Insert(pName varchar(255), OUT pId int) +BEGIN + INSERT INTO `Entity` (`Name`) VALUES (pName); + SET pId = LAST_INSERT_ID(); +END; + +GO; + +CREATE PROCEDURE Entity_Delete(pId int) +DELETE FROM `Entity` WHERE `Id` = pId; +"""); + + AssertSql( +""" +@p0='1' +@p2='Entity2' (Size = 4000) + +CALL `Entity_Delete`(@p0); +SET @_out_p1 = NULL; +CALL `Entity_Insert`(@p2, @_out_p1); +SELECT @_out_p1; +"""); + } + + public override async Task Rows_affected_parameter(bool async) + { + await base.Rows_affected_parameter( + async, +""" +CREATE PROCEDURE Entity_Update(pId int, pName varchar(255), OUT pRowsAffected int) +BEGIN + UPDATE `Entity` SET `Name` = pName WHERE `Id` = pId; + SET pRowsAffected = ROW_COUNT(); +END +"""); + + AssertSql( +""" +@p1='1' +@p2='Updated' (Size = 4000) + +SET @_out_p0 = NULL; +CALL `Entity_Update`(@p1, @p2, @_out_p0); +SELECT @_out_p0; +"""); + } + + public override async Task Rows_affected_parameter_and_concurrency_failure(bool async) + { + await base.Rows_affected_parameter_and_concurrency_failure( + async, +""" +CREATE PROCEDURE Entity_Update(pId int, pName varchar(255), OUT pRowsAffected int) +BEGIN + UPDATE `Entity` SET `Name` = pName WHERE `Id` = pId; + SET pRowsAffected = ROW_COUNT(); +END +"""); + + AssertSql( +""" +@p1='1' +@p2='Updated' (Size = 4000) + +SET @_out_p0 = NULL; +CALL `Entity_Update`(@p1, @p2, @_out_p0); +SELECT @_out_p0; +"""); + } + + public override async Task Rows_affected_result_column(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Rows_affected_result_column(async, createSprocSql: "")); + + Assert.Equal(MySqlStrings.StoredProcedureResultColumnsNotSupported(nameof(Entity), nameof(Entity) + "_Update"), exception.Message); + } + + public override async Task Rows_affected_result_column_and_concurrency_failure(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Rows_affected_result_column_and_concurrency_failure(async, createSprocSql: "")); + + Assert.Equal(MySqlStrings.StoredProcedureResultColumnsNotSupported(nameof(Entity), nameof(Entity) + "_Update"), exception.Message); + } + + public override async Task Rows_affected_return_value(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Rows_affected_return_value(async, createSprocSql: "")); + + Assert.Equal(MySqlStrings.StoredProcedureReturnValueNotSupported(nameof(Entity), nameof(Entity) + "_Update"), exception.Message); + } + + public override async Task Rows_affected_return_value_and_concurrency_failure(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Rows_affected_return_value(async, createSprocSql: "")); + + Assert.Equal(MySqlStrings.StoredProcedureReturnValueNotSupported(nameof(Entity), nameof(Entity) + "_Update"), exception.Message); + } + + public override async Task Store_generated_concurrency_token_as_in_out_parameter(bool async) + { + await base.Store_generated_concurrency_token_as_in_out_parameter( + async, +""" +CREATE PROCEDURE Entity_Update(pId int, INOUT pConcurrencyToken timestamp(6), pName varchar(255), OUT pRowsAffected int) +BEGIN + UPDATE `Entity` SET `Name` = pName WHERE `Id` = pId AND `ConcurrencyToken` = pConcurrencyToken; + SET pRowsAffected = ROW_COUNT(); + SELECT `ConcurrencyToken` INTO pConcurrencyToken FROM `Entity` WHERE `Id` = pId; +END +"""); + + Assert.StartsWith( + """ +@p2='1' +@p4=NULL (DbType = DateTime) +@p0=' +""", + TestSqlLoggerFactory.Sql); + + Assert.EndsWith( +""" +' (Nullable = true) (DbType = DateTime) +@p3='Updated' (Size = 4000) + +SET @_out_p0 = @p0; +SET @_out_p1 = NULL; +CALL `Entity_Update`(@p2, @_out_p0, @p3, @_out_p1); +SELECT @_out_p0, @_out_p1; +""", + TestSqlLoggerFactory.Sql); + +// AssertSql( +// """ +// @p2='1' +// @p4=NULL (DbType = DateTime) +// @p0='2022-11-14T12:03:01.9884410' (Nullable = true) (DbType = DateTime) +// @p3='Updated' (Size = 4000) +// +// SET @_out_p0 = @p0; +// SET @_out_p1 = NULL; +// CALL `Entity_Update`(@p2, @_out_p0, @p3, @_out_p1); +// SELECT @_out_p0, @_out_p1; +// """); + } + + public override async Task Store_generated_concurrency_token_as_two_parameters(bool async) + { + await base.Store_generated_concurrency_token_as_two_parameters( + async, +""" +CREATE PROCEDURE Entity_Update(pId int, pConcurrencyTokenIn timestamp(6), pName varchar(255), OUT pConcurrencyTokenOut timestamp(6), OUT pRowsAffected int) +BEGIN + UPDATE `Entity` SET `Name` = pName WHERE `Id` = pId AND `ConcurrencyToken` = pConcurrencyTokenIn; + SET pRowsAffected = ROW_COUNT(); + SELECT `ConcurrencyToken` INTO pConcurrencyTokenOut FROM `Entity` WHERE `Id` = pId; +END +"""); + + Assert.StartsWith( +""" +@p2='1' +@p3=' +""", + TestSqlLoggerFactory.Sql); + + Assert.EndsWith( + """ +' (Nullable = true) (DbType = DateTime) +@p4='Updated' (Size = 4000) + +SET @_out_p0 = NULL; +SET @_out_p1 = NULL; +CALL `Entity_Update`(@p2, @p3, @p4, @_out_p0, @_out_p1); +SELECT @_out_p0, @_out_p1; +""", + TestSqlLoggerFactory.Sql); + +// AssertSql( +// """ +// @p2='1' +// @p3='2022-11-14T14:02:25.0912340' (Nullable = true) (DbType = DateTime) +// @p4='Updated' (Size = 4000) +// +// SET @_out_p0 = NULL; +// SET @_out_p1 = NULL; +// CALL `Entity_Update`(@p2, @p3, @p4, @_out_p0, @_out_p1); +// SELECT @_out_p0, @_out_p1; +// """); + } + + public override async Task User_managed_concurrency_token(bool async) + { + await base.User_managed_concurrency_token( + async, +""" +CREATE PROCEDURE EntityWithAdditionalProperty_Update(pId int, pConcurrencyTokenOriginal int, pName varchar(255), pConcurrencyTokenCurrent int, OUT pRowsAffected int) +BEGIN + UPDATE `EntityWithAdditionalProperty` SET `Name` = pName, `AdditionalProperty` = pConcurrencyTokenCurrent WHERE `Id` = pId AND `AdditionalProperty` = pConcurrencyTokenOriginal; + SET pRowsAffected = ROW_COUNT(); +END +"""); + + AssertSql( +""" +@p1='1' +@p2='8' +@p3='Updated' (Size = 4000) +@p4='9' + +SET @_out_p0 = NULL; +CALL `EntityWithAdditionalProperty_Update`(@p1, @p2, @p3, @p4, @_out_p0); +SELECT @_out_p0; +"""); + } + + public override async Task Original_and_current_value_on_non_concurrency_token(bool async) + { + await base.Original_and_current_value_on_non_concurrency_token( + async, +""" +CREATE PROCEDURE Entity_Update(pId int, pNameCurrent varchar(255), pNameOriginal varchar(255)) +BEGIN + IF pNameCurrent <> pNameOriginal THEN + UPDATE `Entity` SET `Name` = pNameCurrent WHERE `Id` = pId; + END IF; +END +"""); + + AssertSql( +""" +@p0='1' +@p1='Updated' (Size = 4000) +@p2='Initial' (Size = 4000) + +CALL `Entity_Update`(@p0, @p1, @p2); +"""); + } + + public override async Task Input_or_output_parameter_with_input(bool async) + { + await base.Input_or_output_parameter_with_input( + async, +""" +CREATE PROCEDURE Entity_Insert(OUT pId int, INOUT pName varchar(255)) +BEGIN + IF pName IS NULL THEN + INSERT INTO `Entity` (`Name`) VALUES ('Some default value'); + SET pName = 'Some default value'; + ELSE + INSERT INTO `Entity` (`Name`) VALUES (pName); + SET pName = NULL; + END IF; + + SET pId = LAST_INSERT_ID(); +END +"""); + + AssertSql( +""" +@p1='Initial' (Nullable = false) (Size = 4000) + +SET @_out_p0 = NULL; +SET @_out_p1 = @p1; +CALL `Entity_Insert`(@_out_p0, @_out_p1); +SELECT @_out_p0, @_out_p1; +"""); + } + + public override async Task Input_or_output_parameter_with_output(bool async) + { + await base.Input_or_output_parameter_with_output( + async, +""" +CREATE PROCEDURE Entity_Insert(OUT pId int, INOUT pName varchar(255)) +BEGIN + IF pName IS NULL THEN + INSERT INTO `Entity` (`Name`) VALUES ('Some default value'); + SET pName = 'Some default value'; + ELSE + INSERT INTO `Entity` (`Name`) VALUES (pName); + SET pName = NULL; + END IF; + + SET pId = LAST_INSERT_ID(); +END +"""); + + AssertSql( +""" +SET @_out_p0 = NULL; +SET @_out_p1 = @p1; +CALL `Entity_Insert`(@_out_p0, @_out_p1); +SELECT @_out_p0, @_out_p1; +"""); + } + + public override async Task Tph(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Rows_affected_result_column(async, createSprocSql: "")); + + Assert.Equal(MySqlStrings.StoredProcedureResultColumnsNotSupported(nameof(Entity), nameof(Entity) + "_Update"), exception.Message); + } + + public override async Task Tpt(bool async) + { + var exception = + await Assert.ThrowsAsync( + () => base.Rows_affected_result_column(async, createSprocSql: "")); + + Assert.Equal(MySqlStrings.StoredProcedureResultColumnsNotSupported(nameof(Entity), nameof(Entity) + "_Update"), exception.Message); + } + + public override async Task Tpt_mixed_sproc_and_non_sproc(bool async) + { + await base.Tpt_mixed_sproc_and_non_sproc( + async, +""" +CREATE PROCEDURE Parent_Insert(OUT pId int, pName varchar(255)) +BEGIN + INSERT INTO `Parent` (`Name`) VALUES (pName); + SET pId = LAST_INSERT_ID(); +END +"""); + + AssertSql( +""" +@p1='Child' (Size = 4000) + +SET @_out_p0 = NULL; +CALL `Parent_Insert`(@_out_p0, @p1); +SELECT @_out_p0; +""", + // + """ +@p2='1' +@p3='8' + +INSERT INTO `Child1` (`Id`, `Child1Property`) +VALUES (@p2, @p3); +"""); + } + + public override async Task Tpc(bool async) + { + var createSprocSql = +""" +ALTER TABLE `Child1` MODIFY COLUMN `Id` INT AUTO_INCREMENT; +ALTER TABLE `Child1` AUTO_INCREMENT = 100000; + +GO; + +CREATE PROCEDURE Child1_Insert(OUT pId int, pName varchar(255), pChild1Property int) +BEGIN + INSERT INTO `Child1` (`Name`, `Child1Property`) VALUES (pName, pChild1Property); + SET pId = LAST_INSERT_ID(); +END +"""; + + var contextFactory = await InitializeAsync( + modelBuilder => + { + modelBuilder.Entity().UseTpcMappingStrategy(); + + modelBuilder.Entity() + .UseTpcMappingStrategy() + .InsertUsingStoredProcedure( + nameof(Child1) + "_Insert", + spb => spb + .HasParameter(w => w.Id, pb => pb.IsOutput()) + .HasParameter(w => w.Name) + .HasParameter(w => w.Child1Property)) + .Property(e => e.Id).UseMySqlIdentityColumn(); // <-- + }, + seed: ctx => CreateStoredProcedures(ctx, createSprocSql), + onConfiguring: optionsBuilder => + { + optionsBuilder.ConfigureWarnings(builder => + builder.Ignore(RelationalEventId.TpcStoreGeneratedIdentityWarning)); // <-- added + }); + + await using var context = contextFactory.CreateContext(); + + var entity1 = new Child1 { Name = "Child", Child1Property = 8 }; + context.Set().Add(entity1); + await SaveChanges(context, async); + + context.ChangeTracker.Clear(); + + using (TestSqlLoggerFactory.SuspendRecordingEvents()) + { + var entity2 = context.Set().Single(b => b.Id == entity1.Id); + + Assert.Equal("Child", entity2.Name); + Assert.Equal(8, entity2.Child1Property); + } + + AssertSql( +""" +@p1='Child' (Size = 4000) +@p2='8' + +SET @_out_p0 = NULL; +CALL `Child1_Insert`(@_out_p0, @p1, @p2); +SELECT @_out_p0; +"""); + } + + private async Task SaveChanges(DbContext context, bool async) + { + if (async) + { + await context.SaveChangesAsync(); + } + else + { + // ReSharper disable once MethodHasAsyncOverload + context.SaveChanges(); + } + } + + protected override void CreateStoredProcedures(DbContext context, string createSprocSql) + { + foreach (var batch in + new Regex(@"[\r\n\s]*(?:\r|\n)GO;?[\r\n\s]*", RegexOptions.IgnoreCase | RegexOptions.Singleline, TimeSpan.FromMilliseconds(1000.0)) + .Split(createSprocSql).Where(b => !string.IsNullOrEmpty(b))) + { + context.Database.ExecuteSqlRaw(batch); + } + } + + protected override void ConfigureStoreGeneratedConcurrencyToken(EntityTypeBuilder entityTypeBuilder, string propertyName) + => entityTypeBuilder.Property(propertyName).IsRowVersion(); + + protected override ITestStoreFactory TestStoreFactory + => MySqlTestStoreFactory.Instance; +} diff --git a/test/EFCore.MySql.FunctionalTests/UpdatesMySqlFixture.cs b/test/EFCore.MySql.FunctionalTests/UpdatesMySqlFixture.cs index 6a9038940..ddc6e9880 100644 --- a/test/EFCore.MySql.FunctionalTests/UpdatesMySqlFixture.cs +++ b/test/EFCore.MySql.FunctionalTests/UpdatesMySqlFixture.cs @@ -5,40 +5,4 @@ namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests { - public class UpdatesMySqlFixture : UpdatesRelationalFixture - { - protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; - - protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) - { - base.OnModelCreating(modelBuilder, context); - - Models.Issue1300.Setup(modelBuilder, context); - } - - public static class Models - { - public static class Issue1300 - { - public static void Setup(ModelBuilder modelBuilder, DbContext context) - { - modelBuilder.Entity( - entity => - { - entity.HasKey(e => new {e.FlavorId, e.DiscoveryDate}); - entity.Property(e => e.FlavorId) - .ValueGeneratedOnAdd(); - entity.Property(e => e.DiscoveryDate) - .ValueGeneratedOnAdd(); - }); - } - - public class Flavor - { - public int FlavorId { get; set; } - public DateTime DiscoveryDate { get; set; } - } - } - } - } } diff --git a/test/EFCore.MySql.FunctionalTests/UpdatesMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/UpdatesMySqlTest.cs index 47bd528b2..cb5788469 100644 --- a/test/EFCore.MySql.FunctionalTests/UpdatesMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/UpdatesMySqlTest.cs @@ -1,11 +1,18 @@ +using System; using System.Linq; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.TestModels.UpdatesModel; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.FunctionalTests.TestUtilities; +using Pomelo.EntityFrameworkCore.MySql.Infrastructure; +using Pomelo.EntityFrameworkCore.MySql.Tests; +using Pomelo.EntityFrameworkCore.MySql.Tests.TestUtilities.Attributes; +using Pomelo.EntityFrameworkCore.MySql.ValueGeneration.Internal; using Xunit; namespace Pomelo.EntityFrameworkCore.MySql.FunctionalTests { - public partial class UpdatesMySqlTest : UpdatesRelationalTestBase + public class UpdatesMySqlTest : UpdatesRelationalTestBase { public UpdatesMySqlTest(UpdatesMySqlFixture fixture) : base(fixture) @@ -26,5 +33,57 @@ public override void Identifiers_are_generated_correctly() Assert.Equal("IX_LoginEntityTypeWithAnExtremelyLongAndOverlyConvolutedNameTha~", entityType.GetIndexes().Single().GetDatabaseName()); } } + + [SupportedServerVersionCondition(nameof(ServerVersionSupport.DefaultExpression), nameof(ServerVersionSupport.AlternativeDefaultExpression))] + [SupportedServerVersionCondition(nameof(ServerVersionSupport.Returning))] + public override void Save_with_shared_foreign_key() + { + base.Save_with_shared_foreign_key(); + } + + public class UpdatesMySqlFixture : UpdatesRelationalFixture + { + protected override ITestStoreFactory TestStoreFactory => MySqlTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + // Necessary for test `Save_with_shared_foreign_key` to run correctly. + if (AppConfig.ServerVersion.Supports.DefaultExpression || + AppConfig.ServerVersion.Supports.AlternativeDefaultExpression) + { + modelBuilder.Entity() + .Property(p => p.Id).HasDefaultValueSql("(UUID())"); + } + + Models.Issue1300.Setup(modelBuilder, context); + } + + public static class Models + { + public static class Issue1300 + { + public static void Setup(ModelBuilder modelBuilder, DbContext context) + { + modelBuilder.Entity( + entity => + { + entity.HasKey(e => new {e.FlavorId, e.DiscoveryDate}); + entity.Property(e => e.FlavorId) + .ValueGeneratedOnAdd(); + entity.Property(e => e.DiscoveryDate) + .ValueGeneratedOnAdd(); + }); + } + + public class Flavor + { + public int FlavorId { get; set; } + public DateTime DiscoveryDate { get; set; } + } + } + } + } } } diff --git a/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj b/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj index a229dd781..8c6ea4299 100644 --- a/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj +++ b/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj @@ -1,7 +1,7 @@  - $(DefaultNetCoreTargetFramework) + $(PomeloTestTargetFramework) Pomelo.EntityFrameworkCore.MySql.IntegrationTests Pomelo.EntityFrameworkCore.MySql.IntegrationTests.Program Exe @@ -39,7 +39,7 @@ @@ -47,22 +47,22 @@ - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Design.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Design.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Specification.Tests.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Specification.Tests.dll diff --git a/test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_initial.Designer.csbak b/test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_Initial.Designer.csbak similarity index 99% rename from test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_initial.Designer.csbak rename to test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_Initial.Designer.csbak index 155306cd6..aa696802c 100644 --- a/test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_initial.Designer.csbak +++ b/test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_Initial.Designer.csbak @@ -10,8 +10,8 @@ using Pomelo.EntityFrameworkCore.MySql.IntegrationTests.Models; namespace Pomelo.EntityFrameworkCore.MySql.IntegrationTests.Migrations { [DbContext(typeof(AppDb))] - [Migration("20170829174711_initial")] - partial class initial + [Migration("20170829174711_Initial")] + partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { diff --git a/test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_initial.csbak b/test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_Initial.csbak similarity index 99% rename from test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_initial.csbak rename to test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_Initial.csbak index e4d24ca74..efc60044b 100644 --- a/test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_initial.csbak +++ b/test/EFCore.MySql.IntegrationTests/LegacyMigrations/1.1.2/20170829174711_Initial.csbak @@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace Pomelo.EntityFrameworkCore.MySql.IntegrationTests.Migrations { - public partial class initial : Migration + public partial class Initial : Migration { protected override void Up(MigrationBuilder migrationBuilder) { diff --git a/test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_initial.Designer.csbak b/test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_Initial.Designer.csbak similarity index 99% rename from test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_initial.Designer.csbak rename to test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_Initial.Designer.csbak index 59356906c..410e8fd87 100644 --- a/test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_initial.Designer.csbak +++ b/test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_Initial.Designer.csbak @@ -14,8 +14,8 @@ using System.Collections.Generic; namespace Pomelo.EntityFrameworkCore.MySql.IntegrationTests.Migrations { [DbContext(typeof(AppDb))] - [Migration("20180529213507_initial")] - partial class initial + [Migration("20180529213507_Initial")] + partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { diff --git a/test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_initial.csbak b/test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_Initial.csbak similarity index 99% rename from test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_initial.csbak rename to test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_Initial.csbak index 0f1ba6bb1..ba1b5ee3f 100644 --- a/test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_initial.csbak +++ b/test/EFCore.MySql.IntegrationTests/LegacyMigrations/2.0.1/20180529213507_Initial.csbak @@ -5,7 +5,7 @@ using System.Collections.Generic; namespace Pomelo.EntityFrameworkCore.MySql.IntegrationTests.Migrations { - public partial class initial : Migration + public partial class Initial : Migration { protected override void Up(MigrationBuilder migrationBuilder) { diff --git a/test/EFCore.MySql.IntegrationTests/Tests/Models/ExpressionTest.cs b/test/EFCore.MySql.IntegrationTests/Tests/Models/ExpressionTest.cs index d4b6d38d4..2b2560aae 100644 --- a/test/EFCore.MySql.IntegrationTests/Tests/Models/ExpressionTest.cs +++ b/test/EFCore.MySql.IntegrationTests/Tests/Models/ExpressionTest.cs @@ -89,7 +89,7 @@ public async Task MySqlDateAddTranslator() FutureMinute = m.TypeDateTime.AddMinutes(1), FutureSecond = m.TypeDateTime.AddSeconds(1), FutureMillisecond = m.TypeDateTime.AddMilliseconds(1), - FutureMillisecondRoundUp = m.TypeDateTime.AddMilliseconds(1.8), + FutureMillisecondRound = m.TypeDateTime.AddMilliseconds(1.8), PastYear = m.TypeDateTime.AddYears(-1), PastMonth = m.TypeDateTime.AddMonths(-1), PastDay = m.TypeDateTime.AddDays(-1), @@ -97,7 +97,7 @@ public async Task MySqlDateAddTranslator() PastMinute = m.TypeDateTime.AddMinutes(-1), PastSecond = m.TypeDateTime.AddSeconds(-1), PostMillisecond = m.TypeDateTime.AddMilliseconds(-1), - PostMillisecondRoundUp = m.TypeDateTime.AddMilliseconds(-1.8), + PostMillisecondRound = m.TypeDateTime.AddMilliseconds(-1.8), }).FirstOrDefaultAsync(m => m.Id == _simple.Id); Assert.Equal(_simple.TypeDateTime.AddYears(1), result.FutureYear); @@ -107,7 +107,7 @@ public async Task MySqlDateAddTranslator() Assert.Equal(_simple.TypeDateTime.AddMinutes(1), result.FutureMinute); Assert.Equal(_simple.TypeDateTime.AddSeconds(1), result.FutureSecond); Assert.Equal(_simple.TypeDateTime.AddMilliseconds(1), result.FutureMillisecond); - Assert.Equal(_simple.TypeDateTime.AddMilliseconds(1.8), result.FutureMillisecondRoundUp); + Assert.Equal(_simple.TypeDateTime.AddMilliseconds(Math.Round(1.8, MidpointRounding.AwayFromZero)), result.FutureMillisecondRound); Assert.Equal(_simple.TypeDateTime.AddYears(-1), result.PastYear); Assert.Equal(_simple.TypeDateTime.AddMonths(-1), result.PastMonth); Assert.Equal(_simple.TypeDateTime.AddDays(-1), result.PastDay); @@ -115,7 +115,7 @@ public async Task MySqlDateAddTranslator() Assert.Equal(_simple.TypeDateTime.AddMinutes(-1), result.PastMinute); Assert.Equal(_simple.TypeDateTime.AddSeconds(-1), result.PastSecond); Assert.Equal(_simple.TypeDateTime.AddMilliseconds(-1), result.PostMillisecond); - Assert.Equal(_simple.TypeDateTime.AddMilliseconds(-1.8), result.PostMillisecondRoundUp); + Assert.Equal(_simple.TypeDateTime.AddMilliseconds(Math.Round(-1.8, MidpointRounding.AwayFromZero)), result.PostMillisecondRound); } [Fact] diff --git a/test/EFCore.MySql.IntegrationTests/scripts/legacy.ps1 b/test/EFCore.MySql.IntegrationTests/scripts/legacy.ps1 index 95d357ef1..5c0c62a1c 100644 --- a/test/EFCore.MySql.IntegrationTests/scripts/legacy.ps1 +++ b/test/EFCore.MySql.IntegrationTests/scripts/legacy.ps1 @@ -16,7 +16,7 @@ try Copy-Item (Join-Path 'LegacyMigrations' $legacyVersion '*.csbak') 'Migrations' Get-ChildItem (Join-Path 'Migrations' '*.csbak') | % { Rename-Item -Path $_.FullName -NewName ([System.IO.Path]::ChangeExtension($_.Name, ".cs")) } - dotnet ef migrations add current --verbose + dotnet ef migrations add Current --verbose dotnet ef database update --verbose dotnet test break; diff --git a/test/EFCore.MySql.IntegrationTests/scripts/rebuild.ps1 b/test/EFCore.MySql.IntegrationTests/scripts/rebuild.ps1 index 0dbe7054d..617538aef 100755 --- a/test/EFCore.MySql.IntegrationTests/scripts/rebuild.ps1 +++ b/test/EFCore.MySql.IntegrationTests/scripts/rebuild.ps1 @@ -22,7 +22,7 @@ try Remove-Item (Join-Path "Migrations" "*.cs") dotnet ef database drop -f - dotnet ef migrations add initial + dotnet ef migrations add Initial # add using System.Collections.Generic to the migration files Get-ChildItem (Join-Path "Migrations" "*.cs") | ForEach-Object { diff --git a/test/EFCore.MySql.Tests/EFCore.MySql.Tests.csproj b/test/EFCore.MySql.Tests/EFCore.MySql.Tests.csproj index f158d1ada..a16f047b9 100644 --- a/test/EFCore.MySql.Tests/EFCore.MySql.Tests.csproj +++ b/test/EFCore.MySql.Tests/EFCore.MySql.Tests.csproj @@ -1,7 +1,7 @@  - $(DefaultNetCoreTargetFramework) + $(PomeloTestTargetFramework) true Pomelo.EntityFrameworkCore.MySql.Tests Pomelo.EntityFrameworkCore.MySql @@ -45,28 +45,28 @@ - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Abstractions.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Analyzers.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Design.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Design.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Design.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Proxies.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Proxies.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Relational.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Relational.Specification.Tests.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Relational.Specification.Tests.dll - $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(TargetFramework)\Microsoft.EntityFrameworkCore.Specification.Tests.dll + $(LocalEFCoreRepository)\artifacts\bin\EFCore.Relational.Tests\Debug\$(EfCoreTestTargetFramework)\Microsoft.EntityFrameworkCore.Specification.Tests.dll diff --git a/test/EFCore.MySql.Tests/MySqlDbContextOptionsExtensionsTest.cs b/test/EFCore.MySql.Tests/MySqlDbContextOptionsExtensionsTest.cs index 9745dd307..961813b7b 100644 --- a/test/EFCore.MySql.Tests/MySqlDbContextOptionsExtensionsTest.cs +++ b/test/EFCore.MySql.Tests/MySqlDbContextOptionsExtensionsTest.cs @@ -1,5 +1,8 @@ using System; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.TestModels.ConferencePlanner; +using Microsoft.Extensions.DependencyInjection; using Pomelo.EntityFrameworkCore.MySql.Infrastructure; using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal; using Pomelo.EntityFrameworkCore.MySql.Internal; @@ -367,5 +370,50 @@ public void UseMySql_without_connection_explicit_DefaultDataTypeMappings_is_appl Assert.Equal(MySqlBooleanType.Bit1, mySqlOptions.DefaultDataTypeMappings.ClrBoolean); } + + [ConditionalTheory] + [InlineData(false)] + [InlineData(true)] + public void Service_collection_extension_method_can_configure_provider_options(bool nullConnectionString) + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddMySql( + nullConnectionString + ? null + : AppConfig.ConnectionString, + AppConfig.ServerVersion, + mySqlOption => + { + mySqlOption.MaxBatchSize(123); + mySqlOption.CommandTimeout(30); + }, + dbContextOption => + { + dbContextOption.EnableDetailedErrors(); + }); + + var services = serviceCollection.BuildServiceProvider(); + + using (var serviceScope = services + .GetRequiredService() + .CreateScope()) + { + var coreOptions = serviceScope.ServiceProvider.GetRequiredService>().GetExtension(); + Assert.True(coreOptions.DetailedErrorsEnabled); + + var mySqlOptions = serviceScope.ServiceProvider.GetRequiredService>().GetExtension(); + Assert.Equal(123, mySqlOptions.MaxBatchSize); + Assert.Equal(30, mySqlOptions.CommandTimeout); + + if (nullConnectionString) + { + Assert.Equal(null, mySqlOptions.ConnectionString); + } + else + { + Assert.StartsWith(AppConfig.ConnectionString, mySqlOptions.ConnectionString); + } + } + } } } diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeDatabaseModelFactory.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeDatabaseModelFactory.cs deleted file mode 100644 index 8cde6d217..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeDatabaseModelFactory.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Data.Common; -using Microsoft.EntityFrameworkCore.Scaffolding; -using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; - -namespace Microsoft.EntityFrameworkCore.TestUtilities -{ - public class FakeDatabaseModelFactory : IDatabaseModelFactory - { - public DatabaseModel Create(string connectionString, DatabaseModelFactoryOptions options) => throw new NotImplementedException(); - - public DatabaseModel Create(DbConnection connection, DatabaseModelFactoryOptions options) => throw new NotImplementedException(); - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeDiagnosticsLogger.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeDiagnosticsLogger.cs deleted file mode 100644 index 6618bce5d..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeDiagnosticsLogger.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Diagnostics; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.Diagnostics.Internal; -using Microsoft.Extensions.Logging; - -namespace Microsoft.EntityFrameworkCore.TestUtilities -{ - public class FakeDiagnosticsLogger : IDiagnosticsLogger, ILogger - where T : LoggerCategory, new() - { - public ILoggingOptions Options { get; } - - public bool ShouldLogSensitiveData() => false; - - public ILogger Logger => this; - - public DiagnosticSource DiagnosticSource { get; } = new DiagnosticListener("Fake"); - public IDbContextLogger DbContextLogger { get; } = new NullDbContextLogger(); - - public IInterceptors Interceptors => null; - - public LoggingDefinitions Definitions => null; - - public void Log( - LogLevel logLevel, - EventId eventId, - TState state, - Exception exception, - Func formatter) - { - } - - public bool IsEnabled(LogLevel logLevel) => true; - - public bool IsEnabled(EventId eventId, LogLevel logLevel) => true; - - public WarningBehavior GetLogBehavior(EventId eventId, LogLevel logLevel) => WarningBehavior.Log; - - public IDisposable BeginScope(TState state) => null; - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeCommandExecutor.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeCommandExecutor.cs deleted file mode 100644 index db8200c13..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeCommandExecutor.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Data.Common; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeCommandExecutor - { - private readonly Func _executeNonQuery; - private readonly Func _executeScalar; - private readonly Func _executeReader; - private readonly Func> _executeNonQueryAsync; - private readonly Func> _executeScalarAsync; - private readonly Func> _executeReaderAsync; - - public FakeCommandExecutor( - Func executeNonQuery = null, - Func executeScalar = null, - Func executeReader = null, - Func> executeNonQueryAsync = null, - Func> executeScalarAsync = null, - Func> executeReaderAsync = null) - { - _executeNonQuery = executeNonQuery - ?? (c => -1); - - _executeScalar = executeScalar - ?? (c => null); - - _executeReader = executeReader - ?? ((c, b) => new FakeDbDataReader()); - - _executeNonQueryAsync = executeNonQueryAsync - ?? ((c, ct) => Task.FromResult(-1)); - - _executeScalarAsync = executeScalarAsync - ?? ((c, ct) => Task.FromResult(null)); - - _executeReaderAsync = executeReaderAsync - ?? ((c, ct, b) => Task.FromResult(new FakeDbDataReader())); - } - - public virtual int ExecuteNonQuery(FakeDbCommand command) => _executeNonQuery(command); - - public virtual object ExecuteScalar(FakeDbCommand command) => _executeScalar(command); - - public virtual DbDataReader ExecuteReader(FakeDbCommand command, CommandBehavior behavior) - => _executeReader(command, behavior); - - public Task ExecuteNonQueryAsync(FakeDbCommand command, CancellationToken cancellationToken) - => _executeNonQueryAsync(command, cancellationToken); - - public Task ExecuteScalarAsync(FakeDbCommand command, CancellationToken cancellationToken) - => _executeScalarAsync(command, cancellationToken); - - public Task ExecuteReaderAsync(FakeDbCommand command, CommandBehavior behavior, CancellationToken cancellationToken) - => _executeReaderAsync(command, behavior, cancellationToken); - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbCommand.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbCommand.cs deleted file mode 100644 index ec4c5cc64..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbCommand.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Data.Common; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeDbCommand : DbCommand - { - private readonly FakeCommandExecutor _commandExecutor; - - public FakeDbCommand() - { - } - - public FakeDbCommand( - FakeDbConnection connection, - FakeCommandExecutor commandExecutor) - { - DbConnection = connection; - _commandExecutor = commandExecutor; - } - - protected override DbConnection DbConnection { get; set; } - - protected override DbTransaction DbTransaction { get; set; } - - public override void Cancel() - { - throw new NotImplementedException(); - } - - public override string CommandText { get; set; } - - public static int DefaultCommandTimeout = 30; - - public override int CommandTimeout { get; set; } = DefaultCommandTimeout; - - public override CommandType CommandType { get; set; } - - protected override DbParameter CreateDbParameter() - => new FakeDbParameter(); - - protected override DbParameterCollection DbParameterCollection { get; } - = new FakeDbParameterCollection(); - - public override void Prepare() - { - throw new NotImplementedException(); - } - - public override int ExecuteNonQuery() - { - AssertTransaction(); - - return _commandExecutor.ExecuteNonQuery(this); - } - - public override object ExecuteScalar() - { - AssertTransaction(); - - return _commandExecutor.ExecuteScalar(this); - } - - protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) - { - AssertTransaction(); - - return _commandExecutor.ExecuteReader(this, behavior); - } - - public override Task ExecuteNonQueryAsync(CancellationToken cancellationToken) - { - AssertTransaction(); - - return _commandExecutor.ExecuteNonQueryAsync(this, cancellationToken); - } - - public override Task ExecuteScalarAsync(CancellationToken cancellationToken) - { - AssertTransaction(); - - return _commandExecutor.ExecuteScalarAsync(this, cancellationToken); - } - - protected override Task ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) - { - AssertTransaction(); - - return _commandExecutor.ExecuteReaderAsync(this, behavior, cancellationToken); - } - - public override bool DesignTimeVisible - { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); - } - - public override UpdateRowSource UpdatedRowSource - { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); - } - - public int DisposeCount { get; private set; } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - DisposeCount++; - } - - base.Dispose(disposing); - } - - private void AssertTransaction() - { - if (Transaction == null) - { - Debug.Assert(((FakeDbConnection)DbConnection).ActiveTransaction == null); - } - else - { - var transaction = (FakeDbTransaction)Transaction; - - Debug.Assert(transaction.Connection == Connection); - Debug.Assert(transaction.DisposeCount == 0); - } - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbConnection.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbConnection.cs deleted file mode 100644 index 5e8d0e7de..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbConnection.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeDbConnection : DbConnection - { - private readonly FakeCommandExecutor _commandExecutor; - - private ConnectionState _state; - private readonly List _dbCommands = new List(); - private readonly List _dbTransactions = new List(); - - public FakeDbConnection( - string connectionString, - FakeCommandExecutor commandExecutor = null, - ConnectionState state = ConnectionState.Closed) - { - ConnectionString = connectionString; - _commandExecutor = commandExecutor ?? new FakeCommandExecutor(); - _state = state; - } - - public void SetState(ConnectionState state) - => _state = state; - - public override ConnectionState State => _state; - - public IReadOnlyList DbCommands => _dbCommands; - - public override string ConnectionString { get; set; } - - public override string Database { get; } = "Fake Database"; - - public override string DataSource { get; } = "Fake DataSource"; - - public override string ServerVersion => throw new NotImplementedException(); - - public override void ChangeDatabase(string databaseName) - { - throw new NotImplementedException(); - } - - public int OpenCount { get; private set; } - - public override void Open() - { - OpenCount++; - _state = ConnectionState.Open; - } - - public int OpenAsyncCount { get; private set; } - - public override Task OpenAsync(CancellationToken cancellationToken) - { - OpenAsyncCount++; - return base.OpenAsync(cancellationToken); - } - - public int CloseCount { get; private set; } - - public override void Close() - { - CloseCount++; - _state = ConnectionState.Closed; - } - - protected override DbCommand CreateDbCommand() - { - var command = new FakeDbCommand(this, _commandExecutor); - - _dbCommands.Add(command); - - return command; - } - - public IReadOnlyList DbTransactions => _dbTransactions; - - public FakeDbTransaction ActiveTransaction { get; set; } - - protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) - { - ActiveTransaction = new FakeDbTransaction(this, isolationLevel); - - _dbTransactions.Add(ActiveTransaction); - - return ActiveTransaction; - } - - public int DisposeCount { get; private set; } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - DisposeCount++; - } - - base.Dispose(disposing); - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbDataReader.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbDataReader.cs deleted file mode 100644 index 043a0926e..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbDataReader.cs +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data.Common; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeDbDataReader : DbDataReader - { - private readonly string[] _columnNames; - private readonly IList _results; - - private object[] _currentRow; - private int _rowIndex; - - public FakeDbDataReader(string[] columnNames = null, IList results = null) - { - _columnNames = columnNames ?? new string[0]; - _results = results ?? new List(); - } - - public override bool Read() - { - _currentRow = _rowIndex < _results.Count - ? _results[_rowIndex++] - : null; - - return _currentRow != null; - } - - public int ReadAsyncCount { get; private set; } - - public override Task ReadAsync(CancellationToken cancellationToken) - { - ReadAsyncCount++; - - _currentRow = _rowIndex < _results.Count - ? _results[_rowIndex++] - : null; - - return Task.FromResult(_currentRow != null); - } - - public int CloseCount { get; private set; } - - public override void Close() - { - CloseCount++; - } - - public int DisposeCount { get; private set; } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - DisposeCount++; - - base.Dispose(true); - } - } - - public override int FieldCount => _columnNames.Length; - - public override string GetName(int ordinal) => _columnNames[ordinal]; - - public override bool IsDBNull(int ordinal) => _currentRow[ordinal] == DBNull.Value; - - public override object GetValue(int ordinal) => _currentRow[ordinal]; - - public int GetInt32Count { get; private set; } - - public override int GetInt32(int ordinal) - { - GetInt32Count++; - - return (int)_currentRow[ordinal]; - } - - public override object this[string name] => throw new NotImplementedException(); - - public override object this[int ordinal] => throw new NotImplementedException(); - - public override int Depth => throw new NotImplementedException(); - - public override bool HasRows => throw new NotImplementedException(); - - public override bool IsClosed => throw new NotImplementedException(); - - public override int RecordsAffected => 0; - - public override bool GetBoolean(int ordinal) => (bool)_currentRow[ordinal]; - - public override byte GetByte(int ordinal) => (byte)_currentRow[ordinal]; - - public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) - { - throw new NotImplementedException(); - } - - public override char GetChar(int ordinal) => (char)_currentRow[ordinal]; - - public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) - { - throw new NotImplementedException(); - } - - public override string GetDataTypeName(int ordinal) - { - throw new NotImplementedException(); - } - - public override DateTime GetDateTime(int ordinal) => (DateTime)_currentRow[ordinal]; - - public override decimal GetDecimal(int ordinal) => (decimal)_currentRow[ordinal]; - - public override double GetDouble(int ordinal) => (double)_currentRow[ordinal]; - - public override IEnumerator GetEnumerator() - { - throw new NotImplementedException(); - } - - public override Type GetFieldType(int ordinal) - { - throw new NotImplementedException(); - } - - public override float GetFloat(int ordinal) => (float)_currentRow[ordinal]; - - public override Guid GetGuid(int ordinal) => (Guid)_currentRow[ordinal]; - - public override short GetInt16(int ordinal) => (short)_currentRow[ordinal]; - - public override long GetInt64(int ordinal) => (long)_currentRow[ordinal]; - - public override int GetOrdinal(string name) - { - throw new NotImplementedException(); - } - - public override string GetString(int ordinal) => (string)_currentRow[ordinal]; - - public override int GetValues(object[] values) - { - throw new NotImplementedException(); - } - - public override bool NextResult() - { - throw new NotImplementedException(); - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbParameter.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbParameter.cs deleted file mode 100644 index b0e9c1516..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbParameter.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Data; -using System.Data.Common; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeDbParameter : DbParameter - { - public override string ParameterName { get; set; } - - public override object Value { get; set; } - - public override ParameterDirection Direction { get; set; } - - public static bool DefaultIsNullable = false; - public override bool IsNullable { get; set; } = DefaultIsNullable; - - public static DbType DefaultDbType = DbType.AnsiString; - public override DbType DbType { get; set; } = DefaultDbType; - - public override int Size { get; set; } - - public override string SourceColumn - { - get => throw new NotImplementedException(); - - set => throw new NotImplementedException(); - } - - public override bool SourceColumnNullMapping - { - get => throw new NotImplementedException(); - - set => throw new NotImplementedException(); - } - - public override void ResetDbType() - { - throw new NotImplementedException(); - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbParameterCollection.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbParameterCollection.cs deleted file mode 100644 index 0ce10d925..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbParameterCollection.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data.Common; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeDbParameterCollection : DbParameterCollection - { - private readonly List _parameters = new List(); - - public override int Count => _parameters.Count; - - public override int Add(object value) - { - _parameters.Add(value); - - return _parameters.Count - 1; - } - - protected override DbParameter GetParameter(int index) - => (DbParameter)_parameters[index]; - - public override IEnumerator GetEnumerator() - => _parameters.GetEnumerator(); - - public override object SyncRoot => throw new NotImplementedException(); - - public override void AddRange(Array values) - { - throw new NotImplementedException(); - } - - public override void Clear() - { - // no-op to test that parameters are passed correctly to db command. - } - - public override bool Contains(string value) - { - throw new NotImplementedException(); - } - - public override bool Contains(object value) - { - throw new NotImplementedException(); - } - - public override void CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } - - public override int IndexOf(string parameterName) - { - throw new NotImplementedException(); - } - - public override int IndexOf(object value) - { - throw new NotImplementedException(); - } - - public override void Insert(int index, object value) - { - throw new NotImplementedException(); - } - - public override void Remove(object value) - { - throw new NotImplementedException(); - } - - public override void RemoveAt(string parameterName) - { - throw new NotImplementedException(); - } - - public override void RemoveAt(int index) - { - throw new NotImplementedException(); - } - - protected override DbParameter GetParameter(string parameterName) - { - throw new NotImplementedException(); - } - - protected override void SetParameter(string parameterName, DbParameter value) - { - throw new NotImplementedException(); - } - - protected override void SetParameter(int index, DbParameter value) - { - throw new NotImplementedException(); - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbTransaction.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbTransaction.cs deleted file mode 100644 index ada9eda94..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeDbTransaction.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Data; -using System.Data.Common; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeDbTransaction : DbTransaction - { - public FakeDbTransaction(FakeDbConnection connection, IsolationLevel isolationLevel = IsolationLevel.Unspecified) - { - DbConnection = connection; - IsolationLevel = isolationLevel; - } - - protected override DbConnection DbConnection { get; } - - public override IsolationLevel IsolationLevel { get; } - - public int CommitCount { get; private set; } - - public override void Commit() - { - CommitCount++; - } - - public int RollbackCount { get; private set; } - - public override void Rollback() - { - RollbackCount++; - } - - public int DisposeCount { get; private set; } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - DisposeCount++; - - ((FakeDbConnection)DbConnection).ActiveTransaction = null; - } - - base.Dispose(disposing); - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalConnection.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalConnection.cs deleted file mode 100644 index 92bfa2805..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalConnection.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Data.Common; -using System.Diagnostics; -using Microsoft.EntityFrameworkCore.Diagnostics.Internal; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Infrastructure.Internal; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Storage.Internal; -using Microsoft.Extensions.Logging; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeRelationalConnection : RelationalConnection - { - private DbConnection _connection; - - private readonly List _dbConnections = new(); - - public FakeRelationalConnection(IDbContextOptions options = null) - : base( - new RelationalConnectionDependencies( - options ?? CreateOptions(), - new DiagnosticsLogger( - new LoggerFactory(), - new LoggingOptions(), - new DiagnosticListener("FakeDiagnosticListener"), - new TestRelationalLoggingDefinitions(), - new NullDbContextLogger()), - new RelationalConnectionDiagnosticsLogger( - new LoggerFactory(), - new LoggingOptions(), - new DiagnosticListener("FakeDiagnosticListener"), - new TestRelationalLoggingDefinitions(), - new NullDbContextLogger(), - CreateOptions()), - new NamedConnectionStringResolver(options ?? CreateOptions()), - new RelationalTransactionFactory( - new RelationalTransactionFactoryDependencies( - new RelationalSqlGenerationHelper( - new RelationalSqlGenerationHelperDependencies()))), - new CurrentDbContext(new FakeDbContext()), - new RelationalCommandBuilderFactory( - new RelationalCommandBuilderDependencies( - new TestRelationalTypeMappingSource( - TestServiceFactory.Instance.Create(), - TestServiceFactory.Instance.Create()))))) - { - } - - private class FakeDbContext : DbContext - { - } - - private static IDbContextOptions CreateOptions() - { - var optionsBuilder = new DbContextOptionsBuilder(); - - // ((IDbContextOptionsBuilderInfrastructure)optionsBuilder) - // .AddOrUpdateExtension(new FakeRelationalOptionsExtension().WithConnectionString("Database=Dummy")); - - return optionsBuilder.Options; - } - - public void UseConnection(DbConnection connection) - => _connection = connection; - - public override DbConnection DbConnection - => _connection ?? base.DbConnection; - - public IReadOnlyList DbConnections - => _dbConnections; - - protected override DbConnection CreateDbConnection() - { - var connection = new FakeDbConnection(ConnectionString); - - _dbConnections.Add(connection); - - return connection; - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalDatabaseCreator.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalDatabaseCreator.cs deleted file mode 100644 index a2c9f4e23..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalDatabaseCreator.cs +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.Storage; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeRelationalDatabaseCreator : IRelationalDatabaseCreator - { - public bool EnsureDeleted() - { - throw new NotImplementedException(); - } - - public Task EnsureDeletedAsync(CancellationToken cancellationToken = new CancellationToken()) - { - throw new NotImplementedException(); - } - - public bool EnsureCreated() - { - throw new NotImplementedException(); - } - - public Task EnsureCreatedAsync(CancellationToken cancellationToken = new CancellationToken()) - { - throw new NotImplementedException(); - } - - public bool Exists() - { - throw new NotImplementedException(); - } - - public Task ExistsAsync(CancellationToken cancellationToken = new CancellationToken()) - { - throw new NotImplementedException(); - } - - public void Create() - { - throw new NotImplementedException(); - } - - public Task CreateAsync(CancellationToken cancellationToken = new CancellationToken()) - { - throw new NotImplementedException(); - } - - public void Delete() - { - throw new NotImplementedException(); - } - - public Task DeleteAsync(CancellationToken cancellationToken = new CancellationToken()) - { - throw new NotImplementedException(); - } - - public void CreateTables() - { - throw new NotImplementedException(); - } - - public Task CreateTablesAsync(CancellationToken cancellationToken = new CancellationToken()) - { - throw new NotImplementedException(); - } - - public string GenerateCreateScript() - { - throw new NotImplementedException(); - } - - public bool HasTables() - { - throw new NotImplementedException(); - } - - public Task HasTablesAsync(CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public bool CanConnect() - { - throw new NotImplementedException(); - } - - public Task CanConnectAsync(CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalOptionsExtension.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalOptionsExtension.cs deleted file mode 100644 index 9490acae0..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeRelationalOptionsExtension.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Update; -using Microsoft.Extensions.DependencyInjection; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeRelationalOptionsExtension : RelationalOptionsExtension - { - private DbContextOptionsExtensionInfo _info; - - protected FakeRelationalOptionsExtension(FakeRelationalOptionsExtension copyFrom) - : base(copyFrom) - { - } - - public override DbContextOptionsExtensionInfo Info - => _info = _info ?? new ExtensionInfo(this); - - protected override RelationalOptionsExtension Clone() - => new FakeRelationalOptionsExtension(this); - - public override void ApplyServices(IServiceCollection services) - { - AddEntityFrameworkRelationalDatabase(services); - } - - public static IServiceCollection AddEntityFrameworkRelationalDatabase(IServiceCollection serviceCollection) - { - var builder = new EntityFrameworkRelationalServicesBuilder(serviceCollection) - .TryAdd() - .TryAdd>() - .TryAdd() - .TryAdd() - .TryAdd() - .TryAdd() - .TryAdd() - .TryAdd(_ => null) - .TryAdd() - .TryAdd() - .TryAdd(); - - builder.TryAddCoreServices(); - - return serviceCollection; - } - - private sealed class ExtensionInfo : RelationalExtensionInfo - { - public ExtensionInfo(IDbContextOptionsExtension extension) - : base(extension) - { - } - - public override void PopulateDebugInfo(IDictionary debugInfo) - { - } - } - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeSqlGenerator.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeSqlGenerator.cs deleted file mode 100644 index 06a192bff..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeProvider/FakeSqlGenerator.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Text; -using Microsoft.EntityFrameworkCore.Update; - -namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider -{ - public class FakeSqlGenerator : UpdateSqlGenerator - { - public FakeSqlGenerator(UpdateSqlGeneratorDependencies dependencies) - : base(dependencies) - { - } - - public override ResultSetMapping AppendInsertOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition) - { - AppendInsertOperationCalls++; - return base.AppendInsertOperation(commandStringBuilder, command, commandPosition); - } - - public override ResultSetMapping AppendUpdateOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition) - { - AppendUpdateOperationCalls++; - return base.AppendUpdateOperation(commandStringBuilder, command, commandPosition); - } - - public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition) - { - AppendDeleteOperationCalls++; - return base.AppendDeleteOperation(commandStringBuilder, command, commandPosition); - } - - public int AppendBatchHeaderCalls { get; set; } - public int AppendInsertOperationCalls { get; set; } - public int AppendUpdateOperationCalls { get; set; } - public int AppendDeleteOperationCalls { get; set; } - - public override void AppendBatchHeader(StringBuilder commandStringBuilder) - { - AppendBatchHeaderCalls++; - base.AppendBatchHeader(commandStringBuilder); - } - - protected override void AppendIdentityWhereCondition(StringBuilder commandStringBuilder, IColumnModification columnModification) - => commandStringBuilder - .Append(SqlGenerationHelper.DelimitIdentifier(columnModification.ColumnName)) - .Append(" = ") - .Append("provider_specific_identity()"); - - protected override ResultSetMapping AppendSelectAffectedCountCommand(StringBuilder commandStringBuilder, string name, string schema, int commandPosition) - { - commandStringBuilder - .Append("SELECT provider_specific_rowcount();" + Environment.NewLine + Environment.NewLine); - - return ResultSetMapping.LastInResultSet; - } - - protected override void AppendRowsAffectedWhereCondition(StringBuilder commandStringBuilder, int expectedRowsAffected) - => commandStringBuilder - .Append("provider_specific_rowcount() = " + expectedRowsAffected); - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/FakeRelationalCommandDiagnosticsLogger.cs b/test/EFCore.MySql.Tests/TestUtilities/FakeRelationalCommandDiagnosticsLogger.cs deleted file mode 100644 index 13448ed6b..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/FakeRelationalCommandDiagnosticsLogger.cs +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Data.Common; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.EntityFrameworkCore.Storage; - -#nullable enable - -namespace Microsoft.EntityFrameworkCore.TestUtilities -{ - public class FakeRelationalCommandDiagnosticsLogger - : FakeDiagnosticsLogger, IRelationalCommandDiagnosticsLogger - { - public InterceptionResult CommandCreating( - IRelationalConnection connection, - DbCommandMethod commandMethod, - DbContext? context, - Guid commandId, - Guid connectionId, - DateTimeOffset startTime, - CommandSource commandSource) - => default; - - public DbCommand CommandCreated( - IRelationalConnection connection, - DbCommand command, - DbCommandMethod commandMethod, - DbContext? context, - Guid commandId, - Guid connectionId, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource) - => command; - - public InterceptionResult CommandReaderExecuting( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - DateTimeOffset startTime, - CommandSource commandSource) - => default; - - public InterceptionResult CommandScalarExecuting( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - DateTimeOffset startTime, - CommandSource commandSource) - => default; - - public InterceptionResult CommandNonQueryExecuting( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - DateTimeOffset startTime, - CommandSource commandSource) - => default; - - public ValueTask> CommandReaderExecutingAsync( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - DateTimeOffset startTime, - CommandSource commandSource, - CancellationToken cancellationToken = default) - => default; - - public ValueTask> CommandScalarExecutingAsync( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - DateTimeOffset startTime, - CommandSource commandSource, - CancellationToken cancellationToken = default) - => default; - - public ValueTask> CommandNonQueryExecutingAsync( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - DateTimeOffset startTime, - CommandSource commandSource, - CancellationToken cancellationToken = default) - => default; - - public DbDataReader CommandReaderExecuted( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - DbDataReader methodResult, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource) - => methodResult; - - public object? CommandScalarExecuted( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - object? methodResult, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource) - => methodResult; - - public int CommandNonQueryExecuted( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - int methodResult, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource) - => methodResult; - - public ValueTask CommandReaderExecutedAsync( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - DbDataReader methodResult, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource, - CancellationToken cancellationToken = default) - => new(methodResult); - - public ValueTask CommandScalarExecutedAsync( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - object? methodResult, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource, - CancellationToken cancellationToken = default) - => new(methodResult); - - public ValueTask CommandNonQueryExecutedAsync( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - Guid commandId, - Guid connectionId, - int methodResult, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource, - CancellationToken cancellationToken = default) - => new(methodResult); - - public void CommandError( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - DbCommandMethod executeMethod, - Guid commandId, - Guid connectionId, - Exception exception, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource) - { - } - - public Task CommandErrorAsync( - IRelationalConnection connection, - DbCommand command, - DbContext? context, - DbCommandMethod executeMethod, - Guid commandId, - Guid connectionId, - Exception exception, - DateTimeOffset startTime, - TimeSpan duration, - CommandSource commandSource, - CancellationToken cancellationToken = default) - => Task.CompletedTask; - - public InterceptionResult DataReaderDisposing( - IRelationalConnection connection, - DbCommand command, - DbDataReader dataReader, - Guid commandId, - int recordsAffected, - int readCount, - DateTimeOffset startTime, - TimeSpan duration) - => default; - - public bool ShouldLogCommandCreate(DateTimeOffset now) - => true; - - public bool ShouldLogCommandExecute(DateTimeOffset now) - => true; - - public bool ShouldLogDataReaderDispose(DateTimeOffset now) - => true; - } -} diff --git a/test/EFCore.MySql.Tests/TestUtilities/TestModificationCommandBatchFactory.cs b/test/EFCore.MySql.Tests/TestUtilities/TestModificationCommandBatchFactory.cs deleted file mode 100644 index 92a5f46b4..000000000 --- a/test/EFCore.MySql.Tests/TestUtilities/TestModificationCommandBatchFactory.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.EntityFrameworkCore.Storage; -using Microsoft.EntityFrameworkCore.Update; - -namespace Microsoft.EntityFrameworkCore.TestUtilities -{ - public class TestModificationCommandBatchFactory : IModificationCommandBatchFactory - { - private readonly IRelationalCommandBuilderFactory _commandBuilderFactory; - private readonly ISqlGenerationHelper _sqlGenerationHelper; - private readonly IUpdateSqlGenerator _updateSqlGenerator; - private readonly IRelationalValueBufferFactoryFactory _valueBufferFactoryFactory; - - public TestModificationCommandBatchFactory( - IRelationalCommandBuilderFactory commandBuilderFactory, - ISqlGenerationHelper sqlGenerationHelper, - IUpdateSqlGenerator updateSqlGenerator, - IRelationalValueBufferFactoryFactory valueBufferFactoryFactory) - { - _commandBuilderFactory = commandBuilderFactory; - _sqlGenerationHelper = sqlGenerationHelper; - _updateSqlGenerator = updateSqlGenerator; - _valueBufferFactoryFactory = valueBufferFactoryFactory; - } - - public int CreateCount { get; private set; } - - public virtual ModificationCommandBatch Create() - { - CreateCount++; - - return new SingularModificationCommandBatch( - new ModificationCommandBatchFactoryDependencies( - _commandBuilderFactory, - _sqlGenerationHelper, - _updateSqlGenerator, - _valueBufferFactoryFactory, - null, - new FakeRelationalCommandDiagnosticsLogger())); - } - } -} diff --git a/tools/QueryBaselineUpdater/Program.cs b/tools/QueryBaselineUpdater/Program.cs index 8567b238c..ddae2ae00 100644 --- a/tools/QueryBaselineUpdater/Program.cs +++ b/tools/QueryBaselineUpdater/Program.cs @@ -9,7 +9,7 @@ internal static class Program { private static void Main(string[] args) { - const string assertSqlPattern = @"\s*AssertSql\(\s*@"".*?""\);\r?\n"; + const string assertSqlPattern = @"\s*Assert(?:ExecuteUpdate)?Sql\(\s*(?:(?:@?(""""""|"")).*?\1)?\);\r?\n"; var queryBaselineFilePath = args[0]; var testFilePath = args[1]; diff --git a/tools/QueryBaselineUpdater/QueryBaselineUpdater.csproj b/tools/QueryBaselineUpdater/QueryBaselineUpdater.csproj index 7b96d0181..82cad6d5e 100644 --- a/tools/QueryBaselineUpdater/QueryBaselineUpdater.csproj +++ b/tools/QueryBaselineUpdater/QueryBaselineUpdater.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net7.0