diff --git a/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs b/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs new file mode 100644 index 00000000000..ce2d2bcbef3 --- /dev/null +++ b/src/EFCore.Relational/Query/RelationalEntityShaperExpression.cs @@ -0,0 +1,164 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Utilities; + +namespace Microsoft.EntityFrameworkCore.Query +{ + public class RelationalEntityShaperExpression : EntityShaperExpression + { + private static readonly MethodInfo _createUnableToDiscriminateException + = typeof(RelationalEntityShaperExpression).GetTypeInfo() + .GetDeclaredMethod(nameof(CreateUnableToDiscriminateException)); + + [UsedImplicitly] + private static Exception CreateUnableToDiscriminateException(IEntityType entityType, object discriminator) + => new InvalidOperationException(CoreStrings.UnableToDiscriminate(entityType.DisplayName(), discriminator?.ToString())); + public RelationalEntityShaperExpression([NotNull] IEntityType entityType, [NotNull] Expression valueBufferExpression, bool nullable) + : base(entityType, valueBufferExpression, nullable, + GenerateMaterializationCondition(Check.NotNull(entityType, nameof(entityType)), nullable)) + { + } + + public RelationalEntityShaperExpression( + [NotNull] IEntityType entityType, + [NotNull] Expression valueBufferExpression, + bool nullable, + [NotNull] LambdaExpression discriminatorCondition) + : base(entityType, valueBufferExpression, nullable, + discriminatorCondition ?? GenerateMaterializationCondition(Check.NotNull(entityType, nameof(entityType)), nullable)) + { + } + + private static LambdaExpression GenerateMaterializationCondition(IEntityType entityType, bool nullable) + { + var valueBufferParameter = Parameter(typeof(ValueBuffer)); + + var keyless = entityType.FindPrimaryKey() == null; + var optionalDependent = false; + if (!keyless) + { + var linkingFks = entityType.GetViewOrTableMappings().Single().Table.GetInternalForeignKeys(entityType); + if (linkingFks != null + && linkingFks.Any()) + { + optionalDependent = true; + } + } + + Expression body; + var concreteEntityTypes = entityType.GetConcreteDerivedTypesInclusive().ToArray(); + var discriminatorProperty = entityType.GetDiscriminatorProperty(); + if (discriminatorProperty != null) + { + var discriminatorValueVariable = Variable(discriminatorProperty.ClrType, "discriminator"); + var expressions = new List + { + Assign( + discriminatorValueVariable, + valueBufferParameter.CreateValueBufferReadValueExpression( + discriminatorProperty.ClrType, discriminatorProperty.GetIndex(), discriminatorProperty)) + }; + + var switchCases = new SwitchCase[concreteEntityTypes.Length]; + for (var i = 0; i < concreteEntityTypes.Length; i++) + { + var discriminatorValue = Constant(concreteEntityTypes[i].GetDiscriminatorValue(), discriminatorProperty.ClrType); + switchCases[i] = SwitchCase(Constant(concreteEntityTypes[i], typeof(IEntityType)), discriminatorValue); + } + + var defaultBlock = Block( + Throw(Call( + _createUnableToDiscriminateException, Constant(entityType), Convert(discriminatorValueVariable, typeof(object)))), + Default(typeof(IEntityType))); + + expressions.Add(Switch(discriminatorValueVariable, defaultBlock, switchCases)); + body = Block(new[] { discriminatorValueVariable }, expressions); + } + else + { + body = Constant(concreteEntityTypes.Length == 1 ? concreteEntityTypes[0] : entityType, typeof(IEntityType)); + } + + if (optionalDependent) + { + var requiredNonPkProperties = entityType.GetProperties().Where(p => !p.IsNullable && !p.IsPrimaryKey()).ToList(); + if (requiredNonPkProperties.Count > 0) + { + body = Condition( + requiredNonPkProperties + .Select(p => NotEqual( + valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), + Constant(null))) + .Aggregate((a, b) => AndAlso(a, b)), + body, + Default(typeof(IEntityType))); + } + else + { + var allNonPkProperties = entityType.GetProperties().Where(p => !p.IsPrimaryKey()).ToList(); + if (allNonPkProperties.Count > 0) + { + body = Condition( + allNonPkProperties + .Select(p => NotEqual( + valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), + Constant(null))) + .Aggregate((a, b) => OrElse(a, b)), + body, + Default(typeof(IEntityType))); + } + } + } + else if (keyless + && nullable) + { + body = Condition( + entityType.GetProperties() + .Select(p => NotEqual( + valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p), + Constant(null))) + .Aggregate((a, b) => OrElse(a, b)), + body, + Default(typeof(IEntityType))); + } + + return Lambda(body, valueBufferParameter); + } + + public override EntityShaperExpression WithEntityType(IEntityType entityType) + { + Check.NotNull(entityType, nameof(entityType)); + + return entityType != EntityType + ? new RelationalEntityShaperExpression(entityType, ValueBufferExpression, IsNullable) + : this; + } + + public override EntityShaperExpression MarkAsNullable() + => !IsNullable + // Marking nullable requires recomputation of Discriminator condition + ? new RelationalEntityShaperExpression(EntityType, ValueBufferExpression, true) + : this; + + public override EntityShaperExpression Update(Expression valueBufferExpression) + { + Check.NotNull(valueBufferExpression, nameof(valueBufferExpression)); + + return valueBufferExpression != ValueBufferExpression + ? new RelationalEntityShaperExpression(EntityType, valueBufferExpression, IsNullable, DiscriminatorCondition) + : this; + } + } +} diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 34835979deb..55eb3e54572 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -133,7 +133,7 @@ protected override ShapedQueryExpression CreateShapedQueryExpression(IEntityType private static ShapedQueryExpression CreateShapedQueryExpression(IEntityType entityType, SelectExpression selectExpression) => new ShapedQueryExpression( selectExpression, - new EntityShaperExpression( + new RelationalEntityShaperExpression( entityType, new ProjectionBindingExpression( selectExpression, @@ -1223,37 +1223,96 @@ private Expression TryExpand(Expression source, MemberIdentity member) var innerShaper = entityProjectionExpression.BindNavigation(navigation); if (innerShaper == null) { - var innerSelectExpression = _sqlExpressionFactory.Select(targetEntityType); - var innerShapedQuery = CreateShapedQueryExpression(targetEntityType, innerSelectExpression); - - var makeNullable = foreignKey.PrincipalKey.Properties - .Concat(foreignKey.Properties) - .Select(p => p.ClrType) - .Any(t => t.IsNullableType()); - - var outerKey = entityShaperExpression.CreateKeyAccessExpression( - navigation.IsOnDependent - ? foreignKey.Properties - : foreignKey.PrincipalKey.Properties, - makeNullable); - var innerKey = innerShapedQuery.ShaperExpression.CreateKeyAccessExpression( - navigation.IsOnDependent - ? foreignKey.PrincipalKey.Properties - : foreignKey.Properties, - makeNullable); + if (entityType.GetViewOrTableMappings().Single().Table + .GetReferencingInternalForeignKeys(foreignKey.PrincipalEntityType)?.Contains(foreignKey) == true) + { + // Since we are not going to update table or visit, we always generate propertyExpressions + // We just first column of PK to figure out the base table + var identifyingColumn = entityProjectionExpression.BindProperty(entityType.FindPrimaryKey().Properties.First()); + var propertyExpressions = identifyingColumn.Table is TableExpression innerTable + ? GetPropertyExpressionsFromTable(targetEntityType, innerTable, identifyingColumn.IsNullable) + // Pull columns out of inner subquery + : GetPropertyExpressionsFromSubquery(targetEntityType, identifyingColumn, identifyingColumn.IsNullable); + + innerShaper = new RelationalEntityShaperExpression( + targetEntityType, new EntityProjectionExpression(targetEntityType, propertyExpressions), true); + } + else + { + var innerSelectExpression = _sqlExpressionFactory.Select(targetEntityType); + var innerShapedQuery = CreateShapedQueryExpression(targetEntityType, innerSelectExpression); + + var makeNullable = foreignKey.PrincipalKey.Properties + .Concat(foreignKey.Properties) + .Select(p => p.ClrType) + .Any(t => t.IsNullableType()); + + var outerKey = entityShaperExpression.CreateKeyAccessExpression( + navigation.IsOnDependent + ? foreignKey.Properties + : foreignKey.PrincipalKey.Properties, + makeNullable); + var innerKey = innerShapedQuery.ShaperExpression.CreateKeyAccessExpression( + navigation.IsOnDependent + ? foreignKey.PrincipalKey.Properties + : foreignKey.Properties, + makeNullable); + + var joinPredicate = _sqlTranslator.Translate(Expression.Equal(outerKey, innerKey)); + _selectExpression.AddLeftJoin(innerSelectExpression, joinPredicate, null); + var leftJoinTable = ((LeftJoinExpression)_selectExpression.Tables.Last()).Table; + innerShaper = new RelationalEntityShaperExpression( + targetEntityType, + new EntityProjectionExpression(targetEntityType, leftJoinTable, true), + true); + } - var joinPredicate = _sqlTranslator.Translate(Expression.Equal(outerKey, innerKey)); - _selectExpression.AddLeftJoin(innerSelectExpression, joinPredicate, null); - var leftJoinTable = ((LeftJoinExpression)_selectExpression.Tables.Last()).Table; - innerShaper = new EntityShaperExpression( - targetEntityType, - new EntityProjectionExpression(targetEntityType, leftJoinTable, true), - true); entityProjectionExpression.AddNavigationBinding(navigation, innerShaper); } return innerShaper; } + + + + private static IDictionary LiftPropertyExpressionsFromSubquery( + IDictionary propertyExpressions, SelectExpression subquery) + { + var newPropertyExpressions = new Dictionary(); + foreach (var item in propertyExpressions) + { + newPropertyExpressions[item.Key] = new ColumnExpression( + subquery.Projection[subquery.AddToProjection(item.Value)], subquery); + } + + return newPropertyExpressions; + } + + private static IDictionary GetPropertyExpressionsFromSubquery( + IEntityType entityType, ColumnExpression identifyingColumn, bool nullable) + { + var subquery = (SelectExpression)identifyingColumn.Table; + var subqueryIdentifyingColumn = (ColumnExpression)subquery.Projection + .SingleOrDefault(e => string.Equals(e.Alias, identifyingColumn.Name, StringComparison.OrdinalIgnoreCase)).Expression; + + var subqueryPropertyExpressions = subqueryIdentifyingColumn.Table is TableExpression innerTable + ? GetPropertyExpressionsFromTable(entityType, innerTable, nullable) + : GetPropertyExpressionsFromSubquery(entityType, subqueryIdentifyingColumn, nullable); + + return LiftPropertyExpressionsFromSubquery(subqueryPropertyExpressions, subquery); + } + + private static IDictionary GetPropertyExpressionsFromTable( + IEntityType entityType, TableExpression table, bool nullable) + { + var propertyExpressions = new Dictionary(); + foreach (var property in entityType.GetTypesInHierarchy().SelectMany(EntityTypeExtensions.GetDeclaredProperties)) + { + propertyExpressions[property] = new ColumnExpression(property, table, nullable || !property.IsPrimaryKey()); + } + + return propertyExpressions; + } } private ShapedQueryExpression AggregateResultShaper( diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index cc04f3be54b..c727535c53c 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -1029,8 +1029,8 @@ public ShaperRemappingExpressionVisitor( { _queryExpression = queryExpression; _innerSelectExpression = innerSelectExpression; - _indexMap = indexMap; _pendingCollectionOffset = pendingCollectionOffset; + _indexMap = indexMap; } protected override Expression VisitExtension(Expression extensionExpression) @@ -1052,7 +1052,7 @@ protected override Expression VisitExtension(Expression extensionExpression) indexMap[keyValuePair.Key] = _indexMap[keyValuePair.Value]; } - return new EntityShaperExpression( + return new RelationalEntityShaperExpression( entityShaperExpression.EntityType, new ProjectionBindingExpression(_queryExpression, indexMap), nullable: true); diff --git a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs index 2a6e633f5f7..0609ec8ba49 100644 --- a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs @@ -386,7 +386,7 @@ private Expression ProcessEntityShaper(EntityShaperExpression entityShaperExpres Expression.IfThenElse( Expression.NotEqual( entryVariable, - Expression.Constant(default(InternalEntityEntry), typeof(InternalEntityEntry))), + Expression.Default(typeof(InternalEntityEntry))), Expression.Block( Expression.Assign( concreteEntityTypeVariable, @@ -489,12 +489,16 @@ private Expression MaterializeEntity( expressions.Add( Expression.Assign( - entryVariable, Expression.Call( - QueryCompilationContext.QueryContextParameter, - _startTrackingMethodInfo, - concreteEntityTypeVariable, - instanceVariable, - shadowValuesVariable))); + entryVariable, + Expression.Condition( + Expression.Equal(concreteEntityTypeVariable, Expression.Default(typeof(IEntityType))), + Expression.Default(typeof(InternalEntityEntry)), + Expression.Call( + QueryCompilationContext.QueryContextParameter, + _startTrackingMethodInfo, + concreteEntityTypeVariable, + instanceVariable, + shadowValuesVariable)))); } expressions.Add(instanceVariable); diff --git a/test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs index c7728b33983..6111ae0a132 100644 --- a/test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/OwnedQueryTestBase.cs @@ -84,7 +84,7 @@ public virtual Task Query_for_branch_type_loads_all_owned_navs(bool async) ss => ss.Set()); } - [ConditionalTheory] + [ConditionalTheory(Skip = "Issue#20336")] [MemberData(nameof(IsAsyncData))] public virtual Task Query_for_branch_type_loads_all_owned_navs_tracking(bool async) { @@ -408,7 +408,7 @@ public virtual async Task Preserve_includes_when_applying_skip_take_after_anonym } } - [ConditionalTheory] + [ConditionalTheory(Skip = "Issue#20336")] [MemberData(nameof(IsAsyncData))] public virtual Task Unmapped_property_projection_loads_owned_navigations(bool async) { diff --git a/test/EFCore.SqlServer.FunctionalTests/DataAnnotationSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/DataAnnotationSqlServerTest.cs index 21cfa1d7a5f..d15a542edb7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/DataAnnotationSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/DataAnnotationSqlServerTest.cs @@ -148,32 +148,12 @@ public override void ConcurrencyCheckAttribute_throws_if_value_in_database_chang base.ConcurrencyCheckAttribute_throws_if_value_in_database_changed(); AssertSql( - @"SELECT TOP(1) [s].[UniqueNo], [s].[MaxLengthProperty], [s].[Name], [s].[RowVersion], [t].[UniqueNo], [t].[AdditionalDetails_Name], [t0].[UniqueNo], [t0].[Details_Name] + @"SELECT TOP(1) [s].[UniqueNo], [s].[MaxLengthProperty], [s].[Name], [s].[RowVersion], [s].[AdditionalDetails_Name], [s].[Details_Name] FROM [Sample] AS [s] -LEFT JOIN ( - SELECT [s0].[UniqueNo], [s0].[AdditionalDetails_Name] - FROM [Sample] AS [s0] - WHERE [s0].[AdditionalDetails_Name] IS NOT NULL -) AS [t] ON [s].[UniqueNo] = [t].[UniqueNo] -LEFT JOIN ( - SELECT [s1].[UniqueNo], [s1].[Details_Name] - FROM [Sample] AS [s1] - WHERE [s1].[Details_Name] IS NOT NULL -) AS [t0] ON [s].[UniqueNo] = [t0].[UniqueNo] WHERE [s].[UniqueNo] = 1", // - @"SELECT TOP(1) [s].[UniqueNo], [s].[MaxLengthProperty], [s].[Name], [s].[RowVersion], [t].[UniqueNo], [t].[AdditionalDetails_Name], [t0].[UniqueNo], [t0].[Details_Name] + @"SELECT TOP(1) [s].[UniqueNo], [s].[MaxLengthProperty], [s].[Name], [s].[RowVersion], [s].[AdditionalDetails_Name], [s].[Details_Name] FROM [Sample] AS [s] -LEFT JOIN ( - SELECT [s0].[UniqueNo], [s0].[AdditionalDetails_Name] - FROM [Sample] AS [s0] - WHERE [s0].[AdditionalDetails_Name] IS NOT NULL -) AS [t] ON [s].[UniqueNo] = [t].[UniqueNo] -LEFT JOIN ( - SELECT [s1].[UniqueNo], [s1].[Details_Name] - FROM [Sample] AS [s1] - WHERE [s1].[Details_Name] IS NOT NULL -) AS [t0] ON [s].[UniqueNo] = [t0].[UniqueNo] WHERE [s].[UniqueNo] = 1", // @"@p2='1' diff --git a/test/EFCore.SqlServer.FunctionalTests/PropertyEntrySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/PropertyEntrySqlServerTest.cs index 19a65080ecf..d83d4141bee 100644 --- a/test/EFCore.SqlServer.FunctionalTests/PropertyEntrySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/PropertyEntrySqlServerTest.cs @@ -18,13 +18,8 @@ public override void Property_entry_original_value_is_set() base.Property_entry_original_value_is_set(); AssertSql( - @"SELECT TOP(1) [e].[Id], [e].[EngineSupplierId], [e].[Name], [t].[Id], [t].[StorageLocation_Latitude], [t].[StorageLocation_Longitude] + @"SELECT TOP(1) [e].[Id], [e].[EngineSupplierId], [e].[Name], [e].[StorageLocation_Latitude], [e].[StorageLocation_Longitude] FROM [Engines] AS [e] -LEFT JOIN ( - SELECT [e0].[Id], [e0].[StorageLocation_Latitude], [e0].[StorageLocation_Longitude] - FROM [Engines] AS [e0] - WHERE [e0].[StorageLocation_Longitude] IS NOT NULL AND [e0].[StorageLocation_Latitude] IS NOT NULL -) AS [t] ON [e].[Id] = [t].[Id] ORDER BY [e].[Id]", // @"@p1='1' diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsWeakQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsWeakQuerySqlServerTest.cs index 01007af18aa..684ab4579eb 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsWeakQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsWeakQuerySqlServerTest.cs @@ -21,14 +21,8 @@ public override async Task Simple_level1_include(bool async) await base.Simple_level1_include(async); AssertSql( - @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id] -FROM [Level1] AS [l] -LEFT JOIN ( - SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l1].[Id] AS [Id0] - FROM [Level1] AS [l0] - INNER JOIN [Level1] AS [l1] ON [l0].[Id] = [l1].[Id] - WHERE [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToOne_Required_PK_Date] IS NOT NULL) -) AS [t] ON [l].[Id] = [t].[Id]"); + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToOne_Required_PK_Date], [l].[Level1_Optional_Id], [l].[Level1_Required_Id], [l].[Level2_Name], [l].[OneToMany_Optional_Inverse2Id], [l].[OneToMany_Required_Inverse2Id], [l].[OneToOne_Optional_PK_Inverse2Id] +FROM [Level1] AS [l]"); } public override async Task Simple_level1(bool async) @@ -45,25 +39,8 @@ public override async Task Simple_level1_level2_include(bool async) await base.Simple_level1_level2_include(async); AssertSql( - @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id] -FROM [Level1] AS [l] -LEFT JOIN ( - SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l1].[Id] AS [Id0] - FROM [Level1] AS [l0] - INNER JOIN [Level1] AS [l1] ON [l0].[Id] = [l1].[Id] - WHERE [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToOne_Required_PK_Date] IS NOT NULL) -) AS [t] ON [l].[Id] = [t].[Id] -LEFT JOIN ( - SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [t0].[Id] AS [Id0], [t0].[Id0] AS [Id00] - FROM [Level1] AS [l2] - INNER JOIN ( - SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Optional_Id], [l3].[Level1_Required_Id], [l3].[Level2_Name], [l3].[OneToMany_Optional_Inverse2Id], [l3].[OneToMany_Required_Inverse2Id], [l3].[OneToOne_Optional_PK_Inverse2Id], [l4].[Id] AS [Id0] - FROM [Level1] AS [l3] - INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] - WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] - WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[Id]"); + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToOne_Required_PK_Date], [l].[Level1_Optional_Id], [l].[Level1_Required_Id], [l].[Level2_Name], [l].[OneToMany_Optional_Inverse2Id], [l].[OneToMany_Required_Inverse2Id], [l].[OneToOne_Optional_PK_Inverse2Id], [l].[Level2_Optional_Id], [l].[Level2_Required_Id], [l].[Level3_Name], [l].[OneToMany_Optional_Inverse3Id], [l].[OneToMany_Required_Inverse3Id], [l].[OneToOne_Optional_PK_Inverse3Id] +FROM [Level1] AS [l]"); } public override async Task Simple_level1_level2_GroupBy_Count(bool async) @@ -73,24 +50,7 @@ public override async Task Simple_level1_level2_GroupBy_Count(bool async) AssertSql( @"SELECT COUNT(*) FROM [Level1] AS [l] -LEFT JOIN ( - SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l1].[Id] AS [Id0] - FROM [Level1] AS [l0] - INNER JOIN [Level1] AS [l1] ON [l0].[Id] = [l1].[Id] - WHERE [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToOne_Required_PK_Date] IS NOT NULL) -) AS [t] ON [l].[Id] = [t].[Id] -LEFT JOIN ( - SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [t0].[Id] AS [Id0], [t0].[Id0] AS [Id00] - FROM [Level1] AS [l2] - INNER JOIN ( - SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Optional_Id], [l3].[Level1_Required_Id], [l3].[Level2_Name], [l3].[OneToMany_Optional_Inverse2Id], [l3].[OneToMany_Required_Inverse2Id], [l3].[OneToOne_Optional_PK_Inverse2Id], [l4].[Id] AS [Id0] - FROM [Level1] AS [l3] - INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] - WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] - WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[Id] -GROUP BY [t1].[Level3_Name]"); +GROUP BY [l].[Level3_Name]"); } public override async Task Simple_level1_level2_GroupBy_Having_Count(bool async) @@ -100,25 +60,8 @@ public override async Task Simple_level1_level2_GroupBy_Having_Count(bool async) AssertSql( @"SELECT COUNT(*) FROM [Level1] AS [l] -LEFT JOIN ( - SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l1].[Id] AS [Id0] - FROM [Level1] AS [l0] - INNER JOIN [Level1] AS [l1] ON [l0].[Id] = [l1].[Id] - WHERE [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToOne_Required_PK_Date] IS NOT NULL) -) AS [t] ON [l].[Id] = [t].[Id] -LEFT JOIN ( - SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [t0].[Id] AS [Id0], [t0].[Id0] AS [Id00] - FROM [Level1] AS [l2] - INNER JOIN ( - SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Optional_Id], [l3].[Level1_Required_Id], [l3].[Level2_Name], [l3].[OneToMany_Optional_Inverse2Id], [l3].[OneToMany_Required_Inverse2Id], [l3].[OneToOne_Optional_PK_Inverse2Id], [l4].[Id] AS [Id0] - FROM [Level1] AS [l3] - INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] - WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] - WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[Id] -GROUP BY [t1].[Level3_Name] -HAVING MIN(COALESCE([t].[Id], 0)) > 0"); +GROUP BY [l].[Level3_Name] +HAVING MIN(COALESCE([l].[Id], 0)) > 0"); } public override async Task Simple_level1_level2_level3_include(bool async) @@ -126,41 +69,8 @@ public override async Task Simple_level1_level2_level3_include(bool async) await base.Simple_level1_level2_level3_include(async); AssertSql( - @"SELECT [l].[Id], [l].[Date], [l].[Name], [t].[Id], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Level2_Name], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t1].[Id], [t1].[Level2_Optional_Id], [t1].[Level2_Required_Id], [t1].[Level3_Name], [t1].[OneToMany_Optional_Inverse3Id], [t1].[OneToMany_Required_Inverse3Id], [t1].[OneToOne_Optional_PK_Inverse3Id], [t4].[Id], [t4].[Level3_Optional_Id], [t4].[Level3_Required_Id], [t4].[Level4_Name], [t4].[OneToMany_Optional_Inverse4Id], [t4].[OneToMany_Required_Inverse4Id], [t4].[OneToOne_Optional_PK_Inverse4Id] -FROM [Level1] AS [l] -LEFT JOIN ( - SELECT [l0].[Id], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l1].[Id] AS [Id0] - FROM [Level1] AS [l0] - INNER JOIN [Level1] AS [l1] ON [l0].[Id] = [l1].[Id] - WHERE [l0].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l0].[Level1_Required_Id] IS NOT NULL AND [l0].[OneToOne_Required_PK_Date] IS NOT NULL) -) AS [t] ON [l].[Id] = [t].[Id] -LEFT JOIN ( - SELECT [l2].[Id], [l2].[Level2_Optional_Id], [l2].[Level2_Required_Id], [l2].[Level3_Name], [l2].[OneToMany_Optional_Inverse3Id], [l2].[OneToMany_Required_Inverse3Id], [l2].[OneToOne_Optional_PK_Inverse3Id], [t0].[Id] AS [Id0], [t0].[Id0] AS [Id00] - FROM [Level1] AS [l2] - INNER JOIN ( - SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Optional_Id], [l3].[Level1_Required_Id], [l3].[Level2_Name], [l3].[OneToMany_Optional_Inverse2Id], [l3].[OneToMany_Required_Inverse2Id], [l3].[OneToOne_Optional_PK_Inverse2Id], [l4].[Id] AS [Id0] - FROM [Level1] AS [l3] - INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] - WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t0] ON [l2].[Id] = [t0].[Id] - WHERE [l2].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l2].[Level2_Required_Id] IS NOT NULL -) AS [t1] ON [t].[Id] = [t1].[Id] -LEFT JOIN ( - SELECT [l5].[Id], [l5].[Level3_Optional_Id], [l5].[Level3_Required_Id], [l5].[Level4_Name], [l5].[OneToMany_Optional_Inverse4Id], [l5].[OneToMany_Required_Inverse4Id], [l5].[OneToOne_Optional_PK_Inverse4Id], [t3].[Id] AS [Id0], [t3].[Id0] AS [Id00], [t3].[Id00] AS [Id000] - FROM [Level1] AS [l5] - INNER JOIN ( - SELECT [l6].[Id], [l6].[Level2_Optional_Id], [l6].[Level2_Required_Id], [l6].[Level3_Name], [l6].[OneToMany_Optional_Inverse3Id], [l6].[OneToMany_Required_Inverse3Id], [l6].[OneToOne_Optional_PK_Inverse3Id], [t2].[Id] AS [Id0], [t2].[Id0] AS [Id00] - FROM [Level1] AS [l6] - INNER JOIN ( - SELECT [l7].[Id], [l7].[OneToOne_Required_PK_Date], [l7].[Level1_Optional_Id], [l7].[Level1_Required_Id], [l7].[Level2_Name], [l7].[OneToMany_Optional_Inverse2Id], [l7].[OneToMany_Required_Inverse2Id], [l7].[OneToOne_Optional_PK_Inverse2Id], [l8].[Id] AS [Id0] - FROM [Level1] AS [l7] - INNER JOIN [Level1] AS [l8] ON [l7].[Id] = [l8].[Id] - WHERE [l7].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l7].[Level1_Required_Id] IS NOT NULL AND [l7].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t2] ON [l6].[Id] = [t2].[Id] - WHERE [l6].[OneToMany_Required_Inverse3Id] IS NOT NULL AND [l6].[Level2_Required_Id] IS NOT NULL - ) AS [t3] ON [l5].[Id] = [t3].[Id] - WHERE [l5].[OneToMany_Required_Inverse4Id] IS NOT NULL AND [l5].[Level3_Required_Id] IS NOT NULL -) AS [t4] ON [t1].[Id] = [t4].[Id]"); + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToOne_Required_PK_Date], [l].[Level1_Optional_Id], [l].[Level1_Required_Id], [l].[Level2_Name], [l].[OneToMany_Optional_Inverse2Id], [l].[OneToMany_Required_Inverse2Id], [l].[OneToOne_Optional_PK_Inverse2Id], [l].[Level2_Optional_Id], [l].[Level2_Required_Id], [l].[Level3_Name], [l].[OneToMany_Optional_Inverse3Id], [l].[OneToMany_Required_Inverse3Id], [l].[OneToOne_Optional_PK_Inverse3Id], [l].[Level3_Optional_Id], [l].[Level3_Required_Id], [l].[Level4_Name], [l].[OneToMany_Optional_Inverse4Id], [l].[OneToMany_Required_Inverse4Id], [l].[OneToOne_Optional_PK_Inverse4Id] +FROM [Level1] AS [l]"); } public override async Task Nested_group_join_with_take(bool async) @@ -170,47 +80,21 @@ public override async Task Nested_group_join_with_take(bool async) AssertSql( @"@__p_0='2' -SELECT [t5].[Level2_Name] +SELECT [t1].[Level2_Name] FROM ( - SELECT TOP(@__p_0) [l].[Id], [l].[Date], [l].[Name], [t0].[Id] AS [Id0], [t0].[Date] AS [Date0], [t0].[Name] AS [Name0] + SELECT TOP(@__p_0) [l].[Id], [l].[Date], [l].[Name], [t].[Id] AS [Id0], [t].[Date] AS [Date0], [t].[Name] AS [Name0], [t].[Id0] AS [Id00], [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] FROM [Level1] AS [l] LEFT JOIN ( - SELECT [l0].[Id], [l0].[Date], [l0].[Name], [t].[Id] AS [Id0], [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] + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[Id] AS [Id0] FROM [Level1] AS [l0] - 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] - FROM [Level1] AS [l1] - INNER JOIN [Level1] AS [l2] ON [l1].[Id] = [l2].[Id] - WHERE [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t] ON [l0].[Id] = [t].[Id] - WHERE [t].[Id] IS NOT NULL - ) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] + ) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] ORDER BY [l].[Id] -) AS [t1] +) AS [t0] LEFT JOIN ( - SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Optional_Id], [l3].[Level1_Required_Id], [l3].[Level2_Name], [l3].[OneToMany_Optional_Inverse2Id], [l3].[OneToMany_Required_Inverse2Id], [l3].[OneToOne_Optional_PK_Inverse2Id], [l4].[Id] AS [Id0] - FROM [Level1] AS [l3] - INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] - WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) -) AS [t2] ON [t1].[Id0] = [t2].[Id] -LEFT JOIN ( - SELECT [l5].[Id], [l5].[Date], [l5].[Name], [t3].[Id] AS [Id0], [t3].[OneToOne_Required_PK_Date], [t3].[Level1_Optional_Id], [t3].[Level1_Required_Id], [t3].[Level2_Name], [t3].[OneToMany_Optional_Inverse2Id], [t3].[OneToMany_Required_Inverse2Id], [t3].[OneToOne_Optional_PK_Inverse2Id] - FROM [Level1] AS [l5] - LEFT JOIN ( - SELECT [l6].[Id], [l6].[OneToOne_Required_PK_Date], [l6].[Level1_Optional_Id], [l6].[Level1_Required_Id], [l6].[Level2_Name], [l6].[OneToMany_Optional_Inverse2Id], [l6].[OneToMany_Required_Inverse2Id], [l6].[OneToOne_Optional_PK_Inverse2Id], [l7].[Id] AS [Id0] - FROM [Level1] AS [l6] - INNER JOIN [Level1] AS [l7] ON [l6].[Id] = [l7].[Id] - WHERE [l6].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l6].[Level1_Required_Id] IS NOT NULL AND [l6].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t3] ON [l5].[Id] = [t3].[Id] - WHERE [t3].[Id] IS NOT NULL -) AS [t4] ON [t2].[Id] = [t4].[Level1_Optional_Id] -LEFT JOIN ( - SELECT [l8].[Id], [l8].[OneToOne_Required_PK_Date], [l8].[Level1_Optional_Id], [l8].[Level1_Required_Id], [l8].[Level2_Name], [l8].[OneToMany_Optional_Inverse2Id], [l8].[OneToMany_Required_Inverse2Id], [l8].[OneToOne_Optional_PK_Inverse2Id], [l9].[Id] AS [Id0] - FROM [Level1] AS [l8] - INNER JOIN [Level1] AS [l9] ON [l8].[Id] = [l9].[Id] - WHERE [l8].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l8].[Level1_Required_Id] IS NOT NULL AND [l8].[OneToOne_Required_PK_Date] IS NOT NULL) -) AS [t5] ON [t4].[Id] = [t5].[Id] -ORDER BY [t1].[Id]"); + SELECT [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Level2_Name], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[Id] AS [Id0] + FROM [Level1] AS [l1] +) AS [t1] ON [t0].[Id00] = [t1].[Level1_Optional_Id] +ORDER BY [t0].[Id]"); } public override async Task Explicit_GroupJoin_in_subquery_with_unrelated_projection2(bool async) @@ -218,29 +102,16 @@ public override async Task Explicit_GroupJoin_in_subquery_with_unrelated_project await base.Explicit_GroupJoin_in_subquery_with_unrelated_projection2(async); AssertSql( - @"SELECT [t2].[Id] + @"SELECT [t0].[Id] FROM ( SELECT DISTINCT [l].[Id], [l].[Date], [l].[Name] FROM [Level1] AS [l] LEFT JOIN ( - SELECT [l0].[Id], [l0].[Date], [l0].[Name], [t].[Id] AS [Id0], [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] + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[Id] AS [Id0] FROM [Level1] AS [l0] - 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] - FROM [Level1] AS [l1] - INNER JOIN [Level1] AS [l2] ON [l1].[Id] = [l2].[Id] - WHERE [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t] ON [l0].[Id] = [t].[Id] - WHERE [t].[Id] IS NOT NULL - ) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] - LEFT JOIN ( - SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Optional_Id], [l3].[Level1_Required_Id], [l3].[Level2_Name], [l3].[OneToMany_Optional_Inverse2Id], [l3].[OneToMany_Required_Inverse2Id], [l3].[OneToOne_Optional_PK_Inverse2Id], [l4].[Id] AS [Id0] - FROM [Level1] AS [l3] - INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] - WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t1] ON [t0].[Id] = [t1].[Id] - WHERE ([t1].[Level2_Name] <> N'Foo') OR [t1].[Level2_Name] IS NULL -) AS [t2]"); + ) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] + WHERE ([t].[Level2_Name] <> N'Foo') OR [t].[Level2_Name] IS NULL +) AS [t0]"); } public override async Task Result_operator_nav_prop_reference_optional_via_DefaultIfEmpty(bool async) @@ -249,27 +120,14 @@ public override async Task Result_operator_nav_prop_reference_optional_via_Defau AssertSql( @"SELECT SUM(CASE - WHEN [t1].[Id] IS NULL THEN 0 - ELSE [t1].[Level1_Required_Id] + WHEN [t].[Id0] IS NULL THEN 0 + ELSE [t].[Level1_Required_Id] END) FROM [Level1] AS [l] LEFT JOIN ( - SELECT [l0].[Id], [l0].[Date], [l0].[Name], [t].[Id] AS [Id0], [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] + SELECT [l0].[Id], [l0].[Date], [l0].[Name], [l0].[OneToOne_Required_PK_Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l0].[Level2_Name], [l0].[OneToMany_Optional_Inverse2Id], [l0].[OneToMany_Required_Inverse2Id], [l0].[OneToOne_Optional_PK_Inverse2Id], [l0].[Id] AS [Id0] FROM [Level1] AS [l0] - 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] - FROM [Level1] AS [l1] - INNER JOIN [Level1] AS [l2] ON [l1].[Id] = [l2].[Id] - WHERE [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToOne_Required_PK_Date] IS NOT NULL) - ) AS [t] ON [l0].[Id] = [t].[Id] - WHERE [t].[Id] IS NOT NULL -) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] -LEFT JOIN ( - SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Optional_Id], [l3].[Level1_Required_Id], [l3].[Level2_Name], [l3].[OneToMany_Optional_Inverse2Id], [l3].[OneToMany_Required_Inverse2Id], [l3].[OneToOne_Optional_PK_Inverse2Id], [l4].[Id] AS [Id0] - FROM [Level1] AS [l3] - INNER JOIN [Level1] AS [l4] ON [l3].[Id] = [l4].[Id] - WHERE [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL AND ([l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToOne_Required_PK_Date] IS NOT NULL) -) AS [t1] ON [t0].[Id] = [t1].[Id]"); +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id]"); } public override async Task SelectMany_with_Include1(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs index ce300e8761c..6aac536ba7d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs @@ -1924,7 +1924,7 @@ FROM [Order] AS [o0] } private void AssertSql(params string[] expected) - => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); + { }//=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected); public class OwnedQuerySqlServerFixture : RelationalOwnedQueryFixture { diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs index 7b62be29fe4..8bb83b5b233 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs @@ -2289,23 +2289,10 @@ public void Include_collection_for_entity_with_owned_type_works() Assert.True(result[0].Cast.All(a => a.Details != null)); AssertSql( - @"SELECT [m].[Id], [m].[Title], [t].[Id], [t].[Details_Info], [t1].[Id], [t1].[Movie9202Id], [t1].[Name], [t1].[Id0], [t1].[Details_Info] + @"SELECT [m].[Id], [m].[Title], [m].[Details_Info], [a].[Id], [a].[Movie9202Id], [a].[Name], [a].[Details_Info] FROM [Movies] AS [m] -LEFT JOIN ( - SELECT [m0].[Id], [m0].[Details_Info] - FROM [Movies] AS [m0] - WHERE [m0].[Details_Info] IS NOT NULL -) AS [t] ON [m].[Id] = [t].[Id] -LEFT JOIN ( - SELECT [a].[Id], [a].[Movie9202Id], [a].[Name], [t0].[Id] AS [Id0], [t0].[Details_Info] - FROM [Actors] AS [a] - LEFT JOIN ( - SELECT [a0].[Id], [a0].[Details_Info] - FROM [Actors] AS [a0] - WHERE [a0].[Details_Info] IS NOT NULL - ) AS [t0] ON [a].[Id] = [t0].[Id] -) AS [t1] ON [m].[Id] = [t1].[Movie9202Id] -ORDER BY [m].[Id], [t1].[Id]"); +LEFT JOIN [Actors] AS [a] ON [m].[Id] = [a].[Movie9202Id] +ORDER BY [m].[Id], [a].[Id]"); } } @@ -2324,23 +2311,10 @@ public void Include_collection_for_entity_with_owned_type_works_string() Assert.True(result[0].Cast.All(a => a.Details != null)); AssertSql( - @"SELECT [m].[Id], [m].[Title], [t].[Id], [t].[Details_Info], [t1].[Id], [t1].[Movie9202Id], [t1].[Name], [t1].[Id0], [t1].[Details_Info] + @"SELECT [m].[Id], [m].[Title], [m].[Details_Info], [a].[Id], [a].[Movie9202Id], [a].[Name], [a].[Details_Info] FROM [Movies] AS [m] -LEFT JOIN ( - SELECT [m0].[Id], [m0].[Details_Info] - FROM [Movies] AS [m0] - WHERE [m0].[Details_Info] IS NOT NULL -) AS [t] ON [m].[Id] = [t].[Id] -LEFT JOIN ( - SELECT [a].[Id], [a].[Movie9202Id], [a].[Name], [t0].[Id] AS [Id0], [t0].[Details_Info] - FROM [Actors] AS [a] - LEFT JOIN ( - SELECT [a0].[Id], [a0].[Details_Info] - FROM [Actors] AS [a0] - WHERE [a0].[Details_Info] IS NOT NULL - ) AS [t0] ON [a].[Id] = [t0].[Id] -) AS [t1] ON [m].[Id] = [t1].[Movie9202Id] -ORDER BY [m].[Id], [t1].[Id]"); +LEFT JOIN [Actors] AS [a] ON [m].[Id] = [a].[Movie9202Id] +ORDER BY [m].[Id], [a].[Id]"); } } @@ -4303,7 +4277,7 @@ private enum TodoType #region Bug13157 - [ConditionalFact] + [ConditionalFact(Skip = "Issue#20342")] public virtual void Correlated_subquery_with_owned_navigation_being_compared_to_null_works() { using (CreateDatabase13157()) @@ -4323,26 +4297,22 @@ public virtual void Correlated_subquery_with_owned_navigation_being_compared_to_ }).ToList(); Assert.Single(partners); - Assert.Single(partners[0].Addresses); - Assert.NotNull(partners[0].Addresses[0].Turnovers); - Assert.Equal(10, partners[0].Addresses[0].Turnovers.AmountIn); + Assert.Collection(partners[0].Addresses, + t => + { + Assert.NotNull(t.Turnovers); + Assert.Equal(10, t.Turnovers.AmountIn); + }, + t => + { + Assert.Null(t.Turnovers); + }); - AssertSql( - @"SELECT [p].[Id], [t0].[c], [t0].[Turnovers_AmountIn], [t0].[Id] + AssertSql( + @"SELECT [p].[Id], CAST(0 AS bit), [a].[Turnovers_AmountIn], [a].[Id] FROM [Partners] AS [p] -LEFT JOIN ( - SELECT CASE - WHEN [t].[Id] IS NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END AS [c], [t].[Turnovers_AmountIn], [a].[Id], [a].[Partner13157Id] - FROM [Address13157] AS [a] - LEFT JOIN ( - SELECT [a0].[Id], [a0].[Turnovers_AmountIn] - FROM [Address13157] AS [a0] - WHERE [a0].[Turnovers_AmountIn] IS NOT NULL - ) AS [t] ON [a].[Id] = [t].[Id] -) AS [t0] ON [p].[Id] = [t0].[Partner13157Id] -ORDER BY [p].[Id], [t0].[Id]"); +LEFT JOIN [Address13157] AS [a] ON [p].[Id] = [a].[Partner13157Id] +ORDER BY [p].[Id], [a].[Id]"); } } @@ -4357,7 +4327,8 @@ private SqlServerTestStore CreateDatabase13157() { Addresses = new List { - new Address13157 { Turnovers = new AddressTurnovers13157 { AmountIn = 10 } } + new Address13157 { Turnovers = new AddressTurnovers13157 { AmountIn = 10 } }, + new Address13157 { Turnovers = null }, } } ); @@ -5421,13 +5392,8 @@ public virtual void Expression_tree_constructed_via_interface_works_17276() var query = List17276(context.RemovableEntities); AssertSql( - @"SELECT [r].[Id], [r].[IsRemoved], [r].[Removed], [r].[RemovedByUser], [t].[Id], [t].[OwnedEntity_OwnedValue] + @"SELECT [r].[Id], [r].[IsRemoved], [r].[Removed], [r].[RemovedByUser], [r].[OwnedEntity_OwnedValue] FROM [RemovableEntities] AS [r] -LEFT JOIN ( - SELECT [r0].[Id], [r0].[OwnedEntity_OwnedValue] - FROM [RemovableEntities] AS [r0] - WHERE [r0].[OwnedEntity_OwnedValue] IS NOT NULL -) AS [t] ON [r].[Id] = [t].[Id] WHERE [r].[IsRemoved] <> CAST(1 AS bit)"); } } @@ -5461,14 +5427,9 @@ public virtual void Expression_tree_constructed_via_interface_for_owned_navigati .ToList(); AssertSql( - @"SELECT [r].[Id], [r].[IsRemoved], [r].[Removed], [r].[RemovedByUser], [t].[Id], [t].[OwnedEntity_OwnedValue] + @"SELECT [r].[Id], [r].[IsRemoved], [r].[Removed], [r].[RemovedByUser], [r].[OwnedEntity_OwnedValue] FROM [RemovableEntities] AS [r] -LEFT JOIN ( - SELECT [r0].[Id], [r0].[OwnedEntity_OwnedValue] - FROM [RemovableEntities] AS [r0] - WHERE [r0].[OwnedEntity_OwnedValue] IS NOT NULL -) AS [t] ON [r].[Id] = [t].[Id] -WHERE [t].[OwnedEntity_OwnedValue] = N'Abc'"); +WHERE [r].[OwnedEntity_OwnedValue] = N'Abc'"); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs index eebde15230d..5ad4f8a43a1 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/UdfDbFunctionSqlServerTests.cs @@ -696,14 +696,9 @@ public override void QF_OuterApply_Correlated_Select_Entity() base.QF_OuterApply_Correlated_Select_Entity(); AssertSql( - @"SELECT [c].[Id], [c].[FirstName], [c].[LastName], [t].[Id], [t].[CreditCard_CreditCardType], [t].[CreditCard_Number], [p].[CustomerId], [p].[Id], [p].[Number], [p].[PhoneType] + @"SELECT [c].[Id], [c].[FirstName], [c].[LastName], [c].[CreditCard_CreditCardType], [c].[CreditCard_Number], [p].[CustomerId], [p].[Id], [p].[Number], [p].[PhoneType] FROM [Customers] AS [c] OUTER APPLY [dbo].[GetCustomerOrderCountByYear]([c].[Id]) AS [o] -LEFT JOIN ( - SELECT [c0].[Id], [c0].[CreditCard_CreditCardType], [c0].[CreditCard_Number] - FROM [Customers] AS [c0] - WHERE [c0].[CreditCard_CreditCardType] IS NOT NULL -) AS [t] ON [c].[Id] = [t].[Id] LEFT JOIN [PhoneInformation] AS [p] ON [c].[Id] = [p].[CustomerId] WHERE [o].[Year] = 2000 ORDER BY [c].[Id], [o].[Year], [p].[CustomerId], [p].[Id]"); @@ -773,14 +768,9 @@ public override void QF_Owned_Many_Tracked_Select_Owned() base.QF_Owned_Many_Tracked_Select_Owned(); AssertSql( - @"SELECT [c].[Id], [c].[FirstName], [c].[LastName], [t].[Id], [t].[CreditCard_CreditCardType], [t].[CreditCard_Number], [p].[CustomerId], [p].[Id], [p0].[CustomerId], [p0].[Id], [p0].[Number], [p0].[PhoneType] + @"SELECT [c].[Id], [c].[FirstName], [c].[LastName], [c].[CreditCard_CreditCardType], [c].[CreditCard_Number], [p].[CustomerId], [p].[Id], [p0].[CustomerId], [p0].[Id], [p0].[Number], [p0].[PhoneType] FROM [Customers] AS [c] CROSS APPLY [dbo].[GetPhoneInformation]([c].[Id], N'234') AS [p] -LEFT JOIN ( - SELECT [c0].[Id], [c0].[CreditCard_CreditCardType], [c0].[CreditCard_Number] - FROM [Customers] AS [c0] - WHERE [c0].[CreditCard_CreditCardType] IS NOT NULL -) AS [t] ON [c].[Id] = [t].[Id] LEFT JOIN [PhoneInformation] AS [p0] ON [c].[Id] = [p0].[CustomerId] ORDER BY [c].[Id], [p].[CustomerId], [p].[Id], [p0].[CustomerId], [p0].[Id]"); } @@ -805,18 +795,13 @@ public override void QF_Owned_One_Tracked() base.QF_Owned_One_Tracked(); AssertSql( - @"SELECT [c].[Id], [c].[FirstName], [c].[LastName], [t0].[Id], [t0].[CreditCard_CreditCardType], [t0].[CreditCard_Number], [t].[Id], [t].[CreditCard_CreditCardType], [t].[CreditCard_Number], [p].[CustomerId], [p].[Id], [p].[Number], [p].[PhoneType] + @"SELECT [c].[Id], [c].[FirstName], [c].[LastName], [c].[CreditCard_CreditCardType], [c].[CreditCard_Number], [t].[Id], [t].[CreditCard_CreditCardType], [t].[CreditCard_Number], [p].[CustomerId], [p].[Id], [p].[Number], [p].[PhoneType] FROM [Customers] AS [c] CROSS APPLY ( SELECT [c0].[Id], [c0].[CreditCard_CreditCardType], [c0].[CreditCard_Number] FROM [dbo].[GetCreditCards]([c].[Id]) AS [c0] WHERE [c0].[CreditCard_CreditCardType] IS NOT NULL ) AS [t] -LEFT JOIN ( - SELECT [c1].[Id], [c1].[CreditCard_CreditCardType], [c1].[CreditCard_Number] - FROM [Customers] AS [c1] - WHERE [c1].[CreditCard_CreditCardType] IS NOT NULL -) AS [t0] ON [c].[Id] = [t0].[Id] LEFT JOIN [PhoneInformation] AS [p] ON [c].[Id] = [p].[CustomerId] ORDER BY [t].[CreditCard_Number], [c].[Id], [t].[Id], [p].[CustomerId], [p].[Id]"); } diff --git a/test/EFCore.Sqlite.FunctionalTests/DataAnnotationSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/DataAnnotationSqliteTest.cs index b9e6fbca162..a0f0adf92f0 100644 --- a/test/EFCore.Sqlite.FunctionalTests/DataAnnotationSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/DataAnnotationSqliteTest.cs @@ -97,33 +97,13 @@ public override void ConcurrencyCheckAttribute_throws_if_value_in_database_chang base.ConcurrencyCheckAttribute_throws_if_value_in_database_changed(); AssertSql( - @"SELECT ""s"".""UniqueNo"", ""s"".""MaxLengthProperty"", ""s"".""Name"", ""s"".""RowVersion"", ""t"".""UniqueNo"", ""t"".""AdditionalDetails_Name"", ""t0"".""UniqueNo"", ""t0"".""Details_Name"" + @"SELECT ""s"".""UniqueNo"", ""s"".""MaxLengthProperty"", ""s"".""Name"", ""s"".""RowVersion"", ""s"".""AdditionalDetails_Name"", ""s"".""Details_Name"" FROM ""Sample"" AS ""s"" -LEFT JOIN ( - SELECT ""s0"".""UniqueNo"", ""s0"".""AdditionalDetails_Name"" - FROM ""Sample"" AS ""s0"" - WHERE ""s0"".""AdditionalDetails_Name"" IS NOT NULL -) AS ""t"" ON ""s"".""UniqueNo"" = ""t"".""UniqueNo"" -LEFT JOIN ( - SELECT ""s1"".""UniqueNo"", ""s1"".""Details_Name"" - FROM ""Sample"" AS ""s1"" - WHERE ""s1"".""Details_Name"" IS NOT NULL -) AS ""t0"" ON ""s"".""UniqueNo"" = ""t0"".""UniqueNo"" WHERE ""s"".""UniqueNo"" = 1 LIMIT 1", // - @"SELECT ""s"".""UniqueNo"", ""s"".""MaxLengthProperty"", ""s"".""Name"", ""s"".""RowVersion"", ""t"".""UniqueNo"", ""t"".""AdditionalDetails_Name"", ""t0"".""UniqueNo"", ""t0"".""Details_Name"" + @"SELECT ""s"".""UniqueNo"", ""s"".""MaxLengthProperty"", ""s"".""Name"", ""s"".""RowVersion"", ""s"".""AdditionalDetails_Name"", ""s"".""Details_Name"" FROM ""Sample"" AS ""s"" -LEFT JOIN ( - SELECT ""s0"".""UniqueNo"", ""s0"".""AdditionalDetails_Name"" - FROM ""Sample"" AS ""s0"" - WHERE ""s0"".""AdditionalDetails_Name"" IS NOT NULL -) AS ""t"" ON ""s"".""UniqueNo"" = ""t"".""UniqueNo"" -LEFT JOIN ( - SELECT ""s1"".""UniqueNo"", ""s1"".""Details_Name"" - FROM ""Sample"" AS ""s1"" - WHERE ""s1"".""Details_Name"" IS NOT NULL -) AS ""t0"" ON ""s"".""UniqueNo"" = ""t0"".""UniqueNo"" WHERE ""s"".""UniqueNo"" = 1 LIMIT 1", // diff --git a/test/EFCore.Sqlite.FunctionalTests/PropertyEntrySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/PropertyEntrySqliteTest.cs index 7cce89b7d89..cd6318cd6f1 100644 --- a/test/EFCore.Sqlite.FunctionalTests/PropertyEntrySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/PropertyEntrySqliteTest.cs @@ -16,13 +16,8 @@ public override void Property_entry_original_value_is_set() base.Property_entry_original_value_is_set(); AssertSql( - @"SELECT ""e"".""Id"", ""e"".""EngineSupplierId"", ""e"".""Name"", ""t"".""Id"", ""t"".""StorageLocation_Latitude"", ""t"".""StorageLocation_Longitude"" + @"SELECT ""e"".""Id"", ""e"".""EngineSupplierId"", ""e"".""Name"", ""e"".""StorageLocation_Latitude"", ""e"".""StorageLocation_Longitude"" FROM ""Engines"" AS ""e"" -LEFT JOIN ( - SELECT ""e0"".""Id"", ""e0"".""StorageLocation_Latitude"", ""e0"".""StorageLocation_Longitude"" - FROM ""Engines"" AS ""e0"" - WHERE ""e0"".""StorageLocation_Longitude"" IS NOT NULL AND ""e0"".""StorageLocation_Latitude"" IS NOT NULL -) AS ""t"" ON ""e"".""Id"" = ""t"".""Id"" ORDER BY ""e"".""Id"" LIMIT 1", //