diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs index 56e1ba5eb72..297c9e489c4 100644 --- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs +++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerOnDeleteConvention.cs @@ -13,7 +13,9 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// Accessing SQL Server and SQL Azure databases with EF Core /// for more information and examples. /// -public class SqlServerOnDeleteConvention : CascadeDeleteConvention, ISkipNavigationForeignKeyChangedConvention +public class SqlServerOnDeleteConvention : CascadeDeleteConvention, + ISkipNavigationForeignKeyChangedConvention, + IEntityTypeAnnotationChangedConvention { /// /// Creates a new instance of . @@ -60,23 +62,77 @@ protected override DeleteBehavior GetTargetDeleteBehavior(IConventionForeignKey return DeleteBehavior.ClientCascade; } - var selfReferencingSkipNavigation = foreignKey.GetReferencingSkipNavigations() - .FirstOrDefault(s => s.Inverse != null && s.TargetEntityType == s.DeclaringEntityType); - if (selfReferencingSkipNavigation == null) + return ProcessSkipNavigations(foreignKey.GetReferencingSkipNavigations()) ?? deleteBehavior; + } + + private DeleteBehavior? ProcessSkipNavigations(IEnumerable skipNavigations) + { + var skipNavigation = skipNavigations + .FirstOrDefault( + s => s.Inverse != null + && IsMappedToSameTable(s.DeclaringEntityType, s.TargetEntityType)); + + if (skipNavigation != null) { - return deleteBehavior; + var isFirstSkipNavigation = IsFirstSkipNavigation(skipNavigation); + if (!isFirstSkipNavigation) + { + skipNavigation = skipNavigation.Inverse!; + } + + var inverseSkipNavigation = skipNavigation.Inverse!; + + var deleteBehavior = DefaultDeleteBehavior(skipNavigation); + var inverseDeleteBehavior = DefaultDeleteBehavior(inverseSkipNavigation); + + if (deleteBehavior == DeleteBehavior.Cascade + && inverseDeleteBehavior == DeleteBehavior.Cascade + && !(inverseSkipNavigation.ForeignKey!.GetDeleteBehaviorConfigurationSource() == ConfigurationSource.Explicit + && inverseSkipNavigation.ForeignKey!.DeleteBehavior != DeleteBehavior.Cascade)) + { + deleteBehavior = DeleteBehavior.ClientCascade; + } + + skipNavigation.ForeignKey!.Builder.OnDelete(deleteBehavior); + inverseSkipNavigation.ForeignKey!.Builder.OnDelete(inverseDeleteBehavior); + + return isFirstSkipNavigation ? deleteBehavior : inverseDeleteBehavior; } - if (selfReferencingSkipNavigation - == selfReferencingSkipNavigation.DeclaringEntityType.GetDeclaredSkipNavigations() - .First(s => s == selfReferencingSkipNavigation || s == selfReferencingSkipNavigation.Inverse) - && selfReferencingSkipNavigation != selfReferencingSkipNavigation.Inverse) + return null; + + DeleteBehavior DefaultDeleteBehavior(IConventionSkipNavigation conventionSkipNavigation) + => conventionSkipNavigation.ForeignKey!.IsRequired ? DeleteBehavior.Cascade : DeleteBehavior.ClientSetNull; + + bool IsMappedToSameTable(IConventionEntityType entityType1, IConventionEntityType entityType2) { - selfReferencingSkipNavigation.Inverse!.ForeignKey?.Builder.OnDelete( - GetTargetDeleteBehavior(selfReferencingSkipNavigation.Inverse.ForeignKey)); - return DeleteBehavior.ClientCascade; + var tableName1 = entityType1.GetTableName(); + var tableName2 = entityType2.GetTableName(); + + return tableName1 != null + && tableName2 != null + && tableName1 == tableName2 + && entityType1.GetSchema() == entityType2.GetSchema(); } - return deleteBehavior; + bool IsFirstSkipNavigation(IConventionSkipNavigation navigation) + => navigation.DeclaringEntityType != navigation.TargetEntityType + ? string.Compare(navigation.DeclaringEntityType.Name, navigation.TargetEntityType.Name, StringComparison.Ordinal) < 0 + : string.Compare(navigation.Name, navigation.Inverse!.Name, StringComparison.Ordinal) < 0; + } + + /// + public virtual void ProcessEntityTypeAnnotationChanged( + IConventionEntityTypeBuilder entityTypeBuilder, + string name, + IConventionAnnotation? annotation, + IConventionAnnotation? oldAnnotation, + IConventionContext context) + { + if (name == RelationalAnnotationNames.TableName + || name == RelationalAnnotationNames.Schema) + { + ProcessSkipNavigations(entityTypeBuilder.Metadata.GetDeclaredSkipNavigations()); + } } } diff --git a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpRuntimeModelCodeGeneratorTest.cs b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpRuntimeModelCodeGeneratorTest.cs index b5d7a0d6616..d6bad2c56fe 100644 --- a/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpRuntimeModelCodeGeneratorTest.cs +++ b/test/EFCore.Design.Tests/Scaffolding/Internal/CSharpRuntimeModelCodeGeneratorTest.cs @@ -1566,7 +1566,7 @@ public static RuntimeForeignKey CreateForeignKey2(RuntimeEntityType declaringEnt var runtimeForeignKey = declaringEntityType.AddForeignKey(new[] { declaringEntityType.FindProperty(""PrincipalsId"")!, declaringEntityType.FindProperty(""PrincipalsAlternateId"")! }, principalEntityType.FindKey(new[] { principalEntityType.FindProperty(""Id"")!, principalEntityType.FindProperty(""AlternateId"")! })!, principalEntityType, - deleteBehavior: DeleteBehavior.Cascade, + deleteBehavior: DeleteBehavior.ClientCascade, required: true); return runtimeForeignKey; diff --git a/test/EFCore.Relational.Specification.Tests/ManyToManyTrackingRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/ManyToManyTrackingRelationalTestBase.cs new file mode 100644 index 00000000000..453ec08b1cd --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/ManyToManyTrackingRelationalTestBase.cs @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + +namespace Microsoft.EntityFrameworkCore; + +public abstract class ManyToManyTrackingRelationalTestBase : ManyToManyTrackingTestBase + where TFixture : ManyToManyTrackingRelationalTestBase.ManyToManyTrackingRelationalFixture +{ + protected ManyToManyTrackingRelationalTestBase(TFixture fixture) + : base(fixture) + { + } + + [ConditionalFact] + public void Many_to_many_delete_behaviors_are_set() + { + using var context = CreateContext(); + var model = context.Model; + + var navigations = model.GetEntityTypes().SelectMany(e => e.GetDeclaredSkipNavigations()) + .Where(e => e.ForeignKey.DeleteBehavior != DeleteBehavior.Cascade).ToList(); + + var builder = new StringBuilder(); + foreach (var navigation in navigations) + { + builder.AppendLine($"{{ \"{navigation.DeclaringEntityType.ShortName()}.{navigation.Name}\", DeleteBehavior.ClientCascade }},"); + } + + var x = builder.ToString(); + + foreach (var skipNavigation in model.GetEntityTypes().SelectMany(e => e.GetSkipNavigations())) + { + Assert.Equal( + CustomDeleteBehaviors.TryGetValue( + $"{skipNavigation.DeclaringEntityType.ShortName()}.{skipNavigation.Name}", out var deleteBehavior) + ? deleteBehavior + : DeleteBehavior.Cascade, + skipNavigation.ForeignKey.DeleteBehavior); + } + } + + protected virtual Dictionary CustomDeleteBehaviors { get; } = new(); + + protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) + => facade.UseTransaction(transaction.GetDbTransaction()); + + public abstract class ManyToManyTrackingRelationalFixture : ManyToManyTrackingFixtureBase + { + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity().ToTable("TableSharing"); + modelBuilder.Entity( + b => + { + b.HasOne().WithOne().HasForeignKey(e => e.Id); + b.ToTable("TableSharing"); + }); + } + } +} diff --git a/test/EFCore.Relational.Specification.Tests/Query/ManyToManyQueryRelationalFixture.cs b/test/EFCore.Relational.Specification.Tests/Query/ManyToManyQueryRelationalFixture.cs index ba01dc4ec19..9cd62ea8950 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/ManyToManyQueryRelationalFixture.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/ManyToManyQueryRelationalFixture.cs @@ -1,10 +1,25 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + namespace Microsoft.EntityFrameworkCore.Query; public abstract class ManyToManyQueryRelationalFixture : ManyToManyQueryFixtureBase { public TestSqlLoggerFactory TestSqlLoggerFactory => (TestSqlLoggerFactory)ListLoggerFactory; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity().ToTable("TableSharing"); + modelBuilder.Entity( + b => + { + b.HasOne().WithOne().HasForeignKey(e => e.Id); + b.ToTable("TableSharing"); + }); + } } diff --git a/test/EFCore.Relational.Specification.Tests/Query/TPCManyToManyQueryRelationalFixture.cs b/test/EFCore.Relational.Specification.Tests/Query/TPCManyToManyQueryRelationalFixture.cs index b6bcaf216f1..9e9aa44f40b 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/TPCManyToManyQueryRelationalFixture.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/TPCManyToManyQueryRelationalFixture.cs @@ -23,6 +23,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().ToTable("Roots"); modelBuilder.Entity().ToTable("Branches"); modelBuilder.Entity().ToTable("Leaves"); + modelBuilder.Entity().ToTable("Branch2s"); + modelBuilder.Entity().ToTable("Leaf2s"); modelBuilder.Entity().UseTpcMappingStrategy(); modelBuilder.Entity().ToTable("UnidirectionalRoots"); diff --git a/test/EFCore.Relational.Specification.Tests/Query/TPTManyToManyQueryRelationalFixture.cs b/test/EFCore.Relational.Specification.Tests/Query/TPTManyToManyQueryRelationalFixture.cs index b38b4851006..80cd6e44b57 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/TPTManyToManyQueryRelationalFixture.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/TPTManyToManyQueryRelationalFixture.cs @@ -17,6 +17,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().ToTable("Roots"); modelBuilder.Entity().ToTable("Branches"); modelBuilder.Entity().ToTable("Leaves"); + modelBuilder.Entity().ToTable("Branch2s"); + modelBuilder.Entity().ToTable("Leaf2s"); modelBuilder.Entity().ToTable("UnidirectionalRoots"); modelBuilder.Entity().ToTable("UnidirectionalBranches"); diff --git a/test/EFCore.Specification.Tests/Query/ManyToManyFieldsQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/ManyToManyFieldsQueryFixtureBase.cs index 7580afd036f..5d1cf2a5baf 100644 --- a/test/EFCore.Specification.Tests/Query/ManyToManyFieldsQueryFixtureBase.cs +++ b/test/EFCore.Specification.Tests/Query/ManyToManyFieldsQueryFixtureBase.cs @@ -269,6 +269,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con .HasMany(e => e.TwoSkipShared) .WithMany(e => e.OneSkipShared); + modelBuilder.Entity() + .HasMany(e => e.BranchSkipShared) + .WithMany(e => e.RootSkipShared); + // Nav:2 Payload:No Join:Concrete Extra:None modelBuilder.Entity() .HasMany(e => e.TwoSkip) diff --git a/test/EFCore.Specification.Tests/Query/ManyToManyQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/ManyToManyQueryFixtureBase.cs index 0bf132055ee..b9c44c38c87 100644 --- a/test/EFCore.Specification.Tests/Query/ManyToManyQueryFixtureBase.cs +++ b/test/EFCore.Specification.Tests/Query/ManyToManyQueryFixtureBase.cs @@ -40,6 +40,10 @@ public ISetSource GetExpectedData() { typeof(EntityRoot), e => ((EntityRoot)e)?.Id }, { typeof(EntityBranch), e => ((EntityBranch)e)?.Id }, { typeof(EntityLeaf), e => ((EntityLeaf)e)?.Id }, + { typeof(EntityBranch2), e => ((EntityBranch2)e)?.Id }, + { typeof(EntityLeaf2), e => ((EntityLeaf2)e)?.Id }, + { typeof(EntityTableSharing1), e => ((EntityTableSharing1)e)?.Id }, + { typeof(EntityTableSharing2), e => ((EntityTableSharing2)e)?.Id }, { typeof(UnidirectionalEntityOne), e => ((UnidirectionalEntityOne)e)?.Id }, { typeof(UnidirectionalEntityTwo), e => ((UnidirectionalEntityTwo)e)?.Id }, { typeof(UnidirectionalEntityThree), e => ((UnidirectionalEntityThree)e)?.Id }, @@ -165,6 +169,69 @@ public ISetSource GetExpectedData() } } }, + { + typeof(EntityBranch2), (e, a) => + { + Assert.Equal(e == null, a == null); + + if (a != null) + { + var ee = (EntityBranch2)e; + var aa = (EntityBranch2)a; + + Assert.Equal(ee.Id, aa.Id); + Assert.Equal(ee.Name, aa.Name); + Assert.Equal(ee.Slumber, aa.Slumber); + } + } + }, + { + typeof(EntityLeaf2), (e, a) => + { + Assert.Equal(e == null, a == null); + + if (a != null) + { + var ee = (EntityLeaf2)e; + var aa = (EntityLeaf2)a; + + Assert.Equal(ee.Id, aa.Id); + Assert.Equal(ee.Name, aa.Name); + Assert.Equal(ee.Slumber, aa.Slumber); + Assert.Equal(ee.IsBrown, aa.IsBrown); + } + } + }, + { + typeof(EntityTableSharing1), (e, a) => + { + Assert.Equal(e == null, a == null); + + if (a != null) + { + var ee = (EntityTableSharing1)e; + var aa = (EntityTableSharing1)a; + + Assert.Equal(ee.Id, aa.Id); + Assert.Equal(ee.Name, aa.Name); + } + } + }, + { + typeof(EntityTableSharing2), (e, a) => + { + Assert.Equal(e == null, a == null); + + if (a != null) + { + var ee = (EntityTableSharing2)e; + var aa = (EntityTableSharing2)a; + + Assert.Equal(ee.Id, aa.Id); + Assert.Equal(ee.Cucumber, aa.Cucumber); + } + } + }, { typeof(UnidirectionalEntityOne), (e, a) => { @@ -292,6 +359,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); modelBuilder.Entity().HasBaseType(); modelBuilder.Entity().HasBaseType(); + modelBuilder.Entity().HasBaseType(); + modelBuilder.Entity().HasBaseType(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); @@ -321,6 +392,22 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con .HasMany(e => e.TwoSkipShared) .WithMany(e => e.OneSkipShared); + modelBuilder.Entity() + .HasMany(e => e.BranchSkipShared) + .WithMany(e => e.RootSkipShared); + + modelBuilder.Entity() + .HasMany(e => e.SelfSkipSharedLeft) + .WithMany(e => e.SelfSkipSharedRight); + + modelBuilder.Entity() + .HasMany(e => e.Leaf2SkipShared) + .WithMany(e => e.Branch2SkipShared); + + modelBuilder.Entity() + .HasMany(e => e.TableSharing2Shared) + .WithMany(e => e.TableSharing1Shared); + // Nav:2 Payload:No Join:Concrete Extra:None modelBuilder.Entity() .HasMany(e => e.TwoSkip) @@ -439,6 +526,10 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con .HasMany(e => e.TwoSkipShared) .WithMany(); + modelBuilder.Entity() + .HasMany() + .WithMany(e => e.BranchSkipShared); + // Nav:2 Payload:No Join:Concrete Extra:None modelBuilder.Entity() .HasMany(e => e.TwoSkip) diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/EntityBranch.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/EntityBranch.cs index 70d2075ed55..8e6ad0520dd 100644 --- a/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/EntityBranch.cs +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/EntityBranch.cs @@ -7,4 +7,5 @@ public class EntityBranch : EntityRoot { public long Number; public ICollection OneSkip; + public ICollection RootSkipShared; } diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/EntityRoot.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/EntityRoot.cs index 8ac0329de35..ae27a90d791 100644 --- a/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/EntityRoot.cs +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/EntityRoot.cs @@ -9,4 +9,5 @@ public class EntityRoot public string Name; public ICollection ThreeSkipShared; public ICollection CompositeKeySkipShared; + public ICollection BranchSkipShared; } diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/ManyToManyData.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/ManyToManyData.cs index 154b283cff3..3fe6072bff7 100644 --- a/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/ManyToManyData.cs +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyFieldsModel/ManyToManyData.cs @@ -43,6 +43,7 @@ public ManyToManyData(ManyToManyContext context, bool useGeneratedKeys) context.Set>("EntityCompositeKeyEntityTwo").AddRange(CreateEntityCompositeKeyEntityTwos(context)); context.Set>("EntityRootEntityThree").AddRange(CreateEntityRootEntityThrees(context)); context.Set>("EntityCompositeKeyEntityRoot").AddRange(CreateEntityCompositeKeyEntityRoots(context)); + context.Set>("EntityBranchEntityRoot").AddRange(CreateEntityRootEntityBranches(context)); } public IQueryable Set() @@ -1163,6 +1164,39 @@ private static Dictionary CreateEntityRootEntityThree( e["RootSkipSharedId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id; }); + private Dictionary[] CreateEntityRootEntityBranches(ManyToManyContext context) + { + var branches = _roots.OfType().ToList(); + return new[] + { + CreateEntityRootEntityBranch(context, branches[0], _roots[6]), + CreateEntityRootEntityBranch(context, branches[0], _roots[7]), + CreateEntityRootEntityBranch(context, branches[0], _roots[14]), + CreateEntityRootEntityBranch(context, branches[1], _roots[3]), + CreateEntityRootEntityBranch(context, branches[1], _roots[15]), + CreateEntityRootEntityBranch(context, branches[2], _roots[11]), + CreateEntityRootEntityBranch(context, branches[2], _roots[13]), + CreateEntityRootEntityBranch(context, branches[2], _roots[19]), + CreateEntityRootEntityBranch(context, branches[4], _roots[13]), + CreateEntityRootEntityBranch(context, branches[4], _roots[14]), + CreateEntityRootEntityBranch(context, branches[4], _roots[15]), + CreateEntityRootEntityBranch(context, branches[5], _roots[16]), + CreateEntityRootEntityBranch(context, branches[6], _roots[0]), + CreateEntityRootEntityBranch(context, branches[6], _roots[5]), + }; + } + + private static Dictionary CreateEntityRootEntityBranch( + ManyToManyContext context, + EntityBranch branch, + EntityRoot root) + => CreateInstance( + context?.Set>("EntityRootEntityBranch"), (e, p) => + { + e["BranchSkipSharedId"] = context?.Entry(branch).Property(e => e.Id).CurrentValue ?? branch.Id; + e["RootSkipSharedId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id; + }); + private Dictionary[] CreateEntityCompositeKeyEntityRoots(ManyToManyContext context) => new[] { diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityBranch.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityBranch.cs index 3d0f81ec86f..b2d5d449110 100644 --- a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityBranch.cs +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityBranch.cs @@ -7,4 +7,5 @@ public class EntityBranch : EntityRoot { public virtual long Number { get; set; } public virtual ICollection OneSkip { get; set; } + public virtual ICollection RootSkipShared { get; set; } } diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityBranch2.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityBranch2.cs new file mode 100644 index 00000000000..353da33e0a3 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityBranch2.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + +public abstract class EntityBranch2 : EntityRoot +{ + public virtual long Slumber { get; set; } + public virtual ICollection Leaf2SkipShared { get; set; } + + public virtual ICollection SelfSkipSharedLeft { get; set; } + public virtual ICollection SelfSkipSharedRight { get; set; } +} diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityLeaf2.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityLeaf2.cs new file mode 100644 index 00000000000..68b0ff04c81 --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityLeaf2.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + +public class EntityLeaf2 : EntityBranch2 +{ + public virtual bool? IsBrown { get; set; } + public virtual ICollection Branch2SkipShared { get; set; } +} diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityRoot.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityRoot.cs index be3c4d4d59e..a808d0d33d6 100644 --- a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityRoot.cs +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityRoot.cs @@ -9,4 +9,5 @@ public class EntityRoot public virtual string Name { get; set; } public virtual ICollection ThreeSkipShared { get; set; } public virtual ICollection CompositeKeySkipShared { get; set; } + public virtual ICollection BranchSkipShared { get; set; } } diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityTableSharing1.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityTableSharing1.cs new file mode 100644 index 00000000000..9154cbe084e --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityTableSharing1.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + +public class EntityTableSharing1 +{ + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ICollection TableSharing2Shared { get; set; } +} diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityTableSharing2.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityTableSharing2.cs new file mode 100644 index 00000000000..b15bf4a99af --- /dev/null +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/EntityTableSharing2.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + +public class EntityTableSharing2 +{ + public virtual int Id { get; set; } + public virtual long Cucumber { get; set; } + public virtual ICollection TableSharing1Shared { get; set; } +} diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/ManyToManyContext.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/ManyToManyContext.cs index 2b004c33836..9ceda6af76b 100644 --- a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/ManyToManyContext.cs +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/ManyToManyContext.cs @@ -17,6 +17,8 @@ public ManyToManyContext(DbContextOptions options) public DbSet EntityThrees { get; set; } public DbSet EntityCompositeKeys { get; set; } public DbSet EntityRoots { get; set; } + public DbSet EntityTableSharing1s { get; set; } + public DbSet EntityTableSharing2s { get; set; } public DbSet ImplicitManyToManyAs { get; set; } public DbSet ImplicitManyToManyBs { get; set; } public DbSet GeneratedKeysLefts { get; set; } diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/ManyToManyData.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/ManyToManyData.cs index 44201ef49d4..a45645550dc 100644 --- a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/ManyToManyData.cs +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/ManyToManyData.cs @@ -48,6 +48,7 @@ public ManyToManyData(ManyToManyContext context, bool useGeneratedKeys) context.Set>("EntityCompositeKeyEntityTwo").AddRange(CreateJoinTwoToCompositeKeyShareds(context)); context.Set>("EntityRootEntityThree").AddRange(CreateEntityRootEntityThrees(context)); context.Set>("EntityCompositeKeyEntityRoot").AddRange(CreateJoinCompositeKeyToRootShareds(context)); + context.Set>("EntityBranchEntityRoot").AddRange(CreateEntityRootEntityBranches(context)); _unidirectionalOnes = CreateUnidirectionalOnes(context); context.Set().AddRange(_unidirectionalOnes); @@ -80,8 +81,8 @@ public ManyToManyData(ManyToManyContext context, bool useGeneratedKeys) .AddRange(CreateUnidirectionalEntityRootEntityThrees(context)); context.Set>("UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot") .AddRange(CreateUnidirectionalJoinCompositeKeyToRootShareds(context)); - - var entries = context.ChangeTracker.Entries().ToList(); + context.Set>("UnidirectionalEntityBranchUnidirectionalEntityRoot") + .AddRange(CreateUnidirectionalEntityRootUnidirectionalEntityBranches(context)); } public IQueryable Set() @@ -1186,6 +1187,40 @@ private static Dictionary CreateEntityRootEntityThree( e["RootSkipSharedId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id; }); + + private Dictionary[] CreateEntityRootEntityBranches(ManyToManyContext context) + { + var branches = _roots.OfType().ToList(); + return new[] + { + CreateEntityRootEntityBranch(context, branches[0], _roots[6]), + CreateEntityRootEntityBranch(context, branches[0], _roots[7]), + CreateEntityRootEntityBranch(context, branches[0], _roots[14]), + CreateEntityRootEntityBranch(context, branches[1], _roots[3]), + CreateEntityRootEntityBranch(context, branches[1], _roots[15]), + CreateEntityRootEntityBranch(context, branches[2], _roots[11]), + CreateEntityRootEntityBranch(context, branches[2], _roots[13]), + CreateEntityRootEntityBranch(context, branches[2], _roots[19]), + CreateEntityRootEntityBranch(context, branches[4], _roots[13]), + CreateEntityRootEntityBranch(context, branches[4], _roots[14]), + CreateEntityRootEntityBranch(context, branches[4], _roots[15]), + CreateEntityRootEntityBranch(context, branches[5], _roots[16]), + CreateEntityRootEntityBranch(context, branches[6], _roots[0]), + CreateEntityRootEntityBranch(context, branches[6], _roots[5]), + }; + } + + private static Dictionary CreateEntityRootEntityBranch( + ManyToManyContext context, + EntityBranch branch, + EntityRoot root) + => CreateInstance( + context?.Set>("EntityBranchEntityRoot"), (e, p) => + { + e["BranchSkipSharedId"] = context?.Entry(branch).Property(e => e.Id).CurrentValue ?? branch.Id; + e["RootSkipSharedId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id; + }); + private Dictionary[] CreateJoinCompositeKeyToRootShareds(ManyToManyContext context) => new[] { @@ -2303,6 +2338,40 @@ private static Dictionary CreateUnidirectionalEntityRootEntityTh e["UnidirectionalEntityRootId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id; }); + + private Dictionary[] CreateUnidirectionalEntityRootUnidirectionalEntityBranches(ManyToManyContext context) + { + var branches = _unidirectionalRoots.OfType().ToList(); + return new[] + { + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[0], _unidirectionalRoots[6]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[0], _unidirectionalRoots[7]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[0], _unidirectionalRoots[14]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[1], _unidirectionalRoots[3]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[1], _unidirectionalRoots[15]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[2], _unidirectionalRoots[11]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[2], _unidirectionalRoots[13]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[2], _unidirectionalRoots[19]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[4], _unidirectionalRoots[13]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[4], _unidirectionalRoots[14]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[4], _unidirectionalRoots[15]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[5], _unidirectionalRoots[16]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[6], _unidirectionalRoots[0]), + CreateUnidirectionalEntityRootUnidirectionalEntityBranch(context, branches[6], _unidirectionalRoots[5]), + }; + } + + private static Dictionary CreateUnidirectionalEntityRootUnidirectionalEntityBranch( + ManyToManyContext context, + UnidirectionalEntityBranch branch, + UnidirectionalEntityRoot root) + => CreateInstance( + context?.Set>("UnidirectionalEntityBranchUnidirectionalEntityRoot"), (e, p) => + { + e["BranchSkipSharedId"] = context?.Entry(branch).Property(e => e.Id).CurrentValue ?? branch.Id; + e["UnidirectionalEntityRootId"] = context?.Entry(root).Property(e => e.Id).CurrentValue ?? root.Id; + }); + private Dictionary[] CreateUnidirectionalJoinCompositeKeyToRootShareds(ManyToManyContext context) => new[] { diff --git a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/UnidirectionalEntityRoot.cs b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/UnidirectionalEntityRoot.cs index 464b70a1588..5bbab2c6538 100644 --- a/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/UnidirectionalEntityRoot.cs +++ b/test/EFCore.Specification.Tests/TestModels/ManyToManyModel/UnidirectionalEntityRoot.cs @@ -8,4 +8,5 @@ public class UnidirectionalEntityRoot public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual ICollection ThreeSkipShared { get; set; } + public virtual ICollection BranchSkipShared { get; set; } } diff --git a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingGeneratedKeysSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingGeneratedKeysSqlServerTest.cs index 9f3e8925af5..060b8db0c96 100644 --- a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingGeneratedKeysSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingGeneratedKeysSqlServerTest.cs @@ -30,6 +30,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); modelBuilder.Entity().Property(e => e.Key1).ValueGeneratedOnAdd(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); modelBuilder.SharedTypeEntity("PST").IndexerProperty("Id").ValueGeneratedOnAdd(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); diff --git a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingProxyGeneratedKeysSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingProxyGeneratedKeysSqlServerTest.cs index 5b17310a108..1232e9293b4 100644 --- a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingProxyGeneratedKeysSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingProxyGeneratedKeysSqlServerTest.cs @@ -71,6 +71,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); modelBuilder.Entity().Property(e => e.Key1).ValueGeneratedOnAdd(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); modelBuilder.SharedTypeEntity("PST").IndexerProperty("Id").ValueGeneratedOnAdd(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedOnAdd(); diff --git a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingProxySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingProxySqlServerTest.cs index 35f0c861847..5050375c7d7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingProxySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingProxySqlServerTest.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + namespace Microsoft.EntityFrameworkCore; public class ManyToManyTrackingProxySqlServerTest @@ -11,6 +13,20 @@ public ManyToManyTrackingProxySqlServerTest(ManyToManyTrackingProxySqlServerFixt { } + protected override Dictionary CustomDeleteBehaviors { get; } = new() + { + { "EntityBranch.RootSkipShared", DeleteBehavior.ClientCascade }, + { "EntityBranch2.Leaf2SkipShared", DeleteBehavior.ClientCascade }, + { "EntityBranch2.SelfSkipSharedLeft", DeleteBehavior.Restrict }, + { "EntityBranch2.SelfSkipSharedRight", DeleteBehavior.Restrict }, + { "EntityOne.SelfSkipPayloadLeft", DeleteBehavior.ClientCascade }, + { "EntityTwo.SelfSkipSharedLeft", DeleteBehavior.ClientCascade }, + { "EntityTableSharing1.TableSharing2Shared", DeleteBehavior.ClientCascade }, + { "UnidirectionalEntityBranch.UnidirectionalEntityRoot", DeleteBehavior.ClientCascade }, + { "UnidirectionalEntityOne.SelfSkipPayloadLeft", DeleteBehavior.ClientCascade }, + { "UnidirectionalEntityTwo.SelfSkipSharedRight", DeleteBehavior.ClientCascade } + }; + public override Task Can_insert_many_to_many_shared_with_payload(bool async) // Mutable properties aren't proxyable on Dictionary => Task.CompletedTask; @@ -52,6 +68,14 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con { base.OnModelCreating(modelBuilder, context); + modelBuilder.Entity() + .HasMany(e => e.SelfSkipSharedLeft) + .WithMany(e => e.SelfSkipSharedRight) + .UsingEntity>( + "EntityBranch2EntityBranch2", + r => r.HasOne().WithMany().HasForeignKey("SelfSkipSharedRightId").OnDelete(DeleteBehavior.Restrict), + l => l.HasOne().WithMany().HasForeignKey("SelfSkipSharedLeftId").OnDelete(DeleteBehavior.Restrict)); + modelBuilder .SharedTypeEntity>("JoinOneToThreePayloadFullShared") .Ignore("Payload"); // Mutable properties aren't proxyable on Dictionary diff --git a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTest.cs index a0158f65613..3e079b60e95 100644 --- a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTest.cs @@ -13,5 +13,7 @@ public ManyToManyTrackingSqlServerTest(ManyToManyTrackingSqlServerFixture fixtur public class ManyToManyTrackingSqlServerFixture : ManyToManyTrackingSqlServerFixtureBase { + protected override string StoreName + => "ManyToManyTrackingSqlServerTest"; } } diff --git a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTestBase.cs b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTestBase.cs index 5d102801b22..f75a331bc0a 100644 --- a/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTestBase.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ManyToManyTrackingSqlServerTestBase.cs @@ -5,7 +5,7 @@ namespace Microsoft.EntityFrameworkCore; -public abstract class ManyToManyTrackingSqlServerTestBase : ManyToManyTrackingTestBase +public abstract class ManyToManyTrackingSqlServerTestBase : ManyToManyTrackingRelationalTestBase where TFixture : ManyToManyTrackingSqlServerTestBase.ManyToManyTrackingSqlServerFixtureBase { protected ManyToManyTrackingSqlServerTestBase(TFixture fixture) @@ -13,10 +13,20 @@ protected ManyToManyTrackingSqlServerTestBase(TFixture fixture) { } - protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) - => facade.UseTransaction(transaction.GetDbTransaction()); + protected override Dictionary CustomDeleteBehaviors { get; } = new() + { + { "EntityBranch.RootSkipShared", DeleteBehavior.ClientCascade }, + { "EntityBranch2.Leaf2SkipShared", DeleteBehavior.ClientCascade }, + { "EntityBranch2.SelfSkipSharedLeft", DeleteBehavior.ClientCascade }, + { "EntityOne.SelfSkipPayloadLeft", DeleteBehavior.ClientCascade }, + { "EntityTableSharing1.TableSharing2Shared", DeleteBehavior.ClientCascade }, + { "EntityTwo.SelfSkipSharedLeft", DeleteBehavior.ClientCascade }, + { "UnidirectionalEntityBranch.UnidirectionalEntityRoot", DeleteBehavior.ClientCascade }, + { "UnidirectionalEntityOne.SelfSkipPayloadLeft", DeleteBehavior.ClientCascade }, + { "UnidirectionalEntityTwo.SelfSkipSharedRight", DeleteBehavior.ClientCascade }, + }; - public class ManyToManyTrackingSqlServerFixtureBase : ManyToManyTrackingFixtureBase + public class ManyToManyTrackingSqlServerFixtureBase : ManyToManyTrackingRelationalFixture { protected override ITestStoreFactory TestStoreFactory => SqlServerTestStoreFactory.Instance; diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyNoTrackingQuerySqlServerTest.cs index 45fb06075bb..b7cc22b9a86 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyNoTrackingQuerySqlServerTest.cs @@ -566,10 +566,10 @@ 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], [t].[Id], [t].[Discriminator], [t].[Name], [t].[Number], [t].[IsGreen], [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3] + @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name], [t].[Id], [t].[Discriminator], [t].[Name], [t].[Number], [t].[Slumber], [t].[IsGreen], [t].[IsBrown], [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3] FROM [EntityCompositeKeys] AS [e] LEFT JOIN ( - SELECT [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[IsGreen], [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3] + SELECT [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[Slumber], [e1].[IsGreen], [e1].[IsBrown], [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3] FROM [EntityCompositeKeyEntityRoot] AS [e0] INNER JOIN [EntityRoots] AS [e1] ON [e0].[RootSkipSharedId] = [e1].[Id] ) AS [t] ON [e].[Key1] = [t].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t].[CompositeKeySkipSharedKey3] @@ -746,7 +746,7 @@ public override async Task Filtered_then_include_skip_navigation_where(bool asyn await base.Filtered_then_include_skip_navigation_where(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[IsGreen], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id0], [t0].[Name0], [t0].[OneId], [t0].[ThreeId] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id0], [t0].[Name0], [t0].[OneId], [t0].[ThreeId] FROM [EntityRoots] AS [e] LEFT JOIN ( SELECT [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], [e0].[RootSkipSharedId], [e0].[ThreeSkipSharedId], [t].[Id] AS [Id0], [t].[Name] AS [Name0], [t].[OneId], [t].[ThreeId] @@ -767,7 +767,7 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[IsGreen], [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] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown], [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 [EntityRoots] AS [e] LEFT JOIN ( SELECT [e1].[Key1], [e1].[Key2], [e1].[Key3], [e1].[Name], [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId], [t0].[Id0], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3] @@ -978,10 +978,10 @@ public override async Task Include_skip_navigation_split(bool async) FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", // - @"SELECT [t].[Id], [t].[Discriminator], [t].[Name], [t].[Number], [t].[IsGreen], [e].[Key1], [e].[Key2], [e].[Key3] + @"SELECT [t].[Id], [t].[Discriminator], [t].[Name], [t].[Number], [t].[Slumber], [t].[IsGreen], [t].[IsBrown], [e].[Key1], [e].[Key2], [e].[Key3] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( - SELECT [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[IsGreen], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3] + SELECT [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[Slumber], [e1].[IsGreen], [e1].[IsBrown], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3] FROM [EntityCompositeKeyEntityRoot] AS [e0] INNER JOIN [EntityRoots] AS [e1] ON [e0].[RootSkipSharedId] = [e1].[Id] ) AS [t] ON [e].[Key1] = [t].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t].[CompositeKeySkipSharedKey3] @@ -1218,7 +1218,7 @@ public override async Task Filtered_then_include_skip_navigation_where_split(boo await base.Filtered_then_include_skip_navigation_where_split(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[IsGreen] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown] FROM [EntityRoots] AS [e] ORDER BY [e].[Id]", // @@ -1252,7 +1252,7 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take_split(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[IsGreen] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown] FROM [EntityRoots] AS [e] ORDER BY [e].[Id]", // diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyQuerySqlServerTest.cs index e8c34c5878c..5f25d5b155c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ManyToManyQuerySqlServerTest.cs @@ -565,10 +565,10 @@ 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], [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3], [t].[Id], [t].[Discriminator], [t].[Name], [t].[Number], [t].[IsGreen] + @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name], [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3], [t].[Id], [t].[Discriminator], [t].[Name], [t].[Number], [t].[Slumber], [t].[IsGreen], [t].[IsBrown] FROM [EntityCompositeKeys] AS [e] LEFT JOIN ( - SELECT [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[IsGreen] + SELECT [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[Slumber], [e1].[IsGreen], [e1].[IsBrown] FROM [EntityCompositeKeyEntityRoot] AS [e0] INNER JOIN [EntityRoots] AS [e1] ON [e0].[RootSkipSharedId] = [e1].[Id] ) AS [t] ON [e].[Key1] = [t].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t].[CompositeKeySkipSharedKey3] @@ -745,7 +745,7 @@ public override async Task Filtered_then_include_skip_navigation_where(bool asyn await base.Filtered_then_include_skip_navigation_where(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[IsGreen], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id0], [t0].[Name0] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id0], [t0].[Name0] FROM [EntityRoots] AS [e] LEFT JOIN ( SELECT [e0].[RootSkipSharedId], [e0].[ThreeSkipSharedId], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[ReferenceInverseId], [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id] AS [Id0], [t].[Name] AS [Name0] @@ -766,7 +766,7 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[IsGreen], [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] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown], [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 [EntityRoots] AS [e] LEFT JOIN ( SELECT [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [e1].[Key1], [e1].[Key2], [e1].[Key3], [e1].[Name], [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[ReferenceInverseId] @@ -977,10 +977,10 @@ public override async Task Include_skip_navigation_split(bool async) FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", // - @"SELECT [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3], [t].[Id], [t].[Discriminator], [t].[Name], [t].[Number], [t].[IsGreen], [e].[Key1], [e].[Key2], [e].[Key3] + @"SELECT [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3], [t].[Id], [t].[Discriminator], [t].[Name], [t].[Number], [t].[Slumber], [t].[IsGreen], [t].[IsBrown], [e].[Key1], [e].[Key2], [e].[Key3] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( - SELECT [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[IsGreen] + SELECT [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[Number], [e1].[Slumber], [e1].[IsGreen], [e1].[IsBrown] FROM [EntityCompositeKeyEntityRoot] AS [e0] INNER JOIN [EntityRoots] AS [e1] ON [e0].[RootSkipSharedId] = [e1].[Id] ) AS [t] ON [e].[Key1] = [t].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t].[CompositeKeySkipSharedKey3] @@ -1217,7 +1217,7 @@ public override async Task Filtered_then_include_skip_navigation_where_split(boo await base.Filtered_then_include_skip_navigation_where_split(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[IsGreen] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown] FROM [EntityRoots] AS [e] ORDER BY [e].[Id]", // @@ -1251,7 +1251,7 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take_split(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[IsGreen] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown] FROM [EntityRoots] AS [e] ORDER BY [e].[Id]", // diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyNoTrackingQuerySqlServerTest.cs index 24179593312..745ec88473c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyNoTrackingQuerySqlServerTest.cs @@ -184,6 +184,9 @@ 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]"); } @@ -203,6 +206,9 @@ 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] @@ -377,6 +383,9 @@ FROM [Branches] AS [b] UNION ALL SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], NULL AS [IsGreen], N'EntityLeaf2' AS [Discriminator] + FROM [Leaf2s] AS [l0] ) AS [t] ON [e0].[RootSkipSharedId] = [t].[Id] WHERE [t].[Discriminator] = N'EntityLeaf' ) AS [t0] ON [e].[Key1] = [t0].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t0].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t0].[CompositeKeySkipSharedKey3] @@ -434,6 +443,9 @@ 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] @@ -529,6 +541,9 @@ FROM [Branches] AS [b] UNION ALL SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], NULL AS [IsGreen], N'EntityLeaf2' AS [Discriminator] + FROM [Leaf2s] AS [l0] ) AS [t] ON [e0].[RootSkipSharedId] = [t].[Id] WHERE [t].[Discriminator] IN (N'EntityBranch', N'EntityLeaf') ) AS [t0] ON [e].[Id] = [t0].[ThreeSkipSharedId]"); @@ -618,20 +633,23 @@ 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].[IsGreen], [t0].[Discriminator], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3] + @"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].[IsGreen], [t].[Discriminator], [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3] + 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], NULL AS [Number], NULL AS [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'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]"); @@ -803,16 +821,19 @@ public override async Task Filtered_then_include_skip_navigation_where(bool asyn await base.Filtered_then_include_skip_navigation_where(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id0], [t0].[Name0], [t0].[OneId], [t0].[ThreeId] + @"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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'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] @@ -833,16 +854,19 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [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] + @"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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'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] @@ -1054,20 +1078,23 @@ public override async Task Include_skip_navigation_split(bool async) FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", // - @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [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].[IsGreen], [t].[Discriminator], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3] + 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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'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]"); @@ -1295,16 +1322,19 @@ public override async Task Filtered_then_include_skip_navigation_where_split(boo await base.Filtered_then_include_skip_navigation_where_split(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator] + @"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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'EntityLeaf2' AS [Discriminator] + FROM [Leaf2s] AS [l0] ) AS [t] ORDER BY [t].[Id]", // @@ -1318,6 +1348,9 @@ 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] @@ -1336,6 +1369,9 @@ 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] @@ -1356,16 +1392,19 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take_split(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator] + @"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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'EntityLeaf2' AS [Discriminator] + FROM [Leaf2s] AS [l0] ) AS [t] ORDER BY [t].[Id]", // @@ -1379,6 +1418,9 @@ 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] @@ -1397,6 +1439,9 @@ 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] @@ -1764,7 +1809,7 @@ 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 [IsGreen], N'EntityRoot' AS [Discriminator] + @"SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r]"); } @@ -1773,7 +1818,7 @@ 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 [IsGreen], N'EntityBranch' AS [Discriminator] + @"SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b]"); } @@ -1782,7 +1827,7 @@ 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], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + @"SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyQuerySqlServerTest.cs index 944ab5aca02..893f1ef34d4 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyQuerySqlServerTest.cs @@ -184,6 +184,9 @@ 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]"); } @@ -203,6 +206,9 @@ 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] @@ -377,6 +383,9 @@ FROM [Branches] AS [b] UNION ALL SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], NULL AS [IsGreen], N'EntityLeaf2' AS [Discriminator] + FROM [Leaf2s] AS [l0] ) AS [t] ON [e0].[RootSkipSharedId] = [t].[Id] WHERE [t].[Discriminator] = N'EntityLeaf' ) AS [t0] ON [e].[Key1] = [t0].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t0].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t0].[CompositeKeySkipSharedKey3] @@ -434,6 +443,9 @@ 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] @@ -529,6 +541,9 @@ FROM [Branches] AS [b] UNION ALL SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], NULL AS [IsGreen], N'EntityLeaf2' AS [Discriminator] + FROM [Leaf2s] AS [l0] ) AS [t] ON [e0].[RootSkipSharedId] = [t].[Id] WHERE [t].[Discriminator] IN (N'EntityBranch', N'EntityLeaf') ) AS [t0] ON [e].[Id] = [t0].[ThreeSkipSharedId]"); @@ -618,20 +633,23 @@ 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].[IsGreen], [t0].[Discriminator] + @"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].[IsGreen], [t].[Discriminator] + 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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'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]"); @@ -803,16 +821,19 @@ public override async Task Filtered_then_include_skip_navigation_where(bool asyn await base.Filtered_then_include_skip_navigation_where(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id0], [t0].[Name0] + @"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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'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] @@ -833,16 +854,19 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [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] + @"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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'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] @@ -1054,20 +1078,23 @@ public override async Task Include_skip_navigation_split(bool async) 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].[IsGreen], [t0].[Discriminator], [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].[IsGreen], [t].[Discriminator] + 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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'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]"); @@ -1295,16 +1322,19 @@ public override async Task Filtered_then_include_skip_navigation_where_split(boo await base.Filtered_then_include_skip_navigation_where_split(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator] + @"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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'EntityLeaf2' AS [Discriminator] + FROM [Leaf2s] AS [l0] ) AS [t] ORDER BY [t].[Id]", // @@ -1318,6 +1348,9 @@ 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] @@ -1336,6 +1369,9 @@ 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] @@ -1356,16 +1392,19 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take_split(async); AssertSql( - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator] + @"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 [IsGreen], N'EntityRoot' AS [Discriminator] + SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r] UNION ALL - SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [IsGreen], N'EntityBranch' AS [Discriminator] + SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b] UNION ALL - SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l] + UNION ALL + SELECT [l0].[Id], [l0].[Name], NULL AS [Number], [l0].[Slumber], NULL AS [IsGreen], [l0].[IsBrown], N'EntityLeaf2' AS [Discriminator] + FROM [Leaf2s] AS [l0] ) AS [t] ORDER BY [t].[Id]", // @@ -1379,6 +1418,9 @@ 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] @@ -1397,6 +1439,9 @@ 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] @@ -1770,7 +1815,7 @@ 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 [IsGreen], N'EntityRoot' AS [Discriminator] + @"SELECT [r].[Id], [r].[Name], NULL AS [Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityRoot' AS [Discriminator] FROM [Roots] AS [r]"); } @@ -1779,7 +1824,7 @@ 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 [IsGreen], N'EntityBranch' AS [Discriminator] + @"SELECT [b].[Id], [b].[Name], [b].[Number], NULL AS [Slumber], NULL AS [IsGreen], NULL AS [IsBrown], N'EntityBranch' AS [Discriminator] FROM [Branches] AS [b]"); } @@ -1788,7 +1833,7 @@ 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], [l].[IsGreen], N'EntityLeaf' AS [Discriminator] + @"SELECT [l].[Id], [l].[Name], [l].[Number], NULL AS [Slumber], [l].[IsGreen], NULL AS [IsBrown], N'EntityLeaf' AS [Discriminator] FROM [Leaves] AS [l]"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs index 8d324a05fde..fe8b38d5fbb 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs @@ -359,12 +359,14 @@ LEFT JOIN ( FROM [EntityCompositeKeyEntityRoot] AS [e0] INNER JOIN ( SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] + LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ) AS [t] ON [e0].[RootSkipSharedId] = [t].[Id] WHERE [t].[Discriminator] = N'EntityLeaf' ) AS [t0] ON [e].[Key1] = [t0].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t0].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t0].[CompositeKeySkipSharedKey3] @@ -501,12 +503,14 @@ INNER JOIN ( FROM [EntityRootEntityThree] AS [e0] INNER JOIN ( SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] + LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ) AS [t] ON [e0].[RootSkipSharedId] = [t].[Id] WHERE [t].[Discriminator] IN (N'EntityBranch', N'EntityLeaf') ) AS [t0] ON [e].[Id] = [t0].[ThreeSkipSharedId]"); @@ -597,19 +601,22 @@ 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].[IsGreen], [t0].[Discriminator], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3] + @"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].[IsGreen], [t].[Discriminator], [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3] + 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], [b].[Number], [l].[IsGreen], CASE + SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] + LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] + LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ) 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]"); @@ -786,13 +793,16 @@ public override async Task Filtered_then_include_skip_navigation_where(bool asyn await base.Filtered_then_include_skip_navigation_where(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id0], [t0].[Name0], [t0].[OneId], [t0].[ThreeId] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] LEFT JOIN ( SELECT [e0].[Id], [e0].[CollectionInverseId], [e0].[Name], [e0].[ReferenceInverseId], [e].[RootSkipSharedId], [e].[ThreeSkipSharedId], [t].[Id] AS [Id0], [t].[Name] AS [Name0], [t].[OneId], [t].[ThreeId] FROM [EntityRootEntityThree] AS [e] @@ -812,13 +822,16 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [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 [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] 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] @@ -1032,19 +1045,22 @@ public override async Task Include_skip_navigation_split(bool async) FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", // - @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [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].[IsGreen], [t].[Discriminator], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3] + 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], [b].[Number], [l].[IsGreen], CASE + SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] + LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] + LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ) 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]"); @@ -1282,13 +1298,16 @@ public override async Task Filtered_then_include_skip_navigation_where_split(boo await base.Filtered_then_include_skip_navigation_where_split(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ORDER BY [r].[Id]", // @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [r].[Id], [t].[RootSkipSharedId], [t].[ThreeSkipSharedId] @@ -1321,13 +1340,16 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take_split(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ORDER BY [r].[Id]", // @"SELECT [t].[Key1], [t].[Key2], [t].[Key3], [t].[Name], [r].[Id], [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3] @@ -1714,14 +1736,17 @@ 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], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] -WHERE [l].[Id] IS NULL AND [b].[Id] IS NULL"); +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] +WHERE [l0].[Id] IS NULL AND [l].[Id] IS NULL AND [b].[Id] IS NULL"); } public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) @@ -1729,13 +1754,16 @@ public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) await base.GetType_in_hierarchy_in_intermediate_type(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] WHERE [l].[Id] IS NULL AND [b].[Id] IS NOT NULL"); } @@ -1744,13 +1772,16 @@ public override async Task GetType_in_hierarchy_in_leaf_type(bool async) await base.GetType_in_hierarchy_in_leaf_type(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] WHERE [l].[Id] IS NOT NULL"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs index 8ec757fd30f..5771b78c464 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs @@ -358,12 +358,14 @@ LEFT JOIN ( FROM [EntityCompositeKeyEntityRoot] AS [e0] INNER JOIN ( SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] + LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ) AS [t] ON [e0].[RootSkipSharedId] = [t].[Id] WHERE [t].[Discriminator] = N'EntityLeaf' ) AS [t0] ON [e].[Key1] = [t0].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t0].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t0].[CompositeKeySkipSharedKey3] @@ -500,12 +502,14 @@ INNER JOIN ( FROM [EntityRootEntityThree] AS [e0] INNER JOIN ( SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] + LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ) AS [t] ON [e0].[RootSkipSharedId] = [t].[Id] WHERE [t].[Discriminator] IN (N'EntityBranch', N'EntityLeaf') ) AS [t0] ON [e].[Id] = [t0].[ThreeSkipSharedId]"); @@ -596,19 +600,22 @@ 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].[IsGreen], [t0].[Discriminator] + @"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].[IsGreen], [t].[Discriminator] + 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], [b].[Number], [l].[IsGreen], CASE + SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] + LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] + LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ) 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]"); @@ -785,13 +792,16 @@ public override async Task Filtered_then_include_skip_navigation_where(bool asyn await base.Filtered_then_include_skip_navigation_where(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id0], [t0].[Name0] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] LEFT JOIN ( SELECT [e].[RootSkipSharedId], [e].[ThreeSkipSharedId], [e0].[Id], [e0].[CollectionInverseId], [e0].[Name], [e0].[ReferenceInverseId], [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id] AS [Id0], [t].[Name] AS [Name0] FROM [EntityRootEntityThree] AS [e] @@ -811,13 +821,16 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [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 [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] 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] @@ -1031,19 +1044,22 @@ public override async Task Include_skip_navigation_split(bool async) 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].[IsGreen], [t0].[Discriminator], [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].[IsGreen], [t].[Discriminator] + 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], [b].[Number], [l].[IsGreen], CASE + SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] + LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] + LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ) 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]"); @@ -1281,13 +1297,16 @@ public override async Task Filtered_then_include_skip_navigation_where_split(boo await base.Filtered_then_include_skip_navigation_where_split(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ORDER BY [r].[Id]", // @"SELECT [t].[RootSkipSharedId], [t].[ThreeSkipSharedId], [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [r].[Id] @@ -1320,13 +1339,16 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take_split(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] ORDER BY [r].[Id]", // @"SELECT [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3], [t].[Key1], [t].[Key2], [t].[Key3], [t].[Name], [r].[Id] @@ -1719,14 +1741,17 @@ 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], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] -WHERE [l].[Id] IS NULL AND [b].[Id] IS NULL"); +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] +WHERE [l0].[Id] IS NULL AND [l].[Id] IS NULL AND [b].[Id] IS NULL"); } public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) @@ -1734,13 +1759,16 @@ public override async Task GetType_in_hierarchy_in_intermediate_type(bool async) await base.GetType_in_hierarchy_in_intermediate_type(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] WHERE [l].[Id] IS NULL AND [b].[Id] IS NOT NULL"); } @@ -1749,13 +1777,16 @@ public override async Task GetType_in_hierarchy_in_leaf_type(bool async) await base.GetType_in_hierarchy_in_leaf_type(async); AssertSql( - @"SELECT [r].[Id], [r].[Name], [b].[Number], [l].[IsGreen], CASE + @"SELECT [r].[Id], [r].[Name], [b].[Number], [b0].[Slumber], [l].[IsGreen], [l0].[IsBrown], CASE + WHEN [l0].[Id] IS NOT NULL THEN N'EntityLeaf2' WHEN [l].[Id] IS NOT NULL THEN N'EntityLeaf' WHEN [b].[Id] IS NOT NULL THEN N'EntityBranch' END AS [Discriminator] FROM [Roots] AS [r] LEFT JOIN [Branches] AS [b] ON [r].[Id] = [b].[Id] +LEFT JOIN [Branch2s] AS [b0] ON [r].[Id] = [b0].[Id] LEFT JOIN [Leaves] AS [l] ON [r].[Id] = [l].[Id] +LEFT JOIN [Leaf2s] AS [l0] ON [r].[Id] = [l0].[Id] WHERE [l].[Id] IS NOT NULL"); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalManyToManyQuerySqlServerFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalManyToManyQuerySqlServerFixture.cs index 87abd54c2fe..385c9f68e6f 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalManyToManyQuerySqlServerFixture.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalManyToManyQuerySqlServerFixture.cs @@ -20,6 +20,14 @@ public TestSqlLoggerFactory TestSqlLoggerFactory protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) { + modelBuilder.Entity().ToTable("TableSharing"); + modelBuilder.Entity( + b => + { + b.HasOne().WithOne().HasForeignKey(e => e.Id); + b.ToTable("TableSharing"); + }); + modelBuilder.Entity().ToTable(tb => tb.IsTemporal()); modelBuilder.Entity().ToTable(tb => tb.IsTemporal()); modelBuilder.Entity().ToTable(tb => tb.IsTemporal()); @@ -44,6 +52,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); modelBuilder.Entity().HasBaseType(); modelBuilder.Entity().HasBaseType(); + modelBuilder.Entity().HasBaseType(); + modelBuilder.Entity().HasBaseType(); + modelBuilder.Entity().HasBaseType(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); + modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever(); @@ -74,6 +87,23 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con .WithMany(e => e.OneSkipShared) .UsingEntity(t => t.ToTable(tb => tb.IsTemporal())); + modelBuilder.Entity() + .HasMany(e => e.BranchSkipShared) + .WithMany(e => e.RootSkipShared) + .UsingEntity(t => t.ToTable(tb => tb.IsTemporal())); + + modelBuilder.Entity() + .HasMany(e => e.SelfSkipSharedLeft) + .WithMany(e => e.SelfSkipSharedRight); + + modelBuilder.Entity() + .HasMany(e => e.Leaf2SkipShared) + .WithMany(e => e.Branch2SkipShared); + + modelBuilder.Entity() + .HasMany(e => e.TableSharing2Shared) + .WithMany(e => e.TableSharing1Shared); + // Nav:2 Payload:No Join:Concrete Extra:None modelBuilder.Entity() .HasMany(e => e.TwoSkip) @@ -203,6 +233,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con .WithMany() .UsingEntity(t => t.ToTable(tb => tb.IsTemporal())); + modelBuilder.Entity() + .HasMany() + .WithMany(e => e.BranchSkipShared) + .UsingEntity(t => t.ToTable(tb => tb.IsTemporal())); + // Nav:2 Payload:No Join:Concrete Extra:None modelBuilder.Entity() .HasMany(e => e.TwoSkip) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalManyToManyQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalManyToManyQuerySqlServerTest.cs index e3740127789..b6da36d475d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalManyToManyQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalManyToManyQuerySqlServerTest.cs @@ -28,6 +28,10 @@ protected override Expression RewriteServerQueryExpression(Expression serverQuer typeof(EntityRoot), typeof(EntityBranch), typeof(EntityLeaf), + typeof(EntityBranch2), + typeof(EntityLeaf2), + typeof(EntityTableSharing1), + typeof(EntityTableSharing2), typeof(UnidirectionalEntityOne), typeof(UnidirectionalEntityTwo), typeof(UnidirectionalEntityThree), @@ -592,10 +596,10 @@ 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], [e].[PeriodEnd], [e].[PeriodStart], [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[Number], [t].[IsGreen] + @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [t].[RootSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3], [t].[PeriodEnd], [t].[PeriodStart], [t].[Id], [t].[Discriminator], [t].[Name], [t].[PeriodEnd0], [t].[PeriodStart0], [t].[Number], [t].[Slumber], [t].[IsGreen], [t].[IsBrown] FROM [EntityCompositeKeys] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e] LEFT JOIN ( - SELECT [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [e0].[PeriodEnd], [e0].[PeriodStart], [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[PeriodEnd] AS [PeriodEnd0], [e1].[PeriodStart] AS [PeriodStart0], [e1].[Number], [e1].[IsGreen] + SELECT [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [e0].[PeriodEnd], [e0].[PeriodStart], [e1].[Id], [e1].[Discriminator], [e1].[Name], [e1].[PeriodEnd] AS [PeriodEnd0], [e1].[PeriodStart] AS [PeriodStart0], [e1].[Number], [e1].[Slumber], [e1].[IsGreen], [e1].[IsBrown] FROM [EntityCompositeKeyEntityRoot] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e0] INNER JOIN [EntityRoots] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e1] ON [e0].[RootSkipSharedId] = [e1].[Id] ) AS [t] ON [e].[Key1] = [t].[CompositeKeySkipSharedKey1] AND [e].[Key2] = [t].[CompositeKeySkipSharedKey2] AND [e].[Key3] = [t].[CompositeKeySkipSharedKey3] @@ -792,7 +796,7 @@ public override async Task Filtered_then_include_skip_navigation_where(bool asyn await base.Filtered_then_include_skip_navigation_where(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [e].[Number], [e].[IsGreen], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t0].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[PeriodEnd1], [t0].[PeriodStart1], [t0].[Id0], [t0].[Name0], [t0].[PeriodEnd00], [t0].[PeriodStart00] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[PeriodEnd], [t0].[PeriodStart], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[PeriodEnd0], [t0].[PeriodStart0], [t0].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[PeriodEnd1], [t0].[PeriodStart1], [t0].[Id0], [t0].[Name0], [t0].[PeriodEnd00], [t0].[PeriodStart00] FROM [EntityRoots] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e] LEFT JOIN ( SELECT [e0].[RootSkipSharedId], [e0].[ThreeSkipSharedId], [e0].[PeriodEnd], [e0].[PeriodStart], [e1].[Id], [e1].[CollectionInverseId], [e1].[Name], [e1].[PeriodEnd] AS [PeriodEnd0], [e1].[PeriodStart] AS [PeriodStart0], [e1].[ReferenceInverseId], [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[PeriodEnd] AS [PeriodEnd1], [t].[PeriodStart] AS [PeriodStart1], [t].[Id] AS [Id0], [t].[Name] AS [Name0], [t].[PeriodEnd0] AS [PeriodEnd00], [t].[PeriodStart0] AS [PeriodStart00] @@ -813,7 +817,7 @@ public override async Task Filtered_then_include_skip_navigation_order_by_skip_t await base.Filtered_then_include_skip_navigation_order_by_skip_take(async); AssertSql( - @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [e].[Number], [e].[IsGreen], [t1].[RootSkipSharedId], [t1].[CompositeKeySkipSharedKey1], [t1].[CompositeKeySkipSharedKey2], [t1].[CompositeKeySkipSharedKey3], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Key1], [t1].[Key2], [t1].[Key3], [t1].[Name], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[PeriodEnd1], [t1].[PeriodStart1], [t1].[ThreeId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name0], [t1].[PeriodEnd00], [t1].[PeriodStart00], [t1].[ReferenceInverseId] + @"SELECT [e].[Id], [e].[Discriminator], [e].[Name], [e].[PeriodEnd], [e].[PeriodStart], [e].[Number], [e].[Slumber], [e].[IsGreen], [e].[IsBrown], [t1].[RootSkipSharedId], [t1].[CompositeKeySkipSharedKey1], [t1].[CompositeKeySkipSharedKey2], [t1].[CompositeKeySkipSharedKey3], [t1].[PeriodEnd], [t1].[PeriodStart], [t1].[Key1], [t1].[Key2], [t1].[Key3], [t1].[Name], [t1].[PeriodEnd0], [t1].[PeriodStart0], [t1].[Id], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[PeriodEnd1], [t1].[PeriodStart1], [t1].[ThreeId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name0], [t1].[PeriodEnd00], [t1].[PeriodStart00], [t1].[ReferenceInverseId] FROM [EntityRoots] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [e] LEFT JOIN ( SELECT [e0].[RootSkipSharedId], [e0].[CompositeKeySkipSharedKey1], [e0].[CompositeKeySkipSharedKey2], [e0].[CompositeKeySkipSharedKey3], [e0].[PeriodEnd], [e0].[PeriodStart], [e1].[Key1], [e1].[Key2], [e1].[Key3], [e1].[Name], [e1].[PeriodEnd] AS [PeriodEnd0], [e1].[PeriodStart] AS [PeriodStart0], [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[PeriodEnd] AS [PeriodEnd1], [t0].[PeriodStart] AS [PeriodStart1], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name] AS [Name0], [t0].[PeriodEnd0] AS [PeriodEnd00], [t0].[PeriodStart0] AS [PeriodStart00], [t0].[ReferenceInverseId] diff --git a/test/EFCore.SqlServer.FunctionalTests/TpcManyToManyTrackingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/TpcManyToManyTrackingSqlServerTest.cs new file mode 100644 index 00000000000..5fbcb55cdb2 --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/TpcManyToManyTrackingSqlServerTest.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + +namespace Microsoft.EntityFrameworkCore; + +public class TpcManyToManyTrackingSqlServerTest + : ManyToManyTrackingSqlServerTestBase +{ + public TpcManyToManyTrackingSqlServerTest(TpcManyToManyTrackingSqlServerFixture fixture) + : base(fixture) + { + } + + public class TpcManyToManyTrackingSqlServerFixture : ManyToManyTrackingSqlServerFixtureBase + { + protected override string StoreName + => "TpcManyToManyTrackingSqlServerTest"; + + public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder) + => base.AddOptions(builder).ConfigureWarnings( + w => w.Log(RelationalEventId.ForeignKeyTpcPrincipalWarning)); + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity().UseTpcMappingStrategy(); + modelBuilder.Entity().ToTable("Roots"); + modelBuilder.Entity().ToTable("Branches"); + modelBuilder.Entity().ToTable("Leaves"); + modelBuilder.Entity().ToTable("Branch2s"); + modelBuilder.Entity().ToTable("Leaf2s"); + + modelBuilder.Entity().UseTpcMappingStrategy(); + modelBuilder.Entity().ToTable("UnidirectionalRoots"); + modelBuilder.Entity().ToTable("UnidirectionalBranches"); + modelBuilder.Entity().ToTable("UnidirectionalLeaves"); + } + } +} diff --git a/test/EFCore.SqlServer.FunctionalTests/TptManyToManyTrackingSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/TptManyToManyTrackingSqlServerTest.cs new file mode 100644 index 00000000000..46064f40580 --- /dev/null +++ b/test/EFCore.SqlServer.FunctionalTests/TptManyToManyTrackingSqlServerTest.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; + +namespace Microsoft.EntityFrameworkCore; + +public class TptManyToManyTrackingSqlServerTest + : ManyToManyTrackingSqlServerTestBase +{ + public TptManyToManyTrackingSqlServerTest(TptManyToManyTrackingSqlServerFixture fixture) + : base(fixture) + { + } + + public class TptManyToManyTrackingSqlServerFixture : ManyToManyTrackingSqlServerFixtureBase + { + protected override string StoreName + => "TptManyToManyTrackingSqlServerTest"; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + + modelBuilder.Entity().ToTable("Roots"); + modelBuilder.Entity().ToTable("Branches"); + modelBuilder.Entity().ToTable("Leaves"); + modelBuilder.Entity().ToTable("Branch2s"); + modelBuilder.Entity().ToTable("Leaf2s"); + + modelBuilder.Entity().ToTable("UnidirectionalRoots"); + modelBuilder.Entity().ToTable("UnidirectionalBranches"); + modelBuilder.Entity().ToTable("UnidirectionalLeaves"); + } + } +} diff --git a/test/EFCore.Sqlite.FunctionalTests/ManyToManyTrackingSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/ManyToManyTrackingSqliteTest.cs index b3c98e04664..bc8275ae217 100644 --- a/test/EFCore.Sqlite.FunctionalTests/ManyToManyTrackingSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/ManyToManyTrackingSqliteTest.cs @@ -5,17 +5,15 @@ namespace Microsoft.EntityFrameworkCore; -public class ManyToManyTrackingSqliteTest : ManyToManyTrackingTestBase +public class ManyToManyTrackingSqliteTest + : ManyToManyTrackingRelationalTestBase { public ManyToManyTrackingSqliteTest(ManyToManyTrackingSqliteFixture fixture) : base(fixture) { } - protected override void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction) - => facade.UseTransaction(transaction.GetDbTransaction()); - - public class ManyToManyTrackingSqliteFixture : ManyToManyTrackingFixtureBase + public class ManyToManyTrackingSqliteFixture : ManyToManyTrackingRelationalFixture { protected override ITestStoreFactory TestStoreFactory => SqliteTestStoreFactory.Instance;