From c7d4c623c622be46ecf3273c51313cb5bc4fa666 Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Tue, 12 Jul 2022 23:22:14 +0100 Subject: [PATCH] Update based on code review feedback and use of EF.Property for loading with filtered include. --- .../Internal/InternalEntityEntry.cs | 10 +- src/EFCore/Internal/ManyToManyLoader.cs | 68 +- .../Internal/ManyToManyLoaderFactory.cs | 8 +- .../Builders/CollectionNavigationBuilder.cs | 2 +- src/EFCore/Metadata/IClrCollectionAccessor.cs | 6 +- .../Internal/InternalEntityTypeBuilder.cs | 13 +- src/EFCore/Properties/CoreStrings.Designer.cs | 8 - src/EFCore/Properties/CoreStrings.resx | 3 - .../Query/ManyToManyQueryTestBase.cs | 384 +-------- .../UnidirectionalManyToManyLoadTestBase.cs | 192 +++-- ...CManyToManyNoTrackingQuerySqlServerTest.cs | 733 +++++++++++++++-- .../Query/TPCManyToManyQuerySqlServerTest.cs | 745 ++++++++++++++++-- ...TManyToManyNoTrackingQuerySqlServerTest.cs | 613 +++++++++++++- .../Query/TPTManyToManyQuerySqlServerTest.cs | 628 ++++++++++++++- .../ModelBuilding/ManyToManyTestBase.cs | 186 +++++ .../ModelBuilding/ModelBuilderGenericTest.cs | 6 +- .../ModelBuilderNonGenericTest.cs | 6 +- .../ModelBuilding/ModelBuilderTestBase.cs | 6 +- test/EFCore.Tests/ModelBuilding/TestModel.cs | 21 + 19 files changed, 2952 insertions(+), 686 deletions(-) diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs index a73e3dd1fc8..42e13e69340 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs @@ -918,10 +918,10 @@ private void WritePropertyValue( /// public object GetOrCreateCollection(INavigationBase navigationBase, bool forMaterialization) => navigationBase.IsShadowProperty() - ? GetOrCreateCollectionTyped(navigationBase) + ? GetOrCreateShadowCollection(navigationBase) : navigationBase.GetCollectionAccessor()!.GetOrCreate(Entity, forMaterialization); - private object GetOrCreateCollectionTyped(INavigationBase navigation) + private object GetOrCreateShadowCollection(INavigationBase navigation) { var collection = _shadowValues[navigation.GetShadowIndex()]; if (collection == null) @@ -943,7 +943,7 @@ public bool CollectionContains(INavigationBase navigationBase, object value) { var collectionAccessor = navigationBase.GetCollectionAccessor()!; return navigationBase.IsShadowProperty() - ? collectionAccessor.ContainsStandalone(GetOrCreateCollectionTyped(navigationBase), value) + ? collectionAccessor.ContainsStandalone(GetOrCreateShadowCollection(navigationBase), value) : collectionAccessor.Contains(Entity, value); } @@ -964,7 +964,7 @@ public bool AddToCollection( return collectionAccessor.Add(Entity, value, forMaterialization); } - var collection = GetOrCreateCollectionTyped(navigationBase); + var collection = GetOrCreateShadowCollection(navigationBase); if (!collectionAccessor.ContainsStandalone(collection, value)) { collectionAccessor.AddStandalone(collection, value); @@ -984,7 +984,7 @@ public bool RemoveFromCollection(INavigationBase navigationBase, object value) { var collectionAccessor = navigationBase.GetCollectionAccessor()!; return navigationBase.IsShadowProperty() - ? collectionAccessor.RemoveStandalone(GetOrCreateCollectionTyped(navigationBase), value) + ? collectionAccessor.RemoveStandalone(GetOrCreateShadowCollection(navigationBase), value) : collectionAccessor.Remove(Entity, value); } diff --git a/src/EFCore/Internal/ManyToManyLoader.cs b/src/EFCore/Internal/ManyToManyLoader.cs index f8a73dd0830..d5d969eb1e6 100644 --- a/src/EFCore/Internal/ManyToManyLoader.cs +++ b/src/EFCore/Internal/ManyToManyLoader.cs @@ -3,7 +3,6 @@ using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; using Microsoft.EntityFrameworkCore.Metadata.Internal; -using ValueBuffer = Microsoft.EntityFrameworkCore.Storage.ValueBuffer; namespace Microsoft.EntityFrameworkCore.Internal; @@ -13,10 +12,9 @@ namespace Microsoft.EntityFrameworkCore.Internal; /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// -public class ManyToManyLoader : ICollectionLoader +public class ManyToManyLoader : ICollectionLoader where TEntity : class where TSourceEntity : class - where TJoinEntity : class { private readonly ISkipNavigation _skipNavigation; @@ -44,7 +42,7 @@ public virtual void Load(InternalEntityEntry entry) // Short-circuit for any null key values for perf and because of #6129 if (keyValues != null) { - Query(entry.Context, keyValues).Result.Load(); + Query(entry.Context, keyValues).Load(); } entry.SetIsLoaded(_skipNavigation); @@ -63,8 +61,7 @@ public virtual async Task LoadAsync(InternalEntityEntry entry, CancellationToken // Short-circuit for any null key values for perf and because of #6129 if (keyValues != null) { - await (await Query(entry.Context, keyValues, true, cancellationToken).ConfigureAwait(false)) - .LoadAsync(cancellationToken).ConfigureAwait(false); + await Query(entry.Context, keyValues).LoadAsync(cancellationToken).ConfigureAwait(false); } entry.SetIsLoaded(_skipNavigation); @@ -92,7 +89,7 @@ public virtual IQueryable Query(InternalEntityEntry entry) return queryRoot.Where(e => false); } - return Query(context, keyValues).Result; + return Query(context, keyValues); } private object[]? PrepareForLoad(InternalEntityEntry entry) @@ -101,10 +98,8 @@ public virtual IQueryable Query(InternalEntityEntry entry) { throw new InvalidOperationException(CoreStrings.CannotLoadDetached(_skipNavigation.Name, entry.EntityType.DisplayName())); } - var properties = _skipNavigation.ForeignKey.PrincipalKey.Properties; var values = new object[properties.Count]; - for (var i = 0; i < values.Length; i++) { var value = entry[properties[i]]; @@ -112,13 +107,10 @@ public virtual IQueryable Query(InternalEntityEntry entry) { return null; } - values[i] = value; } - return values; } - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -128,9 +120,12 @@ public virtual IQueryable Query(InternalEntityEntry entry) IQueryable ICollectionLoader.Query(InternalEntityEntry entry) => Query(entry); - private async Task> Query( - DbContext context, object[] keyValues, bool async = false, CancellationToken cancellationToken = default) + private IQueryable Query( + DbContext context, + object[] keyValues) { + var loadProperties = _skipNavigation.ForeignKey.PrincipalKey.Properties; + // Example of query being built: // // IQueryable loaded @@ -140,38 +135,16 @@ private async Task> Query( // .SelectMany(e => e.TwoSkip) // .NotQuiteInclude(e => e.OneSkip.Where(e => e.Id == left.Id)); - var loadProperties = _skipNavigation.ForeignKey.PrincipalKey.Properties; var queryRoot = _skipNavigation.DeclaringEntityType.HasSharedClrType ? context.Set(_skipNavigation.DeclaringEntityType.Name) : context.Set(); - var queryable = queryRoot + return queryRoot .AsTracking() - .Where(BuildWhereLambda(loadProperties, new ValueBuffer(keyValues))) - .SelectMany(BuildSelectManyLambda(_skipNavigation)); - - if (_skipNavigation.Inverse.IsShadowProperty()) - { - // TODOU: This is a hack, until #27493 is implemented. - var joinEntitiesQuery = (_skipNavigation.JoinEntityType.HasSharedClrType - ? context.Set(_skipNavigation.JoinEntityType.Name) - : context.Set()) - .AsTracking() - .Where(BuildWhereLambda(_skipNavigation.ForeignKey.Properties, new ValueBuffer(keyValues))); - - if (async) - { - await joinEntitiesQuery.LoadAsync(cancellationToken).ConfigureAwait(false); - } - else - { - joinEntitiesQuery.Load(); - } - - return queryable; - } - - return queryable.NotQuiteInclude(BuildIncludeLambda(_skipNavigation.Inverse, loadProperties, new ValueBuffer(keyValues))); + .Where(BuildWhereLambda(loadProperties, new ValueBuffer(keyValues))) + .SelectMany(BuildSelectManyLambda(_skipNavigation)) + .NotQuiteInclude(BuildIncludeLambda(_skipNavigation.Inverse, loadProperties, new ValueBuffer(keyValues))) + .AsQueryable(); } private static Expression>> BuildIncludeLambda( @@ -181,32 +154,31 @@ private static Expression>> BuildInclud { var whereParameter = Expression.Parameter(typeof(TSourceEntity), "e"); var entityParameter = Expression.Parameter(typeof(TEntity), "e"); - return Expression.Lambda>>( Expression.Call( EnumerableMethods.Where.MakeGenericMethod(typeof(TSourceEntity)), - Expression.MakeMemberAccess( + Expression.Call( + EF.PropertyMethod.MakeGenericMethod(skipNavigation.ClrType), entityParameter, - skipNavigation.GetIdentifyingMemberInfo()!), + Expression.Constant(skipNavigation.Name, typeof(string))), Expression.Lambda>( ExpressionExtensions.BuildPredicate(keyProperties, keyValues, whereParameter), whereParameter)), entityParameter); } - private static Expression> BuildWhereLambda( + private static Expression> BuildWhereLambda( IReadOnlyList keyProperties, ValueBuffer keyValues) { - var entityParameter = Expression.Parameter(typeof(T), "e"); + var entityParameter = Expression.Parameter(typeof(TSourceEntity), "e"); - return Expression.Lambda>( + return Expression.Lambda>( ExpressionExtensions.BuildPredicate(keyProperties, keyValues, entityParameter), entityParameter); } private static Expression>> BuildSelectManyLambda(INavigationBase navigation) { var entityParameter = Expression.Parameter(typeof(TSourceEntity), "e"); - return Expression.Lambda>>( Expression.MakeMemberAccess( entityParameter, diff --git a/src/EFCore/Internal/ManyToManyLoaderFactory.cs b/src/EFCore/Internal/ManyToManyLoaderFactory.cs index f4b1b75cbf2..05953b2b651 100644 --- a/src/EFCore/Internal/ManyToManyLoaderFactory.cs +++ b/src/EFCore/Internal/ManyToManyLoaderFactory.cs @@ -25,14 +25,12 @@ private static readonly MethodInfo GenericCreate public virtual ICollectionLoader Create(ISkipNavigation skipNavigation) => (ICollectionLoader)GenericCreate.MakeGenericMethod( skipNavigation.TargetEntityType.ClrType, - skipNavigation.DeclaringEntityType.ClrType, - skipNavigation.JoinEntityType.ClrType) + skipNavigation.DeclaringEntityType.ClrType) .Invoke(null, new object[] { skipNavigation })!; [UsedImplicitly] - private static ICollectionLoader CreateManyToMany(ISkipNavigation skipNavigation) + private static ICollectionLoader CreateManyToMany(ISkipNavigation skipNavigation) where TEntity : class where TTargetEntity : class - where TJoinEntity : class - => new ManyToManyLoader(skipNavigation); + => new ManyToManyLoader(skipNavigation); } diff --git a/src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs b/src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs index e14ec81b439..0f30401cf12 100644 --- a/src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs +++ b/src/EFCore/Metadata/Builders/CollectionNavigationBuilder.cs @@ -214,7 +214,7 @@ private InternalForeignKeyBuilder WithOneBuilder(MemberIdentity reference) /// The name of the collection navigation property on the other end of this relationship. /// /// An object to further configure the relationship. - public virtual CollectionCollectionBuilder WithMany(string navigationName) + public virtual CollectionCollectionBuilder WithMany(string? navigationName = null) { var leftName = Builder?.Metadata.PrincipalToDependent?.Name; var collectionCollectionBuilder = diff --git a/src/EFCore/Metadata/IClrCollectionAccessor.cs b/src/EFCore/Metadata/IClrCollectionAccessor.cs index c0d634283e0..07a70cb5015 100644 --- a/src/EFCore/Metadata/IClrCollectionAccessor.cs +++ b/src/EFCore/Metadata/IClrCollectionAccessor.cs @@ -45,7 +45,7 @@ public interface IClrCollectionAccessor bool Remove(object entity, object value); /// - /// Adds a value to the collection, unless it is already contained in the collection. + /// Adds a value to the passed collection, unless it is already contained in the collection. /// /// The collection. /// The value to add. @@ -53,7 +53,7 @@ public interface IClrCollectionAccessor bool AddStandalone(object collection, object value); /// - /// Checks whether the value is contained in the collection. + /// Checks whether the value is contained in the passed collection. /// /// The collection. /// The value to check. @@ -61,7 +61,7 @@ public interface IClrCollectionAccessor bool ContainsStandalone(object collection, object value); /// - /// Removes a value from the collection. + /// Removes a value from the passed collection. /// /// The collection. /// The value to check. diff --git a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs index 8859fa2e8eb..e62abe7e9fe 100644 --- a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs @@ -4253,15 +4253,12 @@ private static bool Contains(IReadOnlyForeignKey? inheritedFk, IReadOnlyForeignK } else { - if (navigationName == null) + var generatedNavigationName = targetEntityType.ShortName(); + navigationName = generatedNavigationName; + var uniquifier = 0; + while (Metadata.FindMembersInHierarchy(navigationName).Any()) { - var generatedNavigationName = targetEntityType.ShortName(); - navigationName = generatedNavigationName; - var uniquifier = 0; - while(Metadata.FindMembersInHierarchy(navigationName).Any()) - { - navigationName = generatedNavigationName + (++uniquifier); - } + navigationName = generatedNavigationName + (++uniquifier); } builder = Metadata.AddSkipNavigation( diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index d414192d028..300c707cfb3 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -2509,14 +2509,6 @@ public static string ServiceProviderConfigRemoved(object? key) public static string SetOperationWithDifferentIncludesInOperands => GetString("SetOperationWithDifferentIncludesInOperands"); - /// - /// Unable to set up a many-to-many relationship between '{leftEntityType}.{leftNavigation}' and '{rightEntityType}.{rightNavigation}' because one or both of the navigations don't have a corresponding CLR property. Consider adding a corresponding private property to the entity CLR type. - /// - public static string ShadowManyToManyNavigation(object? leftEntityType, object? leftNavigation, object? rightEntityType, object? rightNavigation) - => string.Format( - GetString("ShadowManyToManyNavigation", nameof(leftEntityType), nameof(leftNavigation), nameof(rightEntityType), nameof(rightNavigation)), - leftEntityType, leftNavigation, rightEntityType, rightNavigation); - /// /// The shared-type entity type '{entityType}' cannot have a base type. /// diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index 8e1da961ebd..8567610606d 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -1370,9 +1370,6 @@ Unable to translate set operation since both operands have different 'Include' operations. Consider having same 'Include' applied on both sides. - - Unable to set up a many-to-many relationship between '{leftEntityType}.{leftNavigation}' and '{rightEntityType}.{rightNavigation}' because one or both of the navigations don't have a corresponding CLR property. Consider adding a corresponding private property to the entity CLR type. - The shared-type entity type '{entityType}' cannot have a base type. diff --git a/test/EFCore.Specification.Tests/Query/ManyToManyQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ManyToManyQueryTestBase.cs index 2b22c624e14..9d51894eb4f 100644 --- a/test/EFCore.Specification.Tests/Query/ManyToManyQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ManyToManyQueryTestBase.cs @@ -794,15 +794,6 @@ public virtual Task Skip_navigation_all_unidirectional(bool async) ss => ss.Set().Where(e => e.TwoSkip.All(e => e.Name.Contains("B"))), entryCount: 1); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_any_without_predicate_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Where(e => e.ThreeSkipPayloadFull.Where(e => e.Name.Contains("B")).Any()), - // entryCount: 0); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Skip_navigation_any_with_predicate_unidirectional(bool async) @@ -838,60 +829,6 @@ public virtual Task Skip_navigation_count_with_predicate_unidirectional(bool asy assertOrder: true, entryCount: 20); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_long_count_without_predicate_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Where(e => e.ThreeSkipFull.LongCount() > 0), - // entryCount: 19); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_long_count_with_predicate_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().OrderByDescending(e => e.SelfSkipSharedLeft.LongCount(e => e.Name.StartsWith("L"))) - // .ThenBy(e => e.Id), - // assertOrder: true, - // entryCount: 20); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_select_many_average_unidirectional(bool async) - => Task.CompletedTask; - // => AssertAverage( - // async, - // ss => ss.Set().SelectMany(e => e.CompositeKeySkipShared.Select(e => e.Key1))); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_select_many_max_unidirectional(bool async) - => Task.CompletedTask; - // => AssertMax( - // async, - // ss => ss.Set().SelectMany(e => e.CompositeKeySkipFull.Select(e => e.Key1)), - // entryCount: 0); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_select_many_min_unidirectional(bool async) - => Task.CompletedTask; - // => AssertMin( - // async, - // ss => ss.Set().SelectMany(e => e.RootSkipShared.Select(e => e.Id)), - // entryCount: 0); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_select_many_sum_unidirectional(bool async) - => Task.CompletedTask; - // => AssertSum( - // async, - // ss => ss.Set().SelectMany(e => e.CompositeKeySkipShared.Select(e => e.Key1))); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Skip_navigation_select_subquery_average_unidirectional(bool async) @@ -899,57 +836,6 @@ public virtual Task Skip_navigation_select_subquery_average_unidirectional(bool async, ss => ss.Set().Select(e => e.CompositeKeySkipFull.Average(e => e.Key1))); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_select_subquery_max_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQueryScalar( - // async, - // ss => ss.Set().Select(e => e.OneSkip.Max(e => e.Id))); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_select_subquery_min_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQueryScalar( - // async, - // ss => ss.Set().Select(e => e.OneSkipPayloadFull.Min(e => e.Id))); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_select_subquery_sum_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQueryScalar( - // async, - // ss => ss.Set().Select(e => e.OneSkipShared.Sum(e => e.Id))); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_order_by_first_or_default_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Select(e => e.OneSkipPayloadFullShared.OrderBy(i => i.Id).FirstOrDefault()), - // entryCount: 12); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_order_by_single_or_default_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Select(e => e.SelfSkipPayloadRight.OrderBy(i => i.Id).Take(1).SingleOrDefault()), - // entryCount: 9); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_order_by_last_or_default_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Select(e => e.OneSkip.OrderBy(i => i.Id).LastOrDefault()), - // entryCount: 6); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Skip_navigation_order_by_reverse_first_or_default_unidirectional(bool async) @@ -958,17 +844,6 @@ public virtual Task Skip_navigation_order_by_reverse_first_or_default_unidirecti ss => ss.Set().Select(e => e.TwoSkipFull.OrderBy(i => i.Id).Reverse().FirstOrDefault()), entryCount: 11); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Skip_navigation_cast_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().OrderBy(e => e.Key1).Select(e => e.LeafSkipFull.Cast()), - // assertOrder: true, - // elementAsserter: (e, a) => AssertCollection(e, a), - // entryCount: 4); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Skip_navigation_of_type_unidirectional(bool async) @@ -1043,17 +918,6 @@ from t in r.TwoSkip.DefaultIfEmpty() select t, entryCount: 20); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Select_many_over_skip_navigation_order_by_skip_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => from r in ss.Set() - // from t in r.ThreeSkipPayloadFull.OrderBy(e => e.Id).Skip(2) - // select t, - // entryCount: 16); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_many_over_skip_navigation_order_by_take_unidirectional(bool async) @@ -1074,17 +938,6 @@ from t in r.ThreeSkipPayloadFullShared.OrderBy(e => e.Id).Skip(2).Take(3) select t, entryCount: 7); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Select_many_over_skip_navigation_of_type_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => from r in ss.Set() - // from t in r.RootSkipShared.OfType() - // select t, - // entryCount: 9); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_many_over_skip_navigation_cast_unidirectional(bool async) @@ -1107,41 +960,6 @@ orderby r.Id elementAsserter: (e, a) => AssertCollection(e, a), entryCount: 13); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Select_skip_navigation_multiple_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => from r in ss.Set() - // orderby r.Id - // select new - // { - // r.ThreeSkipFull, - // r.SelfSkipSharedLeft, - // r.CompositeKeySkipShared - // }, - // assertOrder: true, - // elementAsserter: (e, a) => - // { - // AssertCollection(e.ThreeSkipFull, a.ThreeSkipFull); - // AssertCollection(e.SelfSkipSharedLeft, a.SelfSkipSharedLeft); - // AssertCollection(e.CompositeKeySkipShared, a.CompositeKeySkipShared); - // }, - // entryCount: 50); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Select_skip_navigation_first_or_default_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => from r in ss.Set() - // orderby r.Id - // select r.CompositeKeySkipFull.OrderBy(e => e.Key1).ThenBy(e => e.Key2).FirstOrDefault(), - // assertOrder: true, - // entryCount: 12); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Include_skip_navigation_unidirectional(bool async) @@ -1252,36 +1070,6 @@ public virtual Task Filtered_include_skip_navigation_order_by_skip_take_unidirec et => et.ThreeSkipFull, includeFilter: x => x.OrderBy(i => i.Id).Skip(1).Take(2))), entryCount: 57); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Filtered_then_include_skip_navigation_where_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.ThreeSkipShared) - // .ThenInclude(e => e.OneSkipPayloadFullShared.Where(i => i.Id < 10)), - // elementAsserter: (e, a) => AssertInclude( - // e, a, - // new ExpectedInclude(et => et.ThreeSkipShared), - // new ExpectedFilteredInclude( - // et => et.OneSkipPayloadFullShared, "ThreeSkipShared", includeFilter: x => x.Where(i => i.Id < 10))), - // entryCount: 78); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Filtered_then_include_skip_navigation_order_by_skip_take_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.CompositeKeySkipShared) - // .ThenInclude(e => e.ThreeSkipFull.OrderBy(i => i.Id).Skip(1).Take(2)), - // elementAsserter: (e, a) => AssertInclude( - // e, a, - // new ExpectedInclude(et => et.CompositeKeySkipShared), - // new ExpectedFilteredInclude( - // et => et.ThreeSkipFull, "CompositeKeySkipShared", includeFilter: x => x.OrderBy(i => i.Id).Skip(1).Take(2))), - // entryCount: 104); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(bool async) @@ -1295,38 +1083,6 @@ public virtual Task Filtered_include_skip_navigation_where_then_include_skip_nav new ExpectedInclude(et => et.TwoSkipShared, "CompositeKeySkipFull")), entryCount: 44); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.TwoSkip.OrderBy(i => i.Id).Skip(1).Take(2)) - // .ThenInclude(e => e.ThreeSkipFull.Where(i => i.Id < 10)), - // elementAsserter: (e, a) => AssertInclude( - // e, a, - // new ExpectedFilteredInclude( - // et => et.TwoSkip, includeFilter: x => x.OrderBy(i => i.Id).Skip(1).Take(2)), - // new ExpectedFilteredInclude( - // et => et.ThreeSkipFull, "TwoSkip", includeFilter: x => x.Where(i => i.Id < 10))), - // entryCount: 100); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Filtered_include_skip_navigation_where_then_include_skip_navigation_order_by_skip_take_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.TwoSkip.Where(i => i.Id < 10)) - // .ThenInclude(e => e.ThreeSkipFull.OrderBy(i => i.Id).Skip(1).Take(2)), - // elementAsserter: (e, a) => AssertInclude( - // e, a, - // new ExpectedFilteredInclude( - // et => et.TwoSkip, includeFilter: x => x.Where(i => i.Id < 10)), - // new ExpectedFilteredInclude( - // et => et.ThreeSkipFull, "TwoSkip", includeFilter: x => x.OrderBy(i => i.Id).Skip(1).Take(2))), - // entryCount: 106); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Filter_include_on_skip_navigation_combined_unidirectional(bool async) @@ -1336,88 +1092,23 @@ public virtual Task Filter_include_on_skip_navigation_combined_unidirectional(bo .Include(e => e.OneSkip).ThenInclude(e => e.Collection), entryCount: 88); - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Filter_include_on_skip_navigation_combined_with_filtered_then_includes_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.OneSkipPayloadFull.Where(i => i.Id < 10)) - // .ThenInclude(e => e.TwoSkip.OrderBy(e => e.Id).Skip(1).Take(2)) - // .Include(e => e.OneSkipPayloadFull).ThenInclude(e => e.BranchSkip.Where(e => e.Id < 20)), - // elementAsserter: (e, a) => AssertInclude( - // e, a, - // new ExpectedFilteredInclude( - // et => et.OneSkipPayloadFull, includeFilter: x => x.Where(i => i.Id < 10)), - // new ExpectedFilteredInclude( - // et => et.TwoSkip, "OneSkipPayloadFull", includeFilter: x => x.OrderBy(e => e.Id).Skip(1).Take(2)), - // new ExpectedFilteredInclude( - // et => et.BranchSkip, "OneSkipPayloadFull", includeFilter: x => x.Where(e => e.Id < 20))), - // entryCount: 116); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Throws_when_different_filtered_include_unidirectional(bool async) - => Task.CompletedTask; - // => Assert.Equal( - // CoreStrings.MultipleFilteredIncludesOnSameNavigation( - // "navigation .Where(i => i.Id < 20)", "navigation .Where(i => i.Id < 10)") - // .Replace("\r", "").Replace("\n", ""), - // (await Assert.ThrowsAsync( - // () => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.OneSkip.Where(i => i.Id < 10)).ThenInclude(e => e.BranchSkip) - // .Include(e => e.OneSkip.Where(i => i.Id < 20)).ThenInclude(e => e.ThreeSkipPayloadFull)))).Message - // .Replace("\r", "").Replace("\n", "")); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Throws_when_different_filtered_then_include_unidirectional(bool async) - => Task.CompletedTask; - // => Assert.Equal( - // CoreStrings.MultipleFilteredIncludesOnSameNavigation( - // "navigation .Where(i => i.Id < 20)", "navigation .Where(i => i.Id < 10)") - // .Replace("\r", "").Replace("\n", ""), - // (await Assert.ThrowsAsync( - // () => AssertQuery( - // async, - // ss => ss.Set() - // .Include(e => e.TwoSkipShared) - // .ThenInclude(e => e.OneSkip.Where(i => i.Id < 10)).ThenInclude(e => e.BranchSkip) - // .Include(e => e.TwoSkipShared) - // .ThenInclude(e => e.OneSkip.Where(i => i.Id < 20)).ThenInclude(e => e.ThreeSkipPayloadFull)))).Message - // .Replace("\r", "").Replace("\n", "")); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Filtered_include_on_skip_navigation_then_filtered_include_on_navigation_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.OneSkipPayloadFull.Where(i => i.Id > 15)) - // .ThenInclude(e => e.Collection.Where(i => i.Id < 5)), - // elementAsserter: (e, a) => AssertInclude( - // e, a, - // new ExpectedFilteredInclude( - // et => et.OneSkipPayloadFull, includeFilter: x => x.Where(i => i.Id > 15)), - // new ExpectedFilteredInclude( - // et => et.Collection, "OneSkipPayloadFull", includeFilter: x => x.Where(i => i.Id < 5))), - // entryCount: 61); - - [ConditionalTheory(Skip = "TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Filtered_include_on_navigation_then_filtered_include_on_skip_navigation_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.Collection.Where(i => i.Id > 15)) - // .ThenInclude(e => e.ThreeSkipFull.Where(i => i.Id < 5)), - // elementAsserter: (e, a) => AssertInclude( - // e, a, - // new ExpectedFilteredInclude(et => et.Collection, includeFilter: x => x.Where(i => i.Id > 15)), - // new ExpectedFilteredInclude( - // et => et.ThreeSkipFull, "Collection", includeFilter: x => x.Where(i => i.Id < 5))), - // entryCount: 29); + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Throws_when_different_filtered_include_unidirectional(bool async) + => Assert.Equal( + CoreStrings.MultipleFilteredIncludesOnSameNavigation( + "navigation .Where(i => i.Id < 20)", "navigation .Where(i => i.Id < 10)") + .Replace("\r", "").Replace("\n", ""), + (await Assert.ThrowsAsync( + () => AssertQuery( + async, + ss => ss.Set() + .Include(e => EF.Property>(e, "UnidirectionalEntityOne").Where(i => i.Id < 10)) + .ThenInclude(e => e.BranchSkip) + .Include(e => EF.Property>(e, "UnidirectionalEntityOne").Where(i => i.Id < 20)) + .ThenInclude>( + e => EF.Property>(e, "UnidirectionalEntityThree"))))).Message + .Replace("\r", "").Replace("\n", "")); [ConditionalTheory(Skip = "Issue#21332")] [MemberData(nameof(IsAsyncData))] @@ -1428,47 +1119,6 @@ public virtual Task Includes_accessed_via_different_path_are_merged_unidirection .Include(e => e.JoinThreePayloadFull).ThenInclude(e => e.Three).ThenInclude(e => e.ReferenceInverse), entryCount: 0); - [ConditionalTheory(Skip = "Issue#21332; TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Filered_includes_accessed_via_different_path_are_merged_unidirectional(bool async) - => Task.CompletedTask; - // => AssertQuery( - // async, - // ss => ss.Set().Include(e => e.OneSkipPayloadFull).ThenInclude(e => e.Collection.Where(i => i.Id < 5)) - // .Include(e => e.JoinOnePayloadFull).ThenInclude(e => e.One).ThenInclude(e => e.Collection) - // .ThenInclude(e => e.Reference), - // elementAsserter: (e, a) => AssertInclude( - // e, a, - // new ExpectedInclude(e => e.OneSkipPayloadFull), - // new ExpectedFilteredInclude( - // e => e.Collection, "OneSkipPayloadFull", includeFilter: x => x.Where(i => i.Id < 5)), - // new ExpectedInclude(e => e.JoinOnePayloadFull), - // new ExpectedInclude(e => e.One, "JoinOnePayloadFull"), - // new ExpectedFilteredInclude( - // e => e.Collection, "JoinOnePayloadFull.One", includeFilter: x => x.Where(i => i.Id < 5)), - // new ExpectedInclude(e => e.Reference, "OneSkipPayloadFull.Collection"), - // new ExpectedInclude(e => e.Reference, "JoinOnePayloadFull.One.Collection")), - // entryCount: 0); - - [ConditionalTheory(Skip = "Issue#21332; TODOU: Needs #27493")] - [MemberData(nameof(IsAsyncData))] - public virtual Task Throws_when_different_filtered_then_include_via_different_paths_unidirectional(bool async) - => Task.CompletedTask; - // => Assert.Equal( - // CoreStrings.MultipleFilteredIncludesOnSameNavigation( - // "navigation .Where(i => i.Id < 20)", "navigation .Where(i => i.Id < 10)") - // .Replace("\r", "").Replace("\n", ""), - // (await Assert.ThrowsAsync( - // () => AssertQuery( - // async, - // ss => ss.Set() - // .Include(e => e.OneSkipPayloadFull) - // .ThenInclude(e => e.Collection.Where(i => i.Id < 20)) - // .Include(e => e.JoinOnePayloadFull) - // .ThenInclude(e => e.One) - // .ThenInclude(e => e.Collection.Where(i => i.Id < 10))))).Message - // .Replace("\r", "").Replace("\n", "")); - [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Select_many_over_skip_navigation_where_non_equality_unidirectional(bool async) diff --git a/test/EFCore.Specification.Tests/UnidirectionalManyToManyLoadTestBase.cs b/test/EFCore.Specification.Tests/UnidirectionalManyToManyLoadTestBase.cs index 9a7055e78df..1f43bd2071b 100644 --- a/test/EFCore.Specification.Tests/UnidirectionalManyToManyLoadTestBase.cs +++ b/test/EFCore.Specification.Tests/UnidirectionalManyToManyLoadTestBase.cs @@ -840,113 +840,111 @@ public virtual async Task Load_collection_using_Query_with_Include_for_inverse_u } Assert.Equal(children, left.TwoSkipShared.ToList()); - - // TODOU: Should be 7, when #27493 is implemented. - Assert.Equal(17, context.ChangeTracker.Entries().Count()); + Assert.Equal(7, context.ChangeTracker.Entries().Count()); } - [ConditionalTheory(Skip = "TODOU: Needs #27493")] + [ConditionalTheory] [InlineData(true)] [InlineData(false)] - public virtual Task Load_collection_using_Query_with_filtered_Include_unidirectional(bool async) + public virtual async Task Load_collection_using_Query_with_filtered_Include_unidirectional(bool async) { - return Task.CompletedTask; - // using var context = Fixture.CreateContext(); - // - // var left = context.Set().Find(3); - // - // ClearLog(); - // - // var collectionEntry = context.Entry(left).Collection(e => e.TwoSkipShared); - // - // Assert.False(collectionEntry.IsLoaded); - // - // var children = async - // ? await collectionEntry.Query().Include(e => e.ThreeSkipFull.Where(e => e.Id == 13 || e.Id == 11)).ToListAsync() - // : collectionEntry.Query().Include(e => e.ThreeSkipFull.Where(e => e.Id == 13 || e.Id == 11)).ToList(); - // - // Assert.False(collectionEntry.IsLoaded); - // foreach (var entityTwo in left.TwoSkipShared) - // { - // Assert.False(context.Entry(entityTwo).Collection("UnidirectionalEntityOne").IsLoaded); - // Assert.True(context.Entry(entityTwo).Collection(e => e.ThreeSkipFull).IsLoaded); - // - // foreach (var entityThree in entityTwo.ThreeSkipFull) - // { - // Assert.False(context.Entry(entityThree).Collection(e => e.TwoSkipFull).IsLoaded); - // } - // } - // - // RecordLog(); - // context.ChangeTracker.LazyLoadingEnabled = false; - // - // Assert.Equal(3, left.TwoSkipShared.Count); - // foreach (var right in left.TwoSkipShared) - // { - // Assert.Contains(left, context.Entry(right).Collection("UnidirectionalEntityOne").CurrentValue!.Cast()); - // foreach (var three in right.ThreeSkipFull) - // { - // Assert.True(three.Id == 11 || three.Id == 13); - // Assert.Contains(right, three.TwoSkipFull); - // } - // } - // - // Assert.Equal(children, left.TwoSkipShared.ToList()); - // - // Assert.Equal(9, context.ChangeTracker.Entries().Count()); + using var context = Fixture.CreateContext(); + + var left = await context.Set().FindAsync(3); + + ClearLog(); + + var collectionEntry = context.Entry(left).Collection(e => e.TwoSkipShared); + + Assert.False(collectionEntry.IsLoaded); + + var children = async + ? await collectionEntry.Query() + .Include(e => EF.Property>(e, "UnidirectionalEntityThree") + .Where(e => e.Id == 13 || e.Id == 11)).ToListAsync() + : collectionEntry.Query() + .Include(e => EF.Property>(e, "UnidirectionalEntityThree") + .Where(e => e.Id == 13 || e.Id == 11)).ToList(); + + Assert.False(collectionEntry.IsLoaded); + foreach (var entityTwo in left.TwoSkipShared) + { + Assert.False(context.Entry(entityTwo).Collection("UnidirectionalEntityOne").IsLoaded); + Assert.True(context.Entry(entityTwo).Collection("UnidirectionalEntityThree").IsLoaded); + + foreach (var entityThree in + context.Entry(entityTwo).Collection("UnidirectionalEntityThree").CurrentValue!) + { + Assert.False(context.Entry(entityThree).Collection(e => e.TwoSkipFull).IsLoaded); + } + } + + RecordLog(); + context.ChangeTracker.LazyLoadingEnabled = false; + + Assert.Equal(3, left.TwoSkipShared.Count); + foreach (var right in left.TwoSkipShared) + { + Assert.Contains(left, context.Entry(right).Collection("UnidirectionalEntityOne").CurrentValue!.Cast()); + foreach (var three in context.Entry(right).Collection("UnidirectionalEntityThree").CurrentValue!) + { + Assert.True(three.Id == 11 || three.Id == 13); + Assert.Contains(right, three.TwoSkipFull); + } + } + + Assert.Equal(children, left.TwoSkipShared.ToList()); + + Assert.Equal(9, context.ChangeTracker.Entries().Count()); } - [ConditionalTheory (Skip = "TODOU: Needs #27493")] + [ConditionalTheory] [InlineData(true)] [InlineData(false)] - public virtual Task Load_collection_using_Query_with_filtered_Include_and_projection_unidirectional(bool async) + public virtual async Task Load_collection_using_Query_with_filtered_Include_and_projection_unidirectional(bool async) { - return Task.CompletedTask; - // using var context = Fixture.CreateContext(); - // - // var left = context.Set().Find(3); - // - // ClearLog(); - // - // var collectionEntry = context.Entry(left).Collection(e => e.TwoSkipShared); - // - // Assert.False(collectionEntry.IsLoaded); - // - // var queryable = collectionEntry - // .Query() - // .Include(e => e.ThreeSkipFull.Where(e => e.Id == 13 || e.Id == 11)) - // .OrderBy(e => e.Id) - // .Select( - // e => new - // { - // e.Id, - // e.Name, - // Count3 = e.ThreeSkipFull.Count - // }); - // - // var projected = async - // ? await queryable.ToListAsync() - // : queryable.ToList(); - // - // RecordLog(); - // context.ChangeTracker.LazyLoadingEnabled = false; - // Assert.False(collectionEntry.IsLoaded); - // Assert.Empty(left.TwoSkipShared); - // Assert.Single(context.ChangeTracker.Entries()); - // - // Assert.Equal(3, projected.Count); - // - // Assert.Equal(10, projected[0].Id); - // Assert.Equal("EntityTwo 10", projected[0].Name); - // Assert.Equal(1, projected[0].Count3); - // - // Assert.Equal(11, projected[1].Id); - // Assert.Equal("EntityTwo 11", projected[1].Name); - // Assert.Equal(4, projected[1].Count3); - // - // Assert.Equal(16, projected[2].Id); - // Assert.Equal("EntityTwo 16", projected[2].Name); - // Assert.Equal(2, projected[2].Count3); + using var context = Fixture.CreateContext(); + + var left = await context.Set().FindAsync(3); + + ClearLog(); + + var collectionEntry = context.Entry(left).Collection(e => e.TwoSkipShared); + + Assert.False(collectionEntry.IsLoaded); + + var queryable = collectionEntry + .Query() + .Include( + e => EF.Property>(e, "UnidirectionalEntityThree") + .Where(e => e.Id == 13 || e.Id == 11)) + .OrderBy(e => e.Id) + .Select( + e => new + { + e.Id, e.Name, + }); + + var projected = async + ? await queryable.ToListAsync() + : queryable.ToList(); + + RecordLog(); + context.ChangeTracker.LazyLoadingEnabled = false; + Assert.False(collectionEntry.IsLoaded); + Assert.Empty(left.TwoSkipShared); + Assert.Single(context.ChangeTracker.Entries()); + + Assert.Equal(3, projected.Count); + + Assert.Equal(10, projected[0].Id); + Assert.Equal("EntityTwo 10", projected[0].Name); + + Assert.Equal(11, projected[1].Id); + Assert.Equal("EntityTwo 11", projected[1].Name); + + Assert.Equal(16, projected[2].Id); + Assert.Equal("EntityTwo 16", projected[2].Name); } [ConditionalTheory] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyNoTrackingQuerySqlServerTest.cs index d763ba26806..24179593312 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyNoTrackingQuerySqlServerTest.cs @@ -15,7 +15,7 @@ public TPCManyToManyNoTrackingQuerySqlServerTest(TPCManyToManyQuerySqlServerFixt protected override bool CanExecuteQueryString => true; - [ConditionalFact(Skip = "TODOU: Needs #27493")] + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); @@ -1053,8 +1053,8 @@ public override async Task Include_skip_navigation_split(bool async) @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", - // - @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [e].[Key1], [e].[Key2], [e].[Key3] + // + @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [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] @@ -1081,8 +1081,8 @@ public override async Task Include_skip_navigation_then_reference_split(bool asy @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityTwos] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id] FROM [EntityTwos] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId], [j].[TwoId] @@ -1101,8 +1101,8 @@ public override async Task Include_skip_navigation_then_include_skip_navigation_ @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", - // - @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [e].[Key1], [e].[Key2], [e].[Key3], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] + // + @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [e].[Key1], [e].[Key2], [e].[Key3], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen], [j].[LeafId], [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3] @@ -1110,8 +1110,8 @@ FROM [JoinCompositeKeyToLeaf] AS [j] INNER JOIN [Leaves] AS [l] ON [j].[LeafId] = [l].[Id] ) AS [t] ON [e].[Key1] = [t].[CompositeId1] AND [e].[Key2] = [t].[CompositeId2] AND [e].[Key3] = [t].[CompositeId3] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Id]", - // - @"SELECT [t0].[Id], [t0].[Name], [e].[Key1], [e].[Key2], [e].[Key3], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Id] + // + @"SELECT [t0].[Id], [t0].[Name], [e].[Key1], [e].[Key2], [e].[Key3], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Id] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( SELECT [l].[Id], [j].[LeafId], [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3] @@ -1134,8 +1134,8 @@ public override async Task Include_skip_navigation_then_include_reference_and_sk @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId] + // + @"SELECT [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId], [j].[OneId], [j].[ThreeId] @@ -1144,8 +1144,8 @@ FROM [JoinOneToThreePayloadFull] AS [j] LEFT JOIN [EntityTwos] AS [e1] ON [e0].[Id] = [e1].[ReferenceInverseId] ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t].[Id0]", - // - @"SELECT [t0].[Id], [t0].[Name], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t].[Id0] + // + @"SELECT [t0].[Id], [t0].[Name], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t].[Id0] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [e1].[Id] AS [Id0], [j].[OneId], [j].[ThreeId] @@ -1170,8 +1170,8 @@ public override async Task Include_skip_navigation_and_reference_split(bool asyn FROM [EntityTwos] AS [e] LEFT JOIN [EntityThrees] AS [e0] ON [e].[Id] = [e0].[ReferenceInverseId] ORDER BY [e].[Id], [e0].[Id]", - // - @"SELECT [t].[Id], [t].[Name], [e].[Id], [e0].[Id] + // + @"SELECT [t].[Id], [t].[Name], [e].[Id], [e0].[Id] FROM [EntityTwos] AS [e] LEFT JOIN [EntityThrees] AS [e0] ON [e].[Id] = [e0].[ReferenceInverseId] INNER JOIN ( @@ -1190,8 +1190,8 @@ public override async Task Filtered_include_skip_navigation_where_split(bool asy @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[Name], [e].[Id] + // + @"SELECT [t].[Id], [t].[Name], [e].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[Name], [j].[ThreeId] @@ -1210,8 +1210,8 @@ public override async Task Filtered_include_skip_navigation_order_by_split(bool @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[CollectionInverseId], [e0].[ExtraId], [e0].[Name], [e0].[ReferenceInverseId], [j].[ThreeId] @@ -1229,8 +1229,8 @@ public override async Task Filtered_include_skip_navigation_order_by_skip_split( @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityTwos] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id] FROM [EntityTwos] AS [e] INNER JOIN ( SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[SelfSkipSharedLeftId] @@ -1252,8 +1252,8 @@ public override async Task Filtered_include_skip_navigation_order_by_take_split( @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Key1], [e].[Key2], [e].[Key3] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Key1], [e].[Key2], [e].[Key3] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3] @@ -1275,8 +1275,8 @@ public override async Task Filtered_include_skip_navigation_order_by_skip_take_s @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Key1], [e].[Key2], [e].[Key3] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Key1], [e].[Key2], [e].[Key3] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] @@ -1307,8 +1307,8 @@ UNION ALL FROM [Leaves] AS [l] ) AS [t] ORDER BY [t].[Id]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t].[Id], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t].[Id], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId] FROM ( SELECT [r].[Id] FROM [Roots] AS [r] @@ -1325,8 +1325,8 @@ FROM [EntityRootEntityThree] AS [e] INNER JOIN [EntityThrees] AS [e0] ON [e].[ThreeSkipSharedId] = [e0].[Id] ) AS [t0] ON [t].[Id] = [t0].[RootSkipSharedId] ORDER BY [t].[Id], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id]", - // - @"SELECT [t1].[Id], [t1].[Name], [t].[Id], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id] + // + @"SELECT [t1].[Id], [t1].[Name], [t].[Id], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id] FROM ( SELECT [r].[Id] FROM [Roots] AS [r] @@ -1368,8 +1368,8 @@ UNION ALL FROM [Leaves] AS [l] ) AS [t] ORDER BY [t].[Id]", - // - @"SELECT [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[Name], [t].[Id], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3] + // + @"SELECT [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[Name], [t].[Id], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3] FROM ( SELECT [r].[Id] FROM [Roots] AS [r] @@ -1386,8 +1386,8 @@ FROM [EntityCompositeKeyEntityRoot] AS [e] INNER JOIN [EntityCompositeKeys] AS [e0] ON [e].[CompositeKeySkipSharedKey1] = [e0].[Key1] AND [e].[CompositeKeySkipSharedKey2] = [e0].[Key2] AND [e].[CompositeKeySkipSharedKey3] = [e0].[Key3] ) AS [t0] ON [t].[Id] = [t0].[RootSkipSharedId] ORDER BY [t].[Id], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Key1], [t0].[Key2], [t0].[Key3]", - // - @"SELECT [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [t].[Id], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Key1], [t0].[Key2], [t0].[Key3] + // + @"SELECT [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [t].[Id], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Key1], [t0].[Key2], [t0].[Key3] FROM ( SELECT [r].[Id] FROM [Roots] AS [r] @@ -1423,8 +1423,8 @@ public override async Task Filtered_include_skip_navigation_where_then_include_s @"SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen] FROM [Leaves] AS [l] ORDER BY [l].[Id]", - // - @"SELECT [t].[Key1], [t].[Key2], [t].[Key3], [t].[Name], [l].[Id], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] + // + @"SELECT [t].[Key1], [t].[Key2], [t].[Key3], [t].[Name], [l].[Id], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] FROM [Leaves] AS [l] INNER JOIN ( SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name], [j].[LeafId], [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3] @@ -1433,8 +1433,8 @@ FROM [JoinCompositeKeyToLeaf] AS [j] WHERE [e].[Key1] < 5 ) AS [t] ON [l].[Id] = [t].[LeafId] ORDER BY [l].[Id], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Key1], [t].[Key2], [t].[Key3]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [l].[Id], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Key1], [t].[Key2], [t].[Key3] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [l].[Id], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Key1], [t].[Key2], [t].[Key3] FROM [Leaves] AS [l] INNER JOIN ( SELECT [e].[Key1], [e].[Key2], [e].[Key3], [j].[LeafId], [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3] @@ -1458,8 +1458,8 @@ public override async Task Filtered_include_skip_navigation_order_by_skip_take_t @"SELECT [e].[Id], [e].[Name] FROM [EntityOnes] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t0].[OneId], [t0].[TwoId] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t0].[OneId], [t0].[TwoId] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[OneId], [t].[TwoId] @@ -1471,8 +1471,8 @@ FROM [JoinOneToTwo] AS [j] WHERE 1 < [t].[row] AND [t].[row] <= 3 ) AS [t0] ON [e].[Id] = [t0].[OneId] ORDER BY [e].[Id], [t0].[OneId], [t0].[Id], [t0].[TwoId]", - // - @"SELECT [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t0].[OneId], [t0].[TwoId], [t0].[Id] + // + @"SELECT [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t0].[OneId], [t0].[TwoId], [t0].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [t].[Id], [t].[OneId], [t].[TwoId] @@ -1500,8 +1500,8 @@ public override async Task Filtered_include_skip_navigation_where_then_include_s @"SELECT [e].[Id], [e].[Name] FROM [EntityOnes] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId] + // + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[CollectionInverseId], [e0].[ExtraId], [e0].[Name], [e0].[ReferenceInverseId], [j].[OneId], [j].[TwoId] @@ -1510,8 +1510,8 @@ FROM [JoinOneToTwo] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [e0].[Id], [j].[OneId], [j].[TwoId] @@ -1539,8 +1539,8 @@ public override async Task Filter_include_on_skip_navigation_combined_split(bool @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityTwos] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId] + // + @"SELECT [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId] FROM [EntityTwos] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId], [j].[OneId], [j].[TwoId] @@ -1550,8 +1550,8 @@ FROM [JoinOneToTwo] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[TwoId] ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0]", - // - @"SELECT [e2].[Id], [e2].[CollectionInverseId], [e2].[ExtraId], [e2].[Name], [e2].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0] + // + @"SELECT [e2].[Id], [e2].[CollectionInverseId], [e2].[ExtraId], [e2].[Name], [e2].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0] FROM [EntityTwos] AS [e] INNER JOIN ( SELECT [e0].[Id], [e1].[Id] AS [Id0], [j].[OneId], [j].[TwoId] @@ -1572,8 +1572,8 @@ public override async Task Filter_include_on_skip_navigation_combined_with_filte @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[Name], [e].[Id], [t].[OneId], [t].[ThreeId] + // + @"SELECT [t].[Id], [t].[Name], [e].[Id], [t].[OneId], [t].[ThreeId] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[Name], [j].[OneId], [j].[ThreeId] @@ -1582,8 +1582,8 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [j].[OneId], [j].[ThreeId] @@ -1601,8 +1601,8 @@ FROM [JoinOneToTwo] AS [j0] WHERE 1 < [t1].[row] AND [t1].[row] <= 3 ) AS [t0] ON [t].[Id] = [t0].[OneId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t0].[OneId], [t0].[Id]", - // - @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + // + @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [j].[OneId], [j].[ThreeId] @@ -1633,8 +1633,8 @@ public override async Task Filtered_include_on_skip_navigation_then_filtered_inc @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[Name], [e].[Id], [t].[OneId], [t].[ThreeId] + // + @"SELECT [t].[Id], [t].[Name], [e].[Id], [t].[OneId], [t].[ThreeId] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[Name], [j].[OneId], [j].[ThreeId] @@ -1643,8 +1643,8 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] > 15 ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [e0].[Id], [j].[OneId], [j].[ThreeId] @@ -1668,8 +1668,8 @@ public override async Task Filtered_include_on_navigation_then_filtered_include_ @"SELECT [e].[Id], [e].[Name] FROM [EntityOnes] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[CollectionInverseId], [e0].[ExtraId], [e0].[Name], [e0].[ReferenceInverseId] @@ -1677,8 +1677,8 @@ FROM [EntityTwos] AS [e0] WHERE [e0].[Id] > 15 ) AS [t] ON [e].[Id] = [t].[CollectionInverseId] ORDER BY [e].[Id], [t].[Id]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[Id] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[CollectionInverseId] @@ -1821,7 +1821,8 @@ FROM [EntityCompositeKeyEntityTwo] AS [e0] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id]"); } - public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property( + bool async) { await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); @@ -1848,6 +1849,610 @@ WHERE [e1].[Id] < 10 ORDER BY [e].[Id], [t1].[Id], [t1].[OneId], [t1].[TwoId], [t1].[ThreeId], [t1].[TwoId0]"); } + public override async Task Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(async); + + AssertSql(); + } + + public override async Task Skip_navigation_all_unidirectional(bool async) + { + await base.Skip_navigation_all_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE NOT EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND NOT ([u1].[Name] LIKE N'%B%'))"); + } + + public override async Task Skip_navigation_any_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_any_with_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + WHERE [u].[Id] = [u0].[UnidirectionalEntityOneId] AND ([u1].[Name] LIKE N'%B%'))"); + } + + public override async Task Skip_navigation_contains_unidirectional(bool async) + { + await base.Skip_navigation_contains_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND [u1].[Id] = 1)"); + } + + public override async Task Skip_navigation_count_without_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_without_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE ( + SELECT COUNT(*) + FROM [UnidirectionalJoinOneSelfPayload] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[LeftId] = [u1].[Id] + WHERE [u].[Id] = [u0].[RightId]) > 0"); + } + + public override async Task Skip_navigation_count_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_with_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +ORDER BY ( + SELECT COUNT(*) + FROM [UnidirectionalJoinOneToBranch] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u1].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u1] + UNION ALL + SELECT [u2].[Id], [u2].[Name], [u2].[Number], [u2].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u2] + ) AS [t] ON [u0].[UnidirectionalEntityBranchId] = [t].[Id] + WHERE [u].[Id] = [u0].[UnidirectionalEntityOneId] AND [t].[Name] IS NOT NULL AND ([t].[Name] LIKE N'L%')), [u].[Id]"); + } + + public override async Task Skip_navigation_select_subquery_average_unidirectional(bool async) + { + await base.Skip_navigation_select_subquery_average_unidirectional(async); + + AssertSql( + @"SELECT ( + SELECT AVG(CAST([u1].[Key1] AS float)) + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u0] + INNER JOIN [UnidirectionalEntityCompositeKeys] AS [u1] ON [u0].[CompositeId1] = [u1].[Key1] AND [u0].[CompositeId2] = [u1].[Key2] AND [u0].[CompositeId3] = [u1].[Key3] + WHERE [u].[Id] = [u0].[LeafId]) +FROM [UnidirectionalLeaves] AS [u]"); + } + + public override async Task Skip_navigation_order_by_reverse_first_or_default_unidirectional(bool async) + { + await base.Skip_navigation_order_by_reverse_first_or_default_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[ThreeId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[ThreeId], ROW_NUMBER() OVER(PARTITION BY [u0].[ThreeId] ORDER BY [u1].[Id] DESC) AS [row] + FROM [UnidirectionalJoinTwoToThree] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [u].[Id] = [t0].[ThreeId]"); + } + + public override async Task Skip_navigation_of_type_unidirectional(bool async) + { + await base.Skip_navigation_of_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[RootSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], NULL AS [Number], NULL AS [IsGreen], N'UnidirectionalEntityRoot' AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + UNION ALL + SELECT [u2].[Id], [u2].[Name], [u2].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u2] + UNION ALL + SELECT [u3].[Id], [u3].[Name], [u3].[Number], [u3].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u3] + ) AS [t] ON [u0].[RootSkipSharedId] = [t].[Id] + WHERE [t].[Discriminator] = N'UnidirectionalEntityLeaf' +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Join_with_skip_navigation_unidirectional(bool async) + { + await base.Join_with_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [u0].[Id], [u0].[CollectionInverseId], [u0].[ExtraId], [u0].[Name], [u0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +INNER JOIN [UnidirectionalEntityTwos] AS [u0] ON [u].[Id] = ( + SELECT TOP(1) [u2].[Id] + FROM [UnidirectionalEntityTwoUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[SelfSkipSharedRightId] = [u2].[Id] + WHERE [u0].[Id] = [u1].[UnidirectionalEntityTwoId] + ORDER BY [u2].[Id])"); + } + + public override async Task Left_join_with_skip_navigation_unidirectional(bool async) + { + await base.Left_join_with_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [u0].[Key1], [u0].[Key2], [u0].[Key3], [u0].[Name] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN [UnidirectionalEntityCompositeKeys] AS [u0] ON ( + SELECT TOP(1) [u2].[Id] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[TwoSkipSharedId] = [u2].[Id] + WHERE [u].[Key1] = [u1].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [u1].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [u1].[UnidirectionalEntityCompositeKeyKey3] + ORDER BY [u2].[Id]) = ( + SELECT TOP(1) [u4].[Id] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u3] + INNER JOIN [UnidirectionalEntityThrees] AS [u4] ON [u3].[ThreeId] = [u4].[Id] + WHERE [u0].[Key1] = [u3].[CompositeId1] AND [u0].[Key2] = [u3].[CompositeId2] AND [u0].[Key3] = [u3].[CompositeId3] + ORDER BY [u4].[Id]) +ORDER BY [u].[Key1], [u0].[Key1], [u].[Key2], [u0].[Key2]"); + } + + public override async Task Select_many_over_skip_navigation_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] +FROM ( + SELECT [u1].[Id] + FROM [UnidirectionalRoots] AS [u1] + UNION ALL + SELECT [u2].[Id] + FROM [UnidirectionalBranches] AS [u2] + UNION ALL + SELECT [u3].[Id] + FROM [UnidirectionalLeaves] AS [u3] +) AS [t] +INNER JOIN ( + SELECT [u0].[Id], [u0].[CollectionInverseId], [u0].[Name], [u0].[ReferenceInverseId], [u].[UnidirectionalEntityRootId] + FROM [UnidirectionalEntityRootUnidirectionalEntityThree] AS [u] + INNER JOIN [UnidirectionalEntityThrees] AS [u0] ON [u].[ThreeSkipSharedId] = [u0].[Id] +) AS [t0] ON [t].[Id] = [t0].[UnidirectionalEntityRootId]"); + } + + public override async Task Select_many_over_skip_navigation_where_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[OneId]"); + } + + public override async Task Select_many_over_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[UnidirectionalEntityOneId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[UnidirectionalEntityOneId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityOneId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[OneId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId], ROW_NUMBER() OVER(PARTITION BY [u0].[OneId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 2 < [t].[row] AND [t].[row] <= 5 +) AS [t0] ON [u].[Id] = [t0].[OneId]"); + } + + public override async Task Select_many_over_skip_navigation_cast_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_cast_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[UnidirectionalEntityOneId] + FROM [UnidirectionalJoinOneToBranch] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u1].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u1] + UNION ALL + SELECT [u2].[Id], [u2].[Name], [u2].[Number], [u2].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u2] + ) AS [t] ON [u0].[UnidirectionalEntityBranchId] = [t].[Id] +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Select_skip_navigation_unidirectional(bool async) + { + await base.Select_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [t].[Id], [t].[Name], [t].[LeftId], [t].[RightId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u0].[LeftId], [u0].[RightId] + FROM [UnidirectionalJoinOneSelfPayload] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[LeftId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[RightId] +ORDER BY [u].[Id], [t].[LeftId], [t].[RightId]"); + } + + public override async Task Include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[RootSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], NULL AS [Number], NULL AS [IsGreen], N'UnidirectionalEntityRoot' AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + UNION ALL + SELECT [u2].[Id], [u2].[Name], [u2].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u2] + UNION ALL + SELECT [u3].[Id], [u3].[Name], [u3].[Number], [u3].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u3] + ) AS [t] ON [u0].[RootSkipSharedId] = [t].[Id] +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Include_skip_navigation_then_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_then_reference_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [t].[OneId], [t].[TwoId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Id] AS [Id0], [u2].[CollectionInverseId], [u2].[ExtraId], [u2].[Name] AS [Name0], [u2].[ReferenceInverseId], [u0].[OneId], [u0].[TwoId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[Id] = [u2].[ReferenceInverseId] +) AS [t] ON [u].[Id] = [t].[TwoId] +ORDER BY [u].[Id], [t].[OneId], [t].[TwoId], [t].[Id]"); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0], [t0].[Name0], [t0].[UnidirectionalEntityBranchId], [t0].[UnidirectionalEntityOneId] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u1].[Number], [u1].[IsGreen], [u0].[LeafId], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], [t].[Id] AS [Id0], [t].[Name] AS [Name0], [t].[UnidirectionalEntityBranchId], [t].[UnidirectionalEntityOneId] + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u0] + INNER JOIN [UnidirectionalLeaves] AS [u1] ON [u0].[LeafId] = [u1].[Id] + LEFT JOIN ( + SELECT [u3].[Id], [u3].[Name], [u2].[UnidirectionalEntityBranchId], [u2].[UnidirectionalEntityOneId] + FROM [UnidirectionalJoinOneToBranch] AS [u2] + INNER JOIN [UnidirectionalEntityOnes] AS [u3] ON [u2].[UnidirectionalEntityOneId] = [u3].[Id] + ) AS [t] ON [u1].[Id] = [t].[UnidirectionalEntityBranchId] +) AS [t0] ON [u].[Key1] = [t0].[CompositeId1] AND [u].[Key2] = [t0].[CompositeId2] AND [u].[Key3] = [t0].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id], [t0].[UnidirectionalEntityBranchId], [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t0].[Id], [t0].[Name], [t0].[Id0], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name0], [t0].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Id1], [t0].[Name1], [t0].[LeftId], [t0].[RightId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Id] AS [Id0], [u2].[CollectionInverseId], [u2].[ExtraId], [u2].[Name] AS [Name0], [u2].[ReferenceInverseId], [u0].[OneId], [u0].[ThreeId], [t].[Id] AS [Id1], [t].[Name] AS [Name1], [t].[LeftId], [t].[RightId] + FROM [UnidirectionalJoinOneToThreePayloadFull] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[Id] = [u2].[ReferenceInverseId] + LEFT JOIN ( + SELECT [u4].[Id], [u4].[Name], [u3].[LeftId], [u3].[RightId] + FROM [UnidirectionalJoinOneSelfPayload] AS [u3] + INNER JOIN [UnidirectionalEntityOnes] AS [u4] ON [u3].[RightId] = [u4].[Id] + ) AS [t] ON [u1].[Id] = [t].[LeftId] +) AS [t0] ON [u].[Id] = [t0].[ThreeId] +ORDER BY [u].[Id], [t0].[OneId], [t0].[ThreeId], [t0].[Id], [t0].[Id0], [t0].[LeftId], [t0].[RightId]"); + } + + public override async Task Include_skip_navigation_and_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_and_reference_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [u0].[Id], [t].[Id], [t].[Name], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityOneId], [u0].[CollectionInverseId], [u0].[Name], [u0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN [UnidirectionalEntityThrees] AS [u0] ON [u].[Id] = [u0].[ReferenceInverseId] +LEFT JOIN ( + SELECT [u2].[Id], [u2].[Name], [u1].[TwoSkipSharedId], [u1].[UnidirectionalEntityOneId] + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityOnes] AS [u2] ON [u1].[UnidirectionalEntityOneId] = [u2].[Id] +) AS [t] ON [u].[Id] = [t].[TwoSkipSharedId] +ORDER BY [u].[Id], [u0].[Id], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityOneId]"); + } + + public override async Task Filtered_include_skip_navigation_where_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_unidirectional(async); + + AssertSql( + @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId], [t].[Id], [t].[Name], [t].[OneId], [t].[ThreeId] +FROM [EntityThrees] AS [e] +LEFT JOIN ( + SELECT [e0].[Id], [e0].[Name], [j].[OneId], [j].[ThreeId] + FROM [JoinOneToThreePayloadFullShared] AS [j] + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e0].[Id] < 10 +) AS [t] ON [e].[Id] = [t].[ThreeId] +ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[ThreeId], [t].[TwoId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[ThreeId], [u0].[TwoId] + FROM [UnidirectionalJoinTwoToThree] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[ThreeId] +ORDER BY [u].[Id], [t].[Id], [t].[ThreeId]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[SelfSkipSharedRightId], [t0].[UnidirectionalEntityTwoId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[SelfSkipSharedRightId], [t].[UnidirectionalEntityTwoId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[SelfSkipSharedRightId], [u0].[UnidirectionalEntityTwoId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityTwoId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityTwoUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[SelfSkipSharedRightId] = [u1].[Id] + ) AS [t] + WHERE 2 < [t].[row] +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityTwoId] +ORDER BY [u].[Id], [t0].[UnidirectionalEntityTwoId], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityCompositeKeyKey1], [t].[UnidirectionalEntityCompositeKeyKey2], [t].[UnidirectionalEntityCompositeKeyKey3] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[TwoSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_unidirectional(async); +AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[Id0] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[Id0], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[Id] AS [Id0], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], ROW_NUMBER() OVER(PARTITION BY [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 1 < [t].[row] AND [t].[row] <= 3 +) AS [t0] ON [u].[Key1] = [t0].[CompositeId1] AND [u].[Key2] = [t0].[CompositeId2] AND [u].[Key3] = [t0].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u].[Number], [u].[IsGreen], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[Name], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name0], [t0].[ReferenceInverseId], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalLeaves] AS [u] +LEFT JOIN ( + SELECT [u1].[Key1], [u1].[Key2], [u1].[Key3], [u1].[Name], [u0].[LeafId], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name] AS [Name0], [t].[ReferenceInverseId], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityCompositeKeyKey1], [t].[UnidirectionalEntityCompositeKeyKey2], [t].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u0] + INNER JOIN [UnidirectionalEntityCompositeKeys] AS [u1] ON [u0].[CompositeId1] = [u1].[Key1] AND [u0].[CompositeId2] = [u1].[Key2] AND [u0].[CompositeId3] = [u1].[Key3] + LEFT JOIN ( + SELECT [u3].[Id], [u3].[CollectionInverseId], [u3].[ExtraId], [u3].[Name], [u3].[ReferenceInverseId], [u2].[TwoSkipSharedId], [u2].[UnidirectionalEntityCompositeKeyKey1], [u2].[UnidirectionalEntityCompositeKeyKey2], [u2].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u2] + INNER JOIN [UnidirectionalEntityTwos] AS [u3] ON [u2].[TwoSkipSharedId] = [u3].[Id] + ) AS [t] ON [u1].[Key1] = [t].[UnidirectionalEntityCompositeKeyKey1] AND [u1].[Key2] = [t].[UnidirectionalEntityCompositeKeyKey2] AND [u1].[Key3] = [t].[UnidirectionalEntityCompositeKeyKey3] + WHERE [u1].[Key1] < 5 +) AS [t0] ON [u].[Id] = [t0].[LeafId] +ORDER BY [u].[Id], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Filter_include_on_skip_navigation_combined_unidirectional(bool async) + { + await base.Filter_include_on_skip_navigation_combined_unidirectional(async); + + AssertSql( + @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [t].[OneId], [t].[TwoId], [t].[Id1], [t].[CollectionInverseId0], [t].[ExtraId0], [t].[Name1], [t].[ReferenceInverseId0] +FROM [EntityTwos] AS [e] +LEFT JOIN ( + SELECT [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId], [j].[OneId], [j].[TwoId], [e2].[Id] AS [Id1], [e2].[CollectionInverseId] AS [CollectionInverseId0], [e2].[ExtraId] AS [ExtraId0], [e2].[Name] AS [Name1], [e2].[ReferenceInverseId] AS [ReferenceInverseId0] + FROM [JoinOneToTwo] AS [j] + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + LEFT JOIN [EntityTwos] AS [e1] ON [e0].[Id] = [e1].[ReferenceInverseId] + LEFT JOIN [EntityTwos] AS [e2] ON [e0].[Id] = [e2].[CollectionInverseId] + WHERE [e0].[Id] < 10 +) AS [t] ON [e].[Id] = [t].[TwoId] +ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0]"); + } + + public override async Task Throws_when_different_filtered_include_unidirectional(bool async) + { + await base.Throws_when_different_filtered_include_unidirectional(async); + + AssertSql(); + } + + public override async Task Includes_accessed_via_different_path_are_merged_unidirectional(bool async) + { + await base.Includes_accessed_via_different_path_are_merged_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[Id0] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[Id0], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[Id] AS [Id0], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], ROW_NUMBER() OVER(PARTITION BY [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 1 < [t].[row] AND [t].[row] <= 3 +) AS [t0] ON [u].[Key1] = [t0].[CompositeId1] AND [u].[Key2] = [t0].[CompositeId2] AND [u].[Key3] = [t0].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id]"); + } + + public override async Task Select_many_over_skip_navigation_where_non_equality_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_non_equality_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[OneId] AND [u].[Id] <> [t].[Id]"); + } + + public override async Task Contains_on_skip_collection_navigation_unidirectional(bool async) + { + await base.Contains_on_skip_collection_navigation_unidirectional(async); + + AssertSql( + @"@__entity_equality_two_0_Id='1' (Nullable = true) + +SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND [u1].[Id] = @__entity_equality_two_0_Id)"); + } + + public override async Task GetType_in_hierarchy_in_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_base_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], NULL AS [Number], NULL AS [IsGreen], N'UnidirectionalEntityRoot' AS [Discriminator] +FROM [UnidirectionalRoots] AS [u]"); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] +FROM [UnidirectionalBranches] AS [u]"); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_unidirectional(async); +AssertSql( + @"SELECT [u].[Id], [u].[Name], [u].[Number], [u].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] +FROM [UnidirectionalLeaves] AS [u]"); + } + + public override async Task GetType_in_hierarchy_in_querying_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_querying_base_type_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator] +FROM ( + SELECT [u].[Id], [u].[Name], [u].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u] + UNION ALL + SELECT [u0].[Id], [u0].[Name], [u0].[Number], [u0].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u0] +) AS [t] +WHERE 0 = 1"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyQuerySqlServerTest.cs index f427f40cb30..944ab5aca02 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCManyToManyQuerySqlServerTest.cs @@ -15,7 +15,7 @@ public TPCManyToManyQuerySqlServerTest(TPCManyToManyQuerySqlServerFixture fixtur protected override bool CanExecuteQueryString => true; - [ConditionalFact(Skip = "TODOU: Needs #27493")] + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); @@ -1053,8 +1053,8 @@ public override async Task Include_skip_navigation_split(bool async) @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", - // - @"SELECT [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[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].[IsGreen], [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] @@ -1081,8 +1081,8 @@ public override async Task Include_skip_navigation_then_reference_split(bool asy @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityTwos] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id] FROM [EntityTwos] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [j].[JoinOneToTwoExtraId], [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId] @@ -1101,8 +1101,8 @@ public override async Task Include_skip_navigation_then_include_skip_navigation_ @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", - // - @"SELECT [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [e].[Key1], [e].[Key2], [e].[Key3] + // + @"SELECT [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [e].[Key1], [e].[Key2], [e].[Key3] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( SELECT [j].[LeafId], [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3], [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen] @@ -1110,8 +1110,8 @@ FROM [JoinCompositeKeyToLeaf] AS [j] INNER JOIN [Leaves] AS [l] ON [j].[LeafId] = [l].[Id] ) AS [t] ON [e].[Key1] = [t].[CompositeId1] AND [e].[Key2] = [t].[CompositeId2] AND [e].[Key3] = [t].[CompositeId3] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Id]", - // - @"SELECT [t0].[EntityBranchId], [t0].[EntityOneId], [t0].[Id], [t0].[Name], [e].[Key1], [e].[Key2], [e].[Key3], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Id] + // + @"SELECT [t0].[EntityBranchId], [t0].[EntityOneId], [t0].[Id], [t0].[Name], [e].[Key1], [e].[Key2], [e].[Key3], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Id] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( SELECT [j].[LeafId], [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3], [l].[Id] @@ -1134,8 +1134,8 @@ public override async Task Include_skip_navigation_then_include_reference_and_sk @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId] @@ -1144,8 +1144,8 @@ FROM [JoinOneToThreePayloadFull] AS [j] LEFT JOIN [EntityTwos] AS [e1] ON [e0].[Id] = [e1].[ReferenceInverseId] ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t].[Id0]", - // - @"SELECT [t0].[LeftId], [t0].[RightId], [t0].[Payload], [t0].[Id], [t0].[Name], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t].[Id0] + // + @"SELECT [t0].[LeftId], [t0].[RightId], [t0].[Payload], [t0].[Id], [t0].[Name], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t].[Id0] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id], [e1].[Id] AS [Id0] @@ -1170,8 +1170,8 @@ public override async Task Include_skip_navigation_and_reference_split(bool asyn FROM [EntityTwos] AS [e] LEFT JOIN [EntityThrees] AS [e0] ON [e].[Id] = [e0].[ReferenceInverseId] ORDER BY [e].[Id], [e0].[Id]", - // - @"SELECT [t].[OneSkipSharedId], [t].[TwoSkipSharedId], [t].[Id], [t].[Name], [e].[Id], [e0].[Id] + // + @"SELECT [t].[OneSkipSharedId], [t].[TwoSkipSharedId], [t].[Id], [t].[Name], [e].[Id], [e0].[Id] FROM [EntityTwos] AS [e] LEFT JOIN [EntityThrees] AS [e0] ON [e].[Id] = [e0].[ReferenceInverseId] INNER JOIN ( @@ -1190,8 +1190,8 @@ public override async Task Filtered_include_skip_navigation_where_split(bool asy @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name], [e].[Id] + // + @"SELECT [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name], [e].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name] @@ -1210,8 +1210,8 @@ public override async Task Filtered_include_skip_navigation_order_by_split(bool @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[ThreeId], [t].[TwoId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[ThreeId], [t].[TwoId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[ThreeId], [j].[TwoId], [e0].[Id], [e0].[CollectionInverseId], [e0].[ExtraId], [e0].[Name], [e0].[ReferenceInverseId] @@ -1229,8 +1229,8 @@ public override async Task Filtered_include_skip_navigation_order_by_skip_split( @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityTwos] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t0].[SelfSkipSharedLeftId], [t0].[SelfSkipSharedRightId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t0].[SelfSkipSharedLeftId], [t0].[SelfSkipSharedRightId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id] FROM [EntityTwos] AS [e] INNER JOIN ( SELECT [t].[SelfSkipSharedLeftId], [t].[SelfSkipSharedRightId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] @@ -1252,8 +1252,8 @@ public override async Task Filtered_include_skip_navigation_order_by_take_split( @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", - // - @"SELECT [t0].[TwoSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Key1], [e].[Key2], [e].[Key3] + // + @"SELECT [t0].[TwoSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Key1], [e].[Key2], [e].[Key3] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( SELECT [t].[TwoSkipSharedId], [t].[CompositeKeySkipSharedKey1], [t].[CompositeKeySkipSharedKey2], [t].[CompositeKeySkipSharedKey3], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] @@ -1275,8 +1275,8 @@ public override async Task Filtered_include_skip_navigation_order_by_skip_take_s @"SELECT [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] FROM [EntityCompositeKeys] AS [e] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3]", - // - @"SELECT [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Key1], [e].[Key2], [e].[Key3] + // + @"SELECT [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Key1], [e].[Key2], [e].[Key3] FROM [EntityCompositeKeys] AS [e] INNER JOIN ( SELECT [t].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[ThreeId], [t].[Id0], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId] @@ -1307,8 +1307,8 @@ UNION ALL FROM [Leaves] AS [l] ) AS [t] ORDER BY [t].[Id]", - // - @"SELECT [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t].[Id] + // + @"SELECT [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t].[Id] FROM ( SELECT [r].[Id] FROM [Roots] AS [r] @@ -1325,8 +1325,8 @@ FROM [EntityRootEntityThree] AS [e] INNER JOIN [EntityThrees] AS [e0] ON [e].[ThreeSkipSharedId] = [e0].[Id] ) AS [t0] ON [t].[Id] = [t0].[RootSkipSharedId] ORDER BY [t].[Id], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id]", - // - @"SELECT [t1].[OneId], [t1].[ThreeId], [t1].[Payload], [t1].[Id], [t1].[Name], [t].[Id], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id] + // + @"SELECT [t1].[OneId], [t1].[ThreeId], [t1].[Payload], [t1].[Id], [t1].[Name], [t].[Id], [t0].[RootSkipSharedId], [t0].[ThreeSkipSharedId], [t0].[Id] FROM ( SELECT [r].[Id] FROM [Roots] AS [r] @@ -1368,8 +1368,8 @@ UNION ALL FROM [Leaves] AS [l] ) AS [t] ORDER BY [t].[Id]", - // - @"SELECT [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[Name], [t].[Id] + // + @"SELECT [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[Name], [t].[Id] FROM ( SELECT [r].[Id] FROM [Roots] AS [r] @@ -1386,8 +1386,8 @@ FROM [EntityCompositeKeyEntityRoot] AS [e] INNER JOIN [EntityCompositeKeys] AS [e0] ON [e].[CompositeKeySkipSharedKey1] = [e0].[Key1] AND [e].[CompositeKeySkipSharedKey2] = [e0].[Key2] AND [e].[CompositeKeySkipSharedKey3] = [e0].[Key3] ) AS [t0] ON [t].[Id] = [t0].[RootSkipSharedId] ORDER BY [t].[Id], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Key1], [t0].[Key2], [t0].[Key3]", - // - @"SELECT [t1].[Id], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[ThreeId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [t].[Id], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Key1], [t0].[Key2], [t0].[Key3] + // + @"SELECT [t1].[Id], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[ThreeId], [t1].[Id0], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [t].[Id], [t0].[RootSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Key1], [t0].[Key2], [t0].[Key3] FROM ( SELECT [r].[Id] FROM [Roots] AS [r] @@ -1423,8 +1423,8 @@ public override async Task Filtered_include_skip_navigation_where_then_include_s @"SELECT [l].[Id], [l].[Name], [l].[Number], [l].[IsGreen] FROM [Leaves] AS [l] ORDER BY [l].[Id]", - // - @"SELECT [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Key1], [t].[Key2], [t].[Key3], [t].[Name], [l].[Id] + // + @"SELECT [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Key1], [t].[Key2], [t].[Key3], [t].[Name], [l].[Id] FROM [Leaves] AS [l] INNER JOIN ( SELECT [j].[LeafId], [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3], [e].[Key1], [e].[Key2], [e].[Key3], [e].[Name] @@ -1433,8 +1433,8 @@ FROM [JoinCompositeKeyToLeaf] AS [j] WHERE [e].[Key1] < 5 ) AS [t] ON [l].[Id] = [t].[LeafId] ORDER BY [l].[Id], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Key1], [t].[Key2], [t].[Key3]", - // - @"SELECT [t0].[TwoSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [l].[Id], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Key1], [t].[Key2], [t].[Key3] + // + @"SELECT [t0].[TwoSkipSharedId], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [l].[Id], [t].[LeafId], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[Key1], [t].[Key2], [t].[Key3] FROM [Leaves] AS [l] INNER JOIN ( SELECT [j].[LeafId], [j].[CompositeId1], [j].[CompositeId2], [j].[CompositeId3], [e].[Key1], [e].[Key2], [e].[Key3] @@ -1458,8 +1458,8 @@ public override async Task Filtered_include_skip_navigation_order_by_skip_take_t @"SELECT [e].[Id], [e].[Name] FROM [EntityOnes] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t0].[OneId], [t0].[TwoId], [t0].[JoinOneToTwoExtraId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t0].[OneId], [t0].[TwoId], [t0].[JoinOneToTwoExtraId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] @@ -1471,8 +1471,8 @@ FROM [JoinOneToTwo] AS [j] WHERE 1 < [t].[row] AND [t].[row] <= 3 ) AS [t0] ON [e].[Id] = [t0].[OneId] ORDER BY [e].[Id], [t0].[OneId], [t0].[Id], [t0].[TwoId]", - // - @"SELECT [t1].[ThreeId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t0].[OneId], [t0].[TwoId], [t0].[Id] + // + @"SELECT [t1].[ThreeId], [t1].[TwoId], [t1].[Id], [t1].[CollectionInverseId], [t1].[Name], [t1].[ReferenceInverseId], [e].[Id], [t0].[OneId], [t0].[TwoId], [t0].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [t].[OneId], [t].[TwoId], [t].[Id] @@ -1500,8 +1500,8 @@ public override async Task Filtered_include_skip_navigation_where_then_include_s @"SELECT [e].[Id], [e].[Name] FROM [EntityOnes] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [j].[JoinOneToTwoExtraId], [e0].[Id], [e0].[CollectionInverseId], [e0].[ExtraId], [e0].[Name], [e0].[ReferenceInverseId] @@ -1510,8 +1510,8 @@ FROM [JoinOneToTwo] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[OneId] ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id]", - // - @"SELECT [t0].[ThreeId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] + // + @"SELECT [t0].[ThreeId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [e0].[Id] @@ -1539,8 +1539,8 @@ public override async Task Filter_include_on_skip_navigation_combined_split(bool @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityTwos] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [e].[Id] FROM [EntityTwos] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [j].[JoinOneToTwoExtraId], [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId] @@ -1550,8 +1550,8 @@ FROM [JoinOneToTwo] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[TwoId] ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0]", - // - @"SELECT [e2].[Id], [e2].[CollectionInverseId], [e2].[ExtraId], [e2].[Name], [e2].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0] + // + @"SELECT [e2].[Id], [e2].[CollectionInverseId], [e2].[ExtraId], [e2].[Name], [e2].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0] FROM [EntityTwos] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[TwoId], [e0].[Id], [e1].[Id] AS [Id0] @@ -1572,8 +1572,8 @@ public override async Task Filter_include_on_skip_navigation_combined_with_filte @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name], [e].[Id] + // + @"SELECT [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name], [e].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name] @@ -1582,8 +1582,8 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] < 10 ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]", - // - @"SELECT [t0].[OneId], [t0].[TwoId], [t0].[JoinOneToTwoExtraId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + // + @"SELECT [t0].[OneId], [t0].[TwoId], [t0].[JoinOneToTwoExtraId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1601,8 +1601,8 @@ FROM [JoinOneToTwo] AS [j0] WHERE 1 < [t1].[row] AND [t1].[row] <= 3 ) AS [t0] ON [t].[Id] = [t0].[OneId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id], [t0].[OneId], [t0].[Id]", - // - @"SELECT [t0].[EntityBranchId], [t0].[EntityOneId], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + // + @"SELECT [t0].[EntityBranchId], [t0].[EntityOneId], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1633,8 +1633,8 @@ public override async Task Filtered_include_on_skip_navigation_then_filtered_inc @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId] FROM [EntityThrees] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name], [e].[Id] + // + @"SELECT [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name], [e].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name] @@ -1643,8 +1643,8 @@ FROM [JoinOneToThreePayloadFull] AS [j] WHERE [e0].[Id] > 15 ) AS [t] ON [e].[Id] = [t].[ThreeId] ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id]", - // - @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] + // + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[OneId], [t].[ThreeId], [t].[Id] FROM [EntityThrees] AS [e] INNER JOIN ( SELECT [j].[OneId], [j].[ThreeId], [e0].[Id] @@ -1668,8 +1668,8 @@ public override async Task Filtered_include_on_navigation_then_filtered_include_ @"SELECT [e].[Id], [e].[Name] FROM [EntityOnes] AS [e] ORDER BY [e].[Id]", - // - @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] + // + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [e].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[CollectionInverseId], [e0].[ExtraId], [e0].[Name], [e0].[ReferenceInverseId] @@ -1677,8 +1677,8 @@ FROM [EntityTwos] AS [e0] WHERE [e0].[Id] > 15 ) AS [t] ON [e].[Id] = [t].[CollectionInverseId] ORDER BY [e].[Id], [t].[Id]", - // - @"SELECT [t0].[ThreeId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[Id] + // + @"SELECT [t0].[ThreeId], [t0].[TwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [e].[Id], [t].[Id] FROM [EntityOnes] AS [e] INNER JOIN ( SELECT [e0].[Id], [e0].[CollectionInverseId] @@ -1827,7 +1827,8 @@ FROM [EntityCompositeKeyEntityTwo] AS [e0] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id]"); } - public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property( + bool async) { await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); @@ -1854,6 +1855,622 @@ WHERE [e1].[Id] < 10 ORDER BY [e].[Id], [t1].[Id], [t1].[OneId], [t1].[TwoId], [t1].[ThreeId], [t1].[TwoId0]"); } + public override async Task Skip_navigation_all_unidirectional(bool async) + { + await base.Skip_navigation_all_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE NOT EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND NOT ([u1].[Name] LIKE N'%B%'))"); + } + + public override async Task Skip_navigation_any_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_any_with_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + WHERE [u].[Id] = [u0].[UnidirectionalEntityOneId] AND ([u1].[Name] LIKE N'%B%'))"); + } + + public override async Task Skip_navigation_contains_unidirectional(bool async) + { + await base.Skip_navigation_contains_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND [u1].[Id] = 1)"); + } + + public override async Task Skip_navigation_count_without_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_without_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE ( + SELECT COUNT(*) + FROM [UnidirectionalJoinOneSelfPayload] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[LeftId] = [u1].[Id] + WHERE [u].[Id] = [u0].[RightId]) > 0"); + } + + public override async Task Skip_navigation_count_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_with_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +ORDER BY ( + SELECT COUNT(*) + FROM [UnidirectionalJoinOneToBranch] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u1].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u1] + UNION ALL + SELECT [u2].[Id], [u2].[Name], [u2].[Number], [u2].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u2] + ) AS [t] ON [u0].[UnidirectionalEntityBranchId] = [t].[Id] + WHERE [u].[Id] = [u0].[UnidirectionalEntityOneId] AND [t].[Name] IS NOT NULL AND ([t].[Name] LIKE N'L%')), [u].[Id]"); + } + + public override async Task Skip_navigation_select_subquery_average_unidirectional(bool async) + { + await base.Skip_navigation_select_subquery_average_unidirectional(async); + + AssertSql( + @"SELECT ( + SELECT AVG(CAST([u1].[Key1] AS float)) + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u0] + INNER JOIN [UnidirectionalEntityCompositeKeys] AS [u1] ON [u0].[CompositeId1] = [u1].[Key1] AND [u0].[CompositeId2] = [u1].[Key2] AND [u0].[CompositeId3] = [u1].[Key3] + WHERE [u].[Id] = [u0].[LeafId]) +FROM [UnidirectionalLeaves] AS [u]"); + } + + public override async Task Skip_navigation_order_by_reverse_first_or_default_unidirectional(bool async) + { + await base.Skip_navigation_order_by_reverse_first_or_default_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[ThreeId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[ThreeId], ROW_NUMBER() OVER(PARTITION BY [u0].[ThreeId] ORDER BY [u1].[Id] DESC) AS [row] + FROM [UnidirectionalJoinTwoToThree] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [u].[Id] = [t0].[ThreeId]"); + } + + public override async Task Skip_navigation_of_type_unidirectional(bool async) + { + await base.Skip_navigation_of_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[RootSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], NULL AS [Number], NULL AS [IsGreen], N'UnidirectionalEntityRoot' AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + UNION ALL + SELECT [u2].[Id], [u2].[Name], [u2].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u2] + UNION ALL + SELECT [u3].[Id], [u3].[Name], [u3].[Number], [u3].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u3] + ) AS [t] ON [u0].[RootSkipSharedId] = [t].[Id] + WHERE [t].[Discriminator] = N'UnidirectionalEntityLeaf' +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Join_with_skip_navigation_unidirectional(bool async) + { + await base.Join_with_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [u0].[Id], [u0].[CollectionInverseId], [u0].[ExtraId], [u0].[Name], [u0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +INNER JOIN [UnidirectionalEntityTwos] AS [u0] ON [u].[Id] = ( + SELECT TOP(1) [u2].[Id] + FROM [UnidirectionalEntityTwoUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[SelfSkipSharedRightId] = [u2].[Id] + WHERE [u0].[Id] = [u1].[UnidirectionalEntityTwoId] + ORDER BY [u2].[Id])"); + } + + public override async Task Left_join_with_skip_navigation_unidirectional(bool async) + { + await base.Left_join_with_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [u0].[Key1], [u0].[Key2], [u0].[Key3], [u0].[Name] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN [UnidirectionalEntityCompositeKeys] AS [u0] ON ( + SELECT TOP(1) [u2].[Id] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[TwoSkipSharedId] = [u2].[Id] + WHERE [u].[Key1] = [u1].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [u1].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [u1].[UnidirectionalEntityCompositeKeyKey3] + ORDER BY [u2].[Id]) = ( + SELECT TOP(1) [u4].[Id] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u3] + INNER JOIN [UnidirectionalEntityThrees] AS [u4] ON [u3].[ThreeId] = [u4].[Id] + WHERE [u0].[Key1] = [u3].[CompositeId1] AND [u0].[Key2] = [u3].[CompositeId2] AND [u0].[Key3] = [u3].[CompositeId3] + ORDER BY [u4].[Id]) +ORDER BY [u].[Key1], [u0].[Key1], [u].[Key2], [u0].[Key2]"); + } + + public override async Task Select_many_over_skip_navigation_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] +FROM ( + SELECT [u1].[Id] + FROM [UnidirectionalRoots] AS [u1] + UNION ALL + SELECT [u2].[Id] + FROM [UnidirectionalBranches] AS [u2] + UNION ALL + SELECT [u3].[Id] + FROM [UnidirectionalLeaves] AS [u3] +) AS [t] +INNER JOIN ( + SELECT [u0].[Id], [u0].[CollectionInverseId], [u0].[Name], [u0].[ReferenceInverseId], [u].[UnidirectionalEntityRootId] + FROM [UnidirectionalEntityRootUnidirectionalEntityThree] AS [u] + INNER JOIN [UnidirectionalEntityThrees] AS [u0] ON [u].[ThreeSkipSharedId] = [u0].[Id] +) AS [t0] ON [t].[Id] = [t0].[UnidirectionalEntityRootId]"); + } + + public override async Task Select_many_over_skip_navigation_where_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[OneId]"); + } + + public override async Task Select_many_over_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[UnidirectionalEntityOneId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[UnidirectionalEntityOneId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityOneId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[OneId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId], ROW_NUMBER() OVER(PARTITION BY [u0].[OneId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 2 < [t].[row] AND [t].[row] <= 5 +) AS [t0] ON [u].[Id] = [t0].[OneId]"); + } + + public override async Task Select_many_over_skip_navigation_cast_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_cast_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[UnidirectionalEntityOneId] + FROM [UnidirectionalJoinOneToBranch] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u1].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u1] + UNION ALL + SELECT [u2].[Id], [u2].[Name], [u2].[Number], [u2].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u2] + ) AS [t] ON [u0].[UnidirectionalEntityBranchId] = [t].[Id] +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Select_skip_navigation_unidirectional(bool async) + { + await base.Select_skip_navigation_unidirectional(async); +AssertSql( + @"SELECT [u].[Id], [t].[Id], [t].[Name], [t].[LeftId], [t].[RightId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u0].[LeftId], [u0].[RightId] + FROM [UnidirectionalJoinOneSelfPayload] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[LeftId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[RightId] +ORDER BY [u].[Id], [t].[LeftId], [t].[RightId]"); + } + + public override async Task Include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [u0].[RootSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3], [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], NULL AS [Number], NULL AS [IsGreen], N'UnidirectionalEntityRoot' AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + UNION ALL + SELECT [u2].[Id], [u2].[Name], [u2].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u2] + UNION ALL + SELECT [u3].[Id], [u3].[Name], [u3].[Number], [u3].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u3] + ) AS [t] ON [u0].[RootSkipSharedId] = [t].[Id] +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Include_skip_navigation_then_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_then_reference_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [t].[OneId], [t].[TwoId], [t].[UnidirectionalJoinOneToTwoExtraId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN ( + SELECT [u0].[OneId], [u0].[TwoId], [u0].[UnidirectionalJoinOneToTwoExtraId], [u1].[Id], [u1].[Name], [u2].[Id] AS [Id0], [u2].[CollectionInverseId], [u2].[ExtraId], [u2].[Name] AS [Name0], [u2].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[Id] = [u2].[ReferenceInverseId] +) AS [t] ON [u].[Id] = [t].[TwoId] +ORDER BY [u].[Id], [t].[OneId], [t].[TwoId], [t].[Id]"); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[UnidirectionalEntityBranchId], [t0].[UnidirectionalEntityOneId], [t0].[Id0], [t0].[Name0] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [u0].[LeafId], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], [u1].[Id], [u1].[Name], [u1].[Number], [u1].[IsGreen], [t].[UnidirectionalEntityBranchId], [t].[UnidirectionalEntityOneId], [t].[Id] AS [Id0], [t].[Name] AS [Name0] + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u0] + INNER JOIN [UnidirectionalLeaves] AS [u1] ON [u0].[LeafId] = [u1].[Id] + LEFT JOIN ( + SELECT [u2].[UnidirectionalEntityBranchId], [u2].[UnidirectionalEntityOneId], [u3].[Id], [u3].[Name] + FROM [UnidirectionalJoinOneToBranch] AS [u2] + INNER JOIN [UnidirectionalEntityOnes] AS [u3] ON [u2].[UnidirectionalEntityOneId] = [u3].[Id] + ) AS [t] ON [u1].[Id] = [t].[UnidirectionalEntityBranchId] +) AS [t0] ON [u].[Key1] = [t0].[CompositeId1] AND [u].[Key2] = [t0].[CompositeId2] AND [u].[Key3] = [t0].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id], [t0].[UnidirectionalEntityBranchId], [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id], [t0].[Name], [t0].[Id0], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name0], [t0].[ReferenceInverseId], [t0].[LeftId], [t0].[RightId], [t0].[Payload0], [t0].[Id1], [t0].[Name1] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u0].[OneId], [u0].[ThreeId], [u0].[Payload], [u1].[Id], [u1].[Name], [u2].[Id] AS [Id0], [u2].[CollectionInverseId], [u2].[ExtraId], [u2].[Name] AS [Name0], [u2].[ReferenceInverseId], [t].[LeftId], [t].[RightId], [t].[Payload] AS [Payload0], [t].[Id] AS [Id1], [t].[Name] AS [Name1] + FROM [UnidirectionalJoinOneToThreePayloadFull] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[Id] = [u2].[ReferenceInverseId] + LEFT JOIN ( + SELECT [u3].[LeftId], [u3].[RightId], [u3].[Payload], [u4].[Id], [u4].[Name] + FROM [UnidirectionalJoinOneSelfPayload] AS [u3] + INNER JOIN [UnidirectionalEntityOnes] AS [u4] ON [u3].[RightId] = [u4].[Id] + ) AS [t] ON [u1].[Id] = [t].[LeftId] +) AS [t0] ON [u].[Id] = [t0].[ThreeId] +ORDER BY [u].[Id], [t0].[OneId], [t0].[ThreeId], [t0].[Id], [t0].[Id0], [t0].[LeftId], [t0].[RightId]"); + } + + public override async Task Include_skip_navigation_and_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_and_reference_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [u0].[Id], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityOneId], [t].[Id], [t].[Name], [u0].[CollectionInverseId], [u0].[Name], [u0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN [UnidirectionalEntityThrees] AS [u0] ON [u].[Id] = [u0].[ReferenceInverseId] +LEFT JOIN ( + SELECT [u1].[TwoSkipSharedId], [u1].[UnidirectionalEntityOneId], [u2].[Id], [u2].[Name] + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityOnes] AS [u2] ON [u1].[UnidirectionalEntityOneId] = [u2].[Id] +) AS [t] ON [u].[Id] = [t].[TwoSkipSharedId] +ORDER BY [u].[Id], [u0].[Id], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityOneId]"); + } + + public override async Task Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id], [t0].[Name], [t0].[OneId0], [t0].[ThreeId0], [t0].[Payload0], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name0], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u0].[OneId], [u0].[ThreeId], [u0].[Payload], [u1].[Id], [u1].[Name], [t].[OneId] AS [OneId0], [t].[ThreeId] AS [ThreeId0], [t].[Payload] AS [Payload0], [t].[Id] AS [Id0], [t].[CollectionInverseId], [t].[Name] AS [Name0], [t].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN ( + SELECT [u2].[OneId], [u2].[ThreeId], [u2].[Payload], [u3].[Id], [u3].[CollectionInverseId], [u3].[Name], [u3].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u2] + INNER JOIN [UnidirectionalEntityThrees] AS [u3] ON [u2].[ThreeId] = [u3].[Id] + ) AS [t] ON [u1].[Id] = [t].[OneId] +) AS [t0] ON [u].[Id] = [t0].[ThreeId] +ORDER BY [u].[Id], [t0].[OneId], [t0].[ThreeId], [t0].[Id], [t0].[OneId0], [t0].[ThreeId0]"); + } + + public override async Task Filtered_include_skip_navigation_where_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_unidirectional(async); + + AssertSql( + @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId], [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name] +FROM [EntityThrees] AS [e] +LEFT JOIN ( + SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name] + FROM [JoinOneToThreePayloadFullShared] AS [j] + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e0].[Id] < 10 +) AS [t] ON [e].[Id] = [t].[ThreeId] +ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t].[ThreeId], [t].[TwoId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u0].[ThreeId], [u0].[TwoId], [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId] + FROM [UnidirectionalJoinTwoToThree] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[ThreeId] +ORDER BY [u].[Id], [t].[Id], [t].[ThreeId]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [t0].[SelfSkipSharedRightId], [t0].[UnidirectionalEntityTwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN ( + SELECT [t].[SelfSkipSharedRightId], [t].[UnidirectionalEntityTwoId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] + FROM ( + SELECT [u0].[SelfSkipSharedRightId], [u0].[UnidirectionalEntityTwoId], [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityTwoId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityTwoUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[SelfSkipSharedRightId] = [u1].[Id] + ) AS [t] + WHERE 2 < [t].[row] +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityTwoId] +ORDER BY [u].[Id], [t0].[UnidirectionalEntityTwoId], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[TwoSkipSharedId], [t].[UnidirectionalEntityCompositeKeyKey1], [t].[UnidirectionalEntityCompositeKeyKey2], [t].[UnidirectionalEntityCompositeKeyKey3], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] + FROM ( + SELECT [u0].[TwoSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3], [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[ThreeId], [t].[Id0], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId] + FROM ( + SELECT [u0].[Id], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], [u0].[ThreeId], [u1].[Id] AS [Id0], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 1 < [t].[row] AND [t].[row] <= 3 +) AS [t0] ON [u].[Key1] = [t0].[CompositeId1] AND [u].[Key2] = [t0].[CompositeId2] AND [u].[Key3] = [t0].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0]"); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u].[Number], [u].[IsGreen], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[Name], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name0], [t0].[ReferenceInverseId] +FROM [UnidirectionalLeaves] AS [u] +LEFT JOIN ( + SELECT [u0].[LeafId], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], [u1].[Key1], [u1].[Key2], [u1].[Key3], [u1].[Name], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityCompositeKeyKey1], [t].[UnidirectionalEntityCompositeKeyKey2], [t].[UnidirectionalEntityCompositeKeyKey3], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name] AS [Name0], [t].[ReferenceInverseId] + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u0] + INNER JOIN [UnidirectionalEntityCompositeKeys] AS [u1] ON [u0].[CompositeId1] = [u1].[Key1] AND [u0].[CompositeId2] = [u1].[Key2] AND [u0].[CompositeId3] = [u1].[Key3] + LEFT JOIN ( + SELECT [u2].[TwoSkipSharedId], [u2].[UnidirectionalEntityCompositeKeyKey1], [u2].[UnidirectionalEntityCompositeKeyKey2], [u2].[UnidirectionalEntityCompositeKeyKey3], [u3].[Id], [u3].[CollectionInverseId], [u3].[ExtraId], [u3].[Name], [u3].[ReferenceInverseId] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u2] + INNER JOIN [UnidirectionalEntityTwos] AS [u3] ON [u2].[TwoSkipSharedId] = [u3].[Id] + ) AS [t] ON [u1].[Key1] = [t].[UnidirectionalEntityCompositeKeyKey1] AND [u1].[Key2] = [t].[UnidirectionalEntityCompositeKeyKey2] AND [u1].[Key3] = [t].[UnidirectionalEntityCompositeKeyKey3] + WHERE [u1].[Key1] < 5 +) AS [t0] ON [u].[Id] = [t0].[LeafId] +ORDER BY [u].[Id], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Filter_include_on_skip_navigation_combined_unidirectional(bool async) + { + await base.Filter_include_on_skip_navigation_combined_unidirectional(async); + + AssertSql( + @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId], [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [t].[Id1], [t].[CollectionInverseId0], [t].[ExtraId0], [t].[Name1], [t].[ReferenceInverseId0] +FROM [EntityTwos] AS [e] +LEFT JOIN ( + SELECT [j].[OneId], [j].[TwoId], [j].[JoinOneToTwoExtraId], [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId], [e2].[Id] AS [Id1], [e2].[CollectionInverseId] AS [CollectionInverseId0], [e2].[ExtraId] AS [ExtraId0], [e2].[Name] AS [Name1], [e2].[ReferenceInverseId] AS [ReferenceInverseId0] + FROM [JoinOneToTwo] AS [j] + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + LEFT JOIN [EntityTwos] AS [e1] ON [e0].[Id] = [e1].[ReferenceInverseId] + LEFT JOIN [EntityTwos] AS [e2] ON [e0].[Id] = [e2].[CollectionInverseId] + WHERE [e0].[Id] < 10 +) AS [t] ON [e].[Id] = [t].[TwoId] +ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0]"); + } + + public override async Task Throws_when_different_filtered_include_unidirectional(bool async) + { + await base.Throws_when_different_filtered_include_unidirectional(async); + + AssertSql(); + } + + public override async Task Includes_accessed_via_different_path_are_merged_unidirectional(bool async) + { + await base.Includes_accessed_via_different_path_are_merged_unidirectional(async); + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id], [t0].[Name], [t0].[OneId0], [t0].[ThreeId0], [t0].[Payload0], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name0], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u0].[OneId], [u0].[ThreeId], [u0].[Payload], [u1].[Id], [u1].[Name], [t].[OneId] AS [OneId0], [t].[ThreeId] AS [ThreeId0], [t].[Payload] AS [Payload0], [t].[Id] AS [Id0], [t].[CollectionInverseId], [t].[Name] AS [Name0], [t].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN ( + SELECT [u2].[OneId], [u2].[ThreeId], [u2].[Payload], [u3].[Id], [u3].[CollectionInverseId], [u3].[Name], [u3].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u2] + INNER JOIN [UnidirectionalEntityThrees] AS [u3] ON [u2].[ThreeId] = [u3].[Id] + ) AS [t] ON [u1].[Id] = [t].[OneId] +) AS [t0] ON [u].[Id] = [t0].[ThreeId] +ORDER BY [u].[Id], [t0].[OneId], [t0].[ThreeId], [t0].[Id], [t0].[OneId0], [t0].[ThreeId0]"); + } + + public override async Task Select_many_over_skip_navigation_where_non_equality_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_non_equality_unidirectional(async); + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[OneId] AND [u].[Id] <> [t].[Id]"); + } + + public override async Task Contains_on_skip_collection_navigation_unidirectional(bool async) + { + await base.Contains_on_skip_collection_navigation_unidirectional(async); + + AssertSql( + @"@__entity_equality_two_0_Id='1' (Nullable = true) + +SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND [u1].[Id] = @__entity_equality_two_0_Id)"); + } + + public override async Task GetType_in_hierarchy_in_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_base_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], NULL AS [Number], NULL AS [IsGreen], N'UnidirectionalEntityRoot' AS [Discriminator] +FROM [UnidirectionalRoots] AS [u]"); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type_unidirectional(async); +AssertSql( + @"SELECT [u].[Id], [u].[Name], [u].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] +FROM [UnidirectionalBranches] AS [u]"); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u].[Number], [u].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] +FROM [UnidirectionalLeaves] AS [u]"); + } + + public override async Task GetType_in_hierarchy_in_querying_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_querying_base_type_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator] +FROM ( + SELECT [u].[Id], [u].[Name], [u].[Number], NULL AS [IsGreen], N'UnidirectionalEntityBranch' AS [Discriminator] + FROM [UnidirectionalBranches] AS [u] + UNION ALL + SELECT [u0].[Id], [u0].[Name], [u0].[Number], [u0].[IsGreen], N'UnidirectionalEntityLeaf' AS [Discriminator] + FROM [UnidirectionalLeaves] AS [u0] +) AS [t] +WHERE 0 = 1"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs index eb47d14ccb1..8d324a05fde 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyNoTrackingQuerySqlServerTest.cs @@ -16,7 +16,7 @@ public TPTManyToManyNoTrackingQuerySqlServerTest(TPTManyToManyQuerySqlServerFixt protected override bool CanExecuteQueryString => true; - [ConditionalFact(Skip = "TODOU: Needs #27493")] + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); @@ -1787,7 +1787,8 @@ FROM [EntityCompositeKeyEntityTwo] AS [e0] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id]"); } - public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property( + bool async) { await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); @@ -1814,6 +1815,614 @@ WHERE [e1].[Id] < 10 ORDER BY [e].[Id], [t1].[Id], [t1].[OneId], [t1].[TwoId], [t1].[ThreeId], [t1].[TwoId0]"); } + public override async Task Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(async); + + AssertSql(); + } + + public override async Task Skip_navigation_all_unidirectional(bool async) + { + await base.Skip_navigation_all_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE NOT EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND NOT ([u1].[Name] LIKE N'%B%'))"); + } + + public override async Task Skip_navigation_any_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_any_with_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + WHERE [u].[Id] = [u0].[UnidirectionalEntityOneId] AND ([u1].[Name] LIKE N'%B%'))"); + } + + public override async Task Skip_navigation_contains_unidirectional(bool async) + { + await base.Skip_navigation_contains_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND [u1].[Id] = 1)"); + } + + public override async Task Skip_navigation_count_without_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_without_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE ( + SELECT COUNT(*) + FROM [UnidirectionalJoinOneSelfPayload] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[LeftId] = [u1].[Id] + WHERE [u].[Id] = [u0].[RightId]) > 0"); + } + + public override async Task Skip_navigation_count_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_with_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +ORDER BY ( + SELECT COUNT(*) + FROM [UnidirectionalJoinOneToBranch] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen], CASE + WHEN [u3].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + END AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + INNER JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + LEFT JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[UnidirectionalEntityBranchId] = [t].[Id] + WHERE [u].[Id] = [u0].[UnidirectionalEntityOneId] AND [t].[Name] IS NOT NULL AND ([t].[Name] LIKE N'L%')), [u].[Id]"); + } + + public override async Task Skip_navigation_select_subquery_average_unidirectional(bool async) + { + await base.Skip_navigation_select_subquery_average_unidirectional(async); + + AssertSql( + @"SELECT ( + SELECT AVG(CAST([u3].[Key1] AS float)) + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u2] + INNER JOIN [UnidirectionalEntityCompositeKeys] AS [u3] ON [u2].[CompositeId1] = [u3].[Key1] AND [u2].[CompositeId2] = [u3].[Key2] AND [u2].[CompositeId3] = [u3].[Key3] + WHERE [u].[Id] = [u2].[LeafId]) +FROM [UnidirectionalRoots] AS [u] +INNER JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +INNER JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id]"); + } + + public override async Task Skip_navigation_order_by_reverse_first_or_default_unidirectional(bool async) + { + await base.Skip_navigation_order_by_reverse_first_or_default_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[ThreeId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[ThreeId], ROW_NUMBER() OVER(PARTITION BY [u0].[ThreeId] ORDER BY [u1].[Id] DESC) AS [row] + FROM [UnidirectionalJoinTwoToThree] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [u].[Id] = [t0].[ThreeId]"); + } + + public override async Task Skip_navigation_of_type_unidirectional(bool async) + { + await base.Skip_navigation_of_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[RootSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen], CASE + WHEN [u3].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u2].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' + END AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + LEFT JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + LEFT JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[RootSkipSharedId] = [t].[Id] + WHERE [t].[Discriminator] = N'UnidirectionalEntityLeaf' +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Join_with_skip_navigation_unidirectional(bool async) + { + await base.Join_with_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [u0].[Id], [u0].[CollectionInverseId], [u0].[ExtraId], [u0].[Name], [u0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +INNER JOIN [UnidirectionalEntityTwos] AS [u0] ON [u].[Id] = ( + SELECT TOP(1) [u2].[Id] + FROM [UnidirectionalEntityTwoUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[SelfSkipSharedRightId] = [u2].[Id] + WHERE [u0].[Id] = [u1].[UnidirectionalEntityTwoId] + ORDER BY [u2].[Id])"); + } + + public override async Task Left_join_with_skip_navigation_unidirectional(bool async) + { + await base.Left_join_with_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [u0].[Key1], [u0].[Key2], [u0].[Key3], [u0].[Name] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN [UnidirectionalEntityCompositeKeys] AS [u0] ON ( + SELECT TOP(1) [u2].[Id] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[TwoSkipSharedId] = [u2].[Id] + WHERE [u].[Key1] = [u1].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [u1].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [u1].[UnidirectionalEntityCompositeKeyKey3] + ORDER BY [u2].[Id]) = ( + SELECT TOP(1) [u4].[Id] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u3] + INNER JOIN [UnidirectionalEntityThrees] AS [u4] ON [u3].[ThreeId] = [u4].[Id] + WHERE [u0].[Key1] = [u3].[CompositeId1] AND [u0].[Key2] = [u3].[CompositeId2] AND [u0].[Key3] = [u3].[CompositeId3] + ORDER BY [u4].[Id]) +ORDER BY [u].[Key1], [u0].[Key1], [u].[Key2], [u0].[Key2]"); + } + + public override async Task Select_many_over_skip_navigation_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalRoots] AS [u] +INNER JOIN ( + SELECT [u3].[Id], [u3].[CollectionInverseId], [u3].[Name], [u3].[ReferenceInverseId], [u2].[UnidirectionalEntityRootId] + FROM [UnidirectionalEntityRootUnidirectionalEntityThree] AS [u2] + INNER JOIN [UnidirectionalEntityThrees] AS [u3] ON [u2].[ThreeSkipSharedId] = [u3].[Id] +) AS [t] ON [u].[Id] = [t].[UnidirectionalEntityRootId]"); + } + + public override async Task Select_many_over_skip_navigation_where_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[OneId]"); + } + + public override async Task Select_many_over_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[UnidirectionalEntityOneId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[UnidirectionalEntityOneId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityOneId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[OneId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId], ROW_NUMBER() OVER(PARTITION BY [u0].[OneId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 2 < [t].[row] AND [t].[row] <= 5 +) AS [t0] ON [u].[Id] = [t0].[OneId]"); + } + + public override async Task Select_many_over_skip_navigation_cast_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_cast_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[UnidirectionalEntityOneId] + FROM [UnidirectionalJoinOneToBranch] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen], CASE + WHEN [u3].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + END AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + INNER JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + LEFT JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[UnidirectionalEntityBranchId] = [t].[Id] +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Select_skip_navigation_unidirectional(bool async) + { + await base.Select_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [t].[Id], [t].[Name], [t].[LeftId], [t].[RightId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u0].[LeftId], [u0].[RightId] + FROM [UnidirectionalJoinOneSelfPayload] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[LeftId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[RightId] +ORDER BY [u].[Id], [t].[LeftId], [t].[RightId]"); + } + + public override async Task Include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[RootSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen], CASE + WHEN [u3].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u2].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' + END AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + LEFT JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + LEFT JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[RootSkipSharedId] = [t].[Id] +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Include_skip_navigation_then_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_then_reference_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [t].[OneId], [t].[TwoId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Id] AS [Id0], [u2].[CollectionInverseId], [u2].[ExtraId], [u2].[Name] AS [Name0], [u2].[ReferenceInverseId], [u0].[OneId], [u0].[TwoId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[Id] = [u2].[ReferenceInverseId] +) AS [t] ON [u].[Id] = [t].[TwoId] +ORDER BY [u].[Id], [t].[OneId], [t].[TwoId], [t].[Id]"); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t1].[Id], [t1].[Name], [t1].[Number], [t1].[IsGreen], [t1].[LeafId], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id0], [t1].[Name0], [t1].[UnidirectionalEntityBranchId], [t1].[UnidirectionalEntityOneId] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [u0].[LeafId], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], [t0].[Id] AS [Id0], [t0].[Name] AS [Name0], [t0].[UnidirectionalEntityBranchId], [t0].[UnidirectionalEntityOneId] + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen] + FROM [UnidirectionalRoots] AS [u1] + INNER JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + INNER JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[LeafId] = [t].[Id] + LEFT JOIN ( + SELECT [u5].[Id], [u5].[Name], [u4].[UnidirectionalEntityBranchId], [u4].[UnidirectionalEntityOneId] + FROM [UnidirectionalJoinOneToBranch] AS [u4] + INNER JOIN [UnidirectionalEntityOnes] AS [u5] ON [u4].[UnidirectionalEntityOneId] = [u5].[Id] + ) AS [t0] ON [t].[Id] = [t0].[UnidirectionalEntityBranchId] +) AS [t1] ON [u].[Key1] = [t1].[CompositeId1] AND [u].[Key2] = [t1].[CompositeId2] AND [u].[Key3] = [t1].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t1].[LeafId], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id], [t1].[UnidirectionalEntityBranchId], [t1].[UnidirectionalEntityOneId]"); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t0].[Id], [t0].[Name], [t0].[Id0], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name0], [t0].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Id1], [t0].[Name1], [t0].[LeftId], [t0].[RightId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Id] AS [Id0], [u2].[CollectionInverseId], [u2].[ExtraId], [u2].[Name] AS [Name0], [u2].[ReferenceInverseId], [u0].[OneId], [u0].[ThreeId], [t].[Id] AS [Id1], [t].[Name] AS [Name1], [t].[LeftId], [t].[RightId] + FROM [UnidirectionalJoinOneToThreePayloadFull] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[Id] = [u2].[ReferenceInverseId] + LEFT JOIN ( + SELECT [u4].[Id], [u4].[Name], [u3].[LeftId], [u3].[RightId] + FROM [UnidirectionalJoinOneSelfPayload] AS [u3] + INNER JOIN [UnidirectionalEntityOnes] AS [u4] ON [u3].[RightId] = [u4].[Id] + ) AS [t] ON [u1].[Id] = [t].[LeftId] +) AS [t0] ON [u].[Id] = [t0].[ThreeId] +ORDER BY [u].[Id], [t0].[OneId], [t0].[ThreeId], [t0].[Id], [t0].[Id0], [t0].[LeftId], [t0].[RightId]"); + } + + public override async Task Include_skip_navigation_and_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_and_reference_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [u0].[Id], [t].[Id], [t].[Name], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityOneId], [u0].[CollectionInverseId], [u0].[Name], [u0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN [UnidirectionalEntityThrees] AS [u0] ON [u].[Id] = [u0].[ReferenceInverseId] +LEFT JOIN ( + SELECT [u2].[Id], [u2].[Name], [u1].[TwoSkipSharedId], [u1].[UnidirectionalEntityOneId] + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityOnes] AS [u2] ON [u1].[UnidirectionalEntityOneId] = [u2].[Id] +) AS [t] ON [u].[Id] = [t].[TwoSkipSharedId] +ORDER BY [u].[Id], [u0].[Id], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityOneId]"); + } + + public override async Task Filtered_include_skip_navigation_where_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_unidirectional(async); + + AssertSql( + @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId], [t].[Id], [t].[Name], [t].[OneId], [t].[ThreeId] +FROM [EntityThrees] AS [e] +LEFT JOIN ( + SELECT [e0].[Id], [e0].[Name], [j].[OneId], [j].[ThreeId] + FROM [JoinOneToThreePayloadFullShared] AS [j] + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e0].[Id] < 10 +) AS [t] ON [e].[Id] = [t].[ThreeId] +ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_unidirectional(async); +AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[ThreeId], [t].[TwoId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[ThreeId], [u0].[TwoId] + FROM [UnidirectionalJoinTwoToThree] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[ThreeId] +ORDER BY [u].[Id], [t].[Id], [t].[ThreeId]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[SelfSkipSharedRightId], [t0].[UnidirectionalEntityTwoId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[SelfSkipSharedRightId], [t].[UnidirectionalEntityTwoId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[SelfSkipSharedRightId], [u0].[UnidirectionalEntityTwoId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityTwoId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityTwoUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[SelfSkipSharedRightId] = [u1].[Id] + ) AS [t] + WHERE 2 < [t].[row] +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityTwoId] +ORDER BY [u].[Id], [t0].[UnidirectionalEntityTwoId], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityCompositeKeyKey1], [t].[UnidirectionalEntityCompositeKeyKey2], [t].[UnidirectionalEntityCompositeKeyKey3] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[TwoSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_unidirectional(async); +AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId], [t0].[Id0] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[Id0], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[Id] AS [Id0], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], ROW_NUMBER() OVER(PARTITION BY [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 1 < [t].[row] AND [t].[row] <= 3 +) AS [t0] ON [u].[Key1] = [t0].[CompositeId1] AND [u].[Key2] = [t0].[CompositeId2] AND [u].[Key3] = [t0].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[Name], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name0], [t0].[ReferenceInverseId], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalRoots] AS [u] +INNER JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +INNER JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +LEFT JOIN ( + SELECT [u3].[Key1], [u3].[Key2], [u3].[Key3], [u3].[Name], [u2].[LeafId], [u2].[CompositeId1], [u2].[CompositeId2], [u2].[CompositeId3], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name] AS [Name0], [t].[ReferenceInverseId], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityCompositeKeyKey1], [t].[UnidirectionalEntityCompositeKeyKey2], [t].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u2] + INNER JOIN [UnidirectionalEntityCompositeKeys] AS [u3] ON [u2].[CompositeId1] = [u3].[Key1] AND [u2].[CompositeId2] = [u3].[Key2] AND [u2].[CompositeId3] = [u3].[Key3] + LEFT JOIN ( + SELECT [u5].[Id], [u5].[CollectionInverseId], [u5].[ExtraId], [u5].[Name], [u5].[ReferenceInverseId], [u4].[TwoSkipSharedId], [u4].[UnidirectionalEntityCompositeKeyKey1], [u4].[UnidirectionalEntityCompositeKeyKey2], [u4].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u4] + INNER JOIN [UnidirectionalEntityTwos] AS [u5] ON [u4].[TwoSkipSharedId] = [u5].[Id] + ) AS [t] ON [u3].[Key1] = [t].[UnidirectionalEntityCompositeKeyKey1] AND [u3].[Key2] = [t].[UnidirectionalEntityCompositeKeyKey2] AND [u3].[Key3] = [t].[UnidirectionalEntityCompositeKeyKey3] + WHERE [u3].[Key1] < 5 +) AS [t0] ON [u].[Id] = [t0].[LeafId] +ORDER BY [u].[Id], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Filter_include_on_skip_navigation_combined_unidirectional(bool async) + { + await base.Filter_include_on_skip_navigation_combined_unidirectional(async); + + AssertSql( + @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [t].[OneId], [t].[TwoId], [t].[Id1], [t].[CollectionInverseId0], [t].[ExtraId0], [t].[Name1], [t].[ReferenceInverseId0] +FROM [EntityTwos] AS [e] +LEFT JOIN ( + SELECT [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId], [j].[OneId], [j].[TwoId], [e2].[Id] AS [Id1], [e2].[CollectionInverseId] AS [CollectionInverseId0], [e2].[ExtraId] AS [ExtraId0], [e2].[Name] AS [Name1], [e2].[ReferenceInverseId] AS [ReferenceInverseId0] + FROM [JoinOneToTwo] AS [j] + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + LEFT JOIN [EntityTwos] AS [e1] ON [e0].[Id] = [e1].[ReferenceInverseId] + LEFT JOIN [EntityTwos] AS [e2] ON [e0].[Id] = [e2].[CollectionInverseId] + WHERE [e0].[Id] < 10 +) AS [t] ON [e].[Id] = [t].[TwoId] +ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0]"); + } + + public override async Task Throws_when_different_filtered_include_unidirectional(bool async) + { + await base.Throws_when_different_filtered_include_unidirectional(async); + + AssertSql(); + } + + public override async Task Includes_accessed_via_different_path_are_merged_unidirectional(bool async) + { + await base.Includes_accessed_via_different_path_are_merged_unidirectional(async); + + AssertSql(); + } + + public override async Task Select_many_over_skip_navigation_where_non_equality_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_non_equality_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[OneId] AND [u].[Id] <> [t].[Id]"); + } + + public override async Task Contains_on_skip_collection_navigation_unidirectional(bool async) + { + await base.Contains_on_skip_collection_navigation_unidirectional(async); + + AssertSql( + @"@__entity_equality_two_0_Id='1' (Nullable = true) + +SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND [u1].[Id] = @__entity_equality_two_0_Id)"); + } + + public override async Task GetType_in_hierarchy_in_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_base_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], CASE + WHEN [u1].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u0].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' +END AS [Discriminator] +FROM [UnidirectionalRoots] AS [u] +LEFT JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +LEFT JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +WHERE [u1].[Id] IS NULL AND [u0].[Id] IS NULL"); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], CASE + WHEN [u1].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u0].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' +END AS [Discriminator] +FROM [UnidirectionalRoots] AS [u] +LEFT JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +LEFT JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +WHERE [u1].[Id] IS NULL AND [u0].[Id] IS NOT NULL"); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], CASE + WHEN [u1].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u0].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' +END AS [Discriminator] +FROM [UnidirectionalRoots] AS [u] +LEFT JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +LEFT JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +WHERE [u1].[Id] IS NOT NULL"); + } + + public override async Task GetType_in_hierarchy_in_querying_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_querying_base_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], CASE + WHEN [u1].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' +END AS [Discriminator] +FROM [UnidirectionalRoots] AS [u] +INNER JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +LEFT JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +WHERE 0 = 1"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs index ef2075300fa..8ec757fd30f 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTManyToManyQuerySqlServerTest.cs @@ -15,7 +15,7 @@ public TPTManyToManyQuerySqlServerTest(TPTManyToManyQuerySqlServerFixture fixtur protected override bool CanExecuteQueryString => true; - [ConditionalFact(Skip = "TODOU: Needs #27493")] + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); @@ -1713,6 +1713,7 @@ FROM [JoinOneToTwo] AS [j] INNER JOIN [EntityTwos] AS [e0] ON [j].[TwoId] = [e0].[Id] WHERE [e].[Id] = [j].[OneId] AND [e0].[Id] = @__entity_equality_two_0_Id)"); } + public override async Task GetType_in_hierarchy_in_base_type(bool async) { await base.GetType_in_hierarchy_in_base_type(async); @@ -1791,7 +1792,8 @@ FROM [EntityCompositeKeyEntityTwo] AS [e0] ORDER BY [e].[Key1], [e].[Key2], [e].[Key3], [t0].[CompositeKeySkipSharedKey1], [t0].[CompositeKeySkipSharedKey2], [t0].[CompositeKeySkipSharedKey3], [t0].[Id]"); } - public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + public override async Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property( + bool async) { await base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); @@ -1818,6 +1820,628 @@ WHERE [e1].[Id] < 10 ORDER BY [e].[Id], [t1].[Id], [t1].[OneId], [t1].[TwoId], [t1].[ThreeId], [t1].[TwoId0]"); } + public override async Task Skip_navigation_all_unidirectional(bool async) + { + await base.Skip_navigation_all_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE NOT EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND NOT ([u1].[Name] LIKE N'%B%'))"); + } + + public override async Task Skip_navigation_any_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_any_with_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + WHERE [u].[Id] = [u0].[UnidirectionalEntityOneId] AND ([u1].[Name] LIKE N'%B%'))"); + } + + public override async Task Skip_navigation_contains_unidirectional(bool async) + { + await base.Skip_navigation_contains_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND [u1].[Id] = 1)"); + } + + public override async Task Skip_navigation_count_without_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_without_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE ( + SELECT COUNT(*) + FROM [UnidirectionalJoinOneSelfPayload] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[LeftId] = [u1].[Id] + WHERE [u].[Id] = [u0].[RightId]) > 0"); + } + + public override async Task Skip_navigation_count_with_predicate_unidirectional(bool async) + { + await base.Skip_navigation_count_with_predicate_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +ORDER BY ( + SELECT COUNT(*) + FROM [UnidirectionalJoinOneToBranch] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen], CASE + WHEN [u3].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + END AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + INNER JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + LEFT JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[UnidirectionalEntityBranchId] = [t].[Id] + WHERE [u].[Id] = [u0].[UnidirectionalEntityOneId] AND [t].[Name] IS NOT NULL AND ([t].[Name] LIKE N'L%')), [u].[Id]"); + } + + public override async Task Skip_navigation_select_subquery_average_unidirectional(bool async) + { + await base.Skip_navigation_select_subquery_average_unidirectional(async); + + AssertSql( + @"SELECT ( + SELECT AVG(CAST([u3].[Key1] AS float)) + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u2] + INNER JOIN [UnidirectionalEntityCompositeKeys] AS [u3] ON [u2].[CompositeId1] = [u3].[Key1] AND [u2].[CompositeId2] = [u3].[Key2] AND [u2].[CompositeId3] = [u3].[Key3] + WHERE [u].[Id] = [u2].[LeafId]) +FROM [UnidirectionalRoots] AS [u] +INNER JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +INNER JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id]"); + } + + public override async Task Skip_navigation_order_by_reverse_first_or_default_unidirectional(bool async) + { + await base.Skip_navigation_order_by_reverse_first_or_default_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[ThreeId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[ThreeId], ROW_NUMBER() OVER(PARTITION BY [u0].[ThreeId] ORDER BY [u1].[Id] DESC) AS [row] + FROM [UnidirectionalJoinTwoToThree] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [u].[Id] = [t0].[ThreeId]"); + } + + public override async Task Skip_navigation_of_type_unidirectional(bool async) + { + await base.Skip_navigation_of_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[RootSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen], CASE + WHEN [u3].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u2].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' + END AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + LEFT JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + LEFT JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[RootSkipSharedId] = [t].[Id] + WHERE [t].[Discriminator] = N'UnidirectionalEntityLeaf' +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Join_with_skip_navigation_unidirectional(bool async) + { + await base.Join_with_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [u0].[Id], [u0].[CollectionInverseId], [u0].[ExtraId], [u0].[Name], [u0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +INNER JOIN [UnidirectionalEntityTwos] AS [u0] ON [u].[Id] = ( + SELECT TOP(1) [u2].[Id] + FROM [UnidirectionalEntityTwoUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[SelfSkipSharedRightId] = [u2].[Id] + WHERE [u0].[Id] = [u1].[UnidirectionalEntityTwoId] + ORDER BY [u2].[Id])"); + } + + public override async Task Left_join_with_skip_navigation_unidirectional(bool async) + { + await base.Left_join_with_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [u0].[Key1], [u0].[Key2], [u0].[Key3], [u0].[Name] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN [UnidirectionalEntityCompositeKeys] AS [u0] ON ( + SELECT TOP(1) [u2].[Id] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[TwoSkipSharedId] = [u2].[Id] + WHERE [u].[Key1] = [u1].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [u1].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [u1].[UnidirectionalEntityCompositeKeyKey3] + ORDER BY [u2].[Id]) = ( + SELECT TOP(1) [u4].[Id] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u3] + INNER JOIN [UnidirectionalEntityThrees] AS [u4] ON [u3].[ThreeId] = [u4].[Id] + WHERE [u0].[Key1] = [u3].[CompositeId1] AND [u0].[Key2] = [u3].[CompositeId2] AND [u0].[Key3] = [u3].[CompositeId3] + ORDER BY [u4].[Id]) +ORDER BY [u].[Key1], [u0].[Key1], [u].[Key2], [u0].[Key2]"); + } + + public override async Task Select_many_over_skip_navigation_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalRoots] AS [u] +INNER JOIN ( + SELECT [u3].[Id], [u3].[CollectionInverseId], [u3].[Name], [u3].[ReferenceInverseId], [u2].[UnidirectionalEntityRootId] + FROM [UnidirectionalEntityRootUnidirectionalEntityThree] AS [u2] + INNER JOIN [UnidirectionalEntityThrees] AS [u3] ON [u2].[ThreeSkipSharedId] = [u3].[Id] +) AS [t] ON [u].[Id] = [t].[UnidirectionalEntityRootId]"); + } + + public override async Task Select_many_over_skip_navigation_where_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_unidirectional(async); + + AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[OneId]"); + } + + public override async Task Select_many_over_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId], [t].[UnidirectionalEntityOneId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[UnidirectionalEntityOneId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityOneId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Select_many_over_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId], [t].[OneId] + FROM ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId], ROW_NUMBER() OVER(PARTITION BY [u0].[OneId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 2 < [t].[row] AND [t].[row] <= 5 +) AS [t0] ON [u].[Id] = [t0].[OneId]"); + } + + public override async Task Select_many_over_skip_navigation_cast_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_cast_unidirectional(async); + + AssertSql( + @"SELECT [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator] +FROM [UnidirectionalEntityOnes] AS [u] +INNER JOIN ( + SELECT [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator], [u0].[UnidirectionalEntityOneId] + FROM [UnidirectionalJoinOneToBranch] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen], CASE + WHEN [u3].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + END AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + INNER JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + LEFT JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[UnidirectionalEntityBranchId] = [t].[Id] +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityOneId]"); + } + + public override async Task Select_skip_navigation_unidirectional(bool async) + { + await base.Select_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [t].[Id], [t].[Name], [t].[LeftId], [t].[RightId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[Name], [u0].[LeftId], [u0].[RightId] + FROM [UnidirectionalJoinOneSelfPayload] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[LeftId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[RightId] +ORDER BY [u].[Id], [t].[LeftId], [t].[RightId]"); + } + + public override async Task Include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id], [t0].[Name], [t0].[Number], [t0].[IsGreen], [t0].[Discriminator] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [u0].[RootSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3], [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t].[Discriminator] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityRoot] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen], CASE + WHEN [u3].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u2].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' + END AS [Discriminator] + FROM [UnidirectionalRoots] AS [u1] + LEFT JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + LEFT JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[RootSkipSharedId] = [t].[Id] +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[RootSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Include_skip_navigation_then_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_then_reference_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [t].[OneId], [t].[TwoId], [t].[UnidirectionalJoinOneToTwoExtraId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN ( + SELECT [u0].[OneId], [u0].[TwoId], [u0].[UnidirectionalJoinOneToTwoExtraId], [u1].[Id], [u1].[Name], [u2].[Id] AS [Id0], [u2].[CollectionInverseId], [u2].[ExtraId], [u2].[Name] AS [Name0], [u2].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[Id] = [u2].[ReferenceInverseId] +) AS [t] ON [u].[Id] = [t].[TwoId] +ORDER BY [u].[Id], [t].[OneId], [t].[TwoId], [t].[Id]"); + } + + public override async Task Include_skip_navigation_then_include_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t1].[LeafId], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id], [t1].[Name], [t1].[Number], [t1].[IsGreen], [t1].[UnidirectionalEntityBranchId], [t1].[UnidirectionalEntityOneId], [t1].[Id0], [t1].[Name0] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [u0].[LeafId], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], [t].[Id], [t].[Name], [t].[Number], [t].[IsGreen], [t0].[UnidirectionalEntityBranchId], [t0].[UnidirectionalEntityOneId], [t0].[Id] AS [Id0], [t0].[Name] AS [Name0] + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u0] + INNER JOIN ( + SELECT [u1].[Id], [u1].[Name], [u2].[Number], [u3].[IsGreen] + FROM [UnidirectionalRoots] AS [u1] + INNER JOIN [UnidirectionalBranches] AS [u2] ON [u1].[Id] = [u2].[Id] + INNER JOIN [UnidirectionalLeaves] AS [u3] ON [u1].[Id] = [u3].[Id] + ) AS [t] ON [u0].[LeafId] = [t].[Id] + LEFT JOIN ( + SELECT [u4].[UnidirectionalEntityBranchId], [u4].[UnidirectionalEntityOneId], [u5].[Id], [u5].[Name] + FROM [UnidirectionalJoinOneToBranch] AS [u4] + INNER JOIN [UnidirectionalEntityOnes] AS [u5] ON [u4].[UnidirectionalEntityOneId] = [u5].[Id] + ) AS [t0] ON [t].[Id] = [t0].[UnidirectionalEntityBranchId] +) AS [t1] ON [u].[Key1] = [t1].[CompositeId1] AND [u].[Key2] = [t1].[CompositeId2] AND [u].[Key3] = [t1].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t1].[LeafId], [t1].[CompositeId1], [t1].[CompositeId2], [t1].[CompositeId3], [t1].[Id], [t1].[UnidirectionalEntityBranchId], [t1].[UnidirectionalEntityOneId]"); + } + + public override async Task Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_reference_and_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id], [t0].[Name], [t0].[Id0], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name0], [t0].[ReferenceInverseId], [t0].[LeftId], [t0].[RightId], [t0].[Payload0], [t0].[Id1], [t0].[Name1] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u0].[OneId], [u0].[ThreeId], [u0].[Payload], [u1].[Id], [u1].[Name], [u2].[Id] AS [Id0], [u2].[CollectionInverseId], [u2].[ExtraId], [u2].[Name] AS [Name0], [u2].[ReferenceInverseId], [t].[LeftId], [t].[RightId], [t].[Payload] AS [Payload0], [t].[Id] AS [Id1], [t].[Name] AS [Name1] + FROM [UnidirectionalJoinOneToThreePayloadFull] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN [UnidirectionalEntityTwos] AS [u2] ON [u1].[Id] = [u2].[ReferenceInverseId] + LEFT JOIN ( + SELECT [u3].[LeftId], [u3].[RightId], [u3].[Payload], [u4].[Id], [u4].[Name] + FROM [UnidirectionalJoinOneSelfPayload] AS [u3] + INNER JOIN [UnidirectionalEntityOnes] AS [u4] ON [u3].[RightId] = [u4].[Id] + ) AS [t] ON [u1].[Id] = [t].[LeftId] +) AS [t0] ON [u].[Id] = [t0].[ThreeId] +ORDER BY [u].[Id], [t0].[OneId], [t0].[ThreeId], [t0].[Id], [t0].[Id0], [t0].[LeftId], [t0].[RightId]"); + } + + public override async Task Include_skip_navigation_and_reference_unidirectional(bool async) + { + await base.Include_skip_navigation_and_reference_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [u0].[Id], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityOneId], [t].[Id], [t].[Name], [u0].[CollectionInverseId], [u0].[Name], [u0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN [UnidirectionalEntityThrees] AS [u0] ON [u].[Id] = [u0].[ReferenceInverseId] +LEFT JOIN ( + SELECT [u1].[TwoSkipSharedId], [u1].[UnidirectionalEntityOneId], [u2].[Id], [u2].[Name] + FROM [UnidirectionalEntityOneUnidirectionalEntityTwo] AS [u1] + INNER JOIN [UnidirectionalEntityOnes] AS [u2] ON [u1].[UnidirectionalEntityOneId] = [u2].[Id] +) AS [t] ON [u].[Id] = [t].[TwoSkipSharedId] +ORDER BY [u].[Id], [u0].[Id], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityOneId]"); + } + + public override async Task Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(bool async) + { + await base.Include_skip_navigation_then_include_inverse_works_for_tracking_query_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t0].[OneId], [t0].[ThreeId], [t0].[Payload], [t0].[Id], [t0].[Name], [t0].[OneId0], [t0].[ThreeId0], [t0].[Payload0], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name0], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u0].[OneId], [u0].[ThreeId], [u0].[Payload], [u1].[Id], [u1].[Name], [t].[OneId] AS [OneId0], [t].[ThreeId] AS [ThreeId0], [t].[Payload] AS [Payload0], [t].[Id] AS [Id0], [t].[CollectionInverseId], [t].[Name] AS [Name0], [t].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u0] + INNER JOIN [UnidirectionalEntityOnes] AS [u1] ON [u0].[OneId] = [u1].[Id] + LEFT JOIN ( + SELECT [u2].[OneId], [u2].[ThreeId], [u2].[Payload], [u3].[Id], [u3].[CollectionInverseId], [u3].[Name], [u3].[ReferenceInverseId] + FROM [UnidirectionalJoinOneToThreePayloadFullShared] AS [u2] + INNER JOIN [UnidirectionalEntityThrees] AS [u3] ON [u2].[ThreeId] = [u3].[Id] + ) AS [t] ON [u1].[Id] = [t].[OneId] +) AS [t0] ON [u].[Id] = [t0].[ThreeId] +ORDER BY [u].[Id], [t0].[OneId], [t0].[ThreeId], [t0].[Id], [t0].[OneId0], [t0].[ThreeId0]"); + } + + public override async Task Filtered_include_skip_navigation_where_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_unidirectional(async); + + AssertSql( + @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[Name], [e].[ReferenceInverseId], [t].[OneId], [t].[ThreeId], [t].[Payload], [t].[Id], [t].[Name] +FROM [EntityThrees] AS [e] +LEFT JOIN ( + SELECT [j].[OneId], [j].[ThreeId], [j].[Payload], [e0].[Id], [e0].[Name] + FROM [JoinOneToThreePayloadFullShared] AS [j] + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + WHERE [e0].[Id] < 10 +) AS [t] ON [e].[Id] = [t].[ThreeId] +ORDER BY [e].[Id], [t].[OneId], [t].[ThreeId]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[Name], [u].[ReferenceInverseId], [t].[ThreeId], [t].[TwoId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityThrees] AS [u] +LEFT JOIN ( + SELECT [u0].[ThreeId], [u0].[TwoId], [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId] + FROM [UnidirectionalJoinTwoToThree] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[ThreeId] +ORDER BY [u].[Id], [t].[Id], [t].[ThreeId]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[CollectionInverseId], [u].[ExtraId], [u].[Name], [u].[ReferenceInverseId], [t0].[SelfSkipSharedRightId], [t0].[UnidirectionalEntityTwoId], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityTwos] AS [u] +LEFT JOIN ( + SELECT [t].[SelfSkipSharedRightId], [t].[UnidirectionalEntityTwoId], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] + FROM ( + SELECT [u0].[SelfSkipSharedRightId], [u0].[UnidirectionalEntityTwoId], [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityTwoId] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityTwoUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[SelfSkipSharedRightId] = [u1].[Id] + ) AS [t] + WHERE 2 < [t].[row] +) AS [t0] ON [u].[Id] = [t0].[UnidirectionalEntityTwoId] +ORDER BY [u].[Id], [t0].[UnidirectionalEntityTwoId], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_take_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[TwoSkipSharedId], [t].[UnidirectionalEntityCompositeKeyKey1], [t].[UnidirectionalEntityCompositeKeyKey2], [t].[UnidirectionalEntityCompositeKeyKey3], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] + FROM ( + SELECT [u0].[TwoSkipSharedId], [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3], [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [u0].[UnidirectionalEntityCompositeKeyKey1], [u0].[UnidirectionalEntityCompositeKeyKey2], [u0].[UnidirectionalEntityCompositeKeyKey3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoSkipSharedId] = [u1].[Id] + ) AS [t] + WHERE [t].[row] <= 2 +) AS [t0] ON [u].[Key1] = [t0].[UnidirectionalEntityCompositeKeyKey1] AND [u].[Key2] = [t0].[UnidirectionalEntityCompositeKeyKey2] AND [u].[Key3] = [t0].[UnidirectionalEntityCompositeKeyKey3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id]"); + } + + public override async Task Filtered_include_skip_navigation_order_by_skip_take_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_order_by_skip_take_unidirectional(async); + + AssertSql( + @"SELECT [u].[Key1], [u].[Key2], [u].[Key3], [u].[Name], [t0].[Id], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[ThreeId], [t0].[Id0], [t0].[CollectionInverseId], [t0].[Name], [t0].[ReferenceInverseId] +FROM [UnidirectionalEntityCompositeKeys] AS [u] +LEFT JOIN ( + SELECT [t].[Id], [t].[CompositeId1], [t].[CompositeId2], [t].[CompositeId3], [t].[ThreeId], [t].[Id0], [t].[CollectionInverseId], [t].[Name], [t].[ReferenceInverseId] + FROM ( + SELECT [u0].[Id], [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3], [u0].[ThreeId], [u1].[Id] AS [Id0], [u1].[CollectionInverseId], [u1].[Name], [u1].[ReferenceInverseId], ROW_NUMBER() OVER(PARTITION BY [u0].[CompositeId1], [u0].[CompositeId2], [u0].[CompositeId3] ORDER BY [u1].[Id]) AS [row] + FROM [UnidirectionalJoinThreeToCompositeKeyFull] AS [u0] + INNER JOIN [UnidirectionalEntityThrees] AS [u1] ON [u0].[ThreeId] = [u1].[Id] + ) AS [t] + WHERE 1 < [t].[row] AND [t].[row] <= 3 +) AS [t0] ON [u].[Key1] = [t0].[CompositeId1] AND [u].[Key2] = [t0].[CompositeId2] AND [u].[Key3] = [t0].[CompositeId3] +ORDER BY [u].[Key1], [u].[Key2], [u].[Key3], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Id0]"); + } + + public override async Task Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(bool async) + { + await base.Filtered_include_skip_navigation_where_then_include_skip_navigation_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[Name], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3], [t0].[Id], [t0].[CollectionInverseId], [t0].[ExtraId], [t0].[Name0], [t0].[ReferenceInverseId] +FROM [UnidirectionalRoots] AS [u] +INNER JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +INNER JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +LEFT JOIN ( + SELECT [u2].[LeafId], [u2].[CompositeId1], [u2].[CompositeId2], [u2].[CompositeId3], [u3].[Key1], [u3].[Key2], [u3].[Key3], [u3].[Name], [t].[TwoSkipSharedId], [t].[UnidirectionalEntityCompositeKeyKey1], [t].[UnidirectionalEntityCompositeKeyKey2], [t].[UnidirectionalEntityCompositeKeyKey3], [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name] AS [Name0], [t].[ReferenceInverseId] + FROM [UnidirectionalJoinCompositeKeyToLeaf] AS [u2] + INNER JOIN [UnidirectionalEntityCompositeKeys] AS [u3] ON [u2].[CompositeId1] = [u3].[Key1] AND [u2].[CompositeId2] = [u3].[Key2] AND [u2].[CompositeId3] = [u3].[Key3] + LEFT JOIN ( + SELECT [u4].[TwoSkipSharedId], [u4].[UnidirectionalEntityCompositeKeyKey1], [u4].[UnidirectionalEntityCompositeKeyKey2], [u4].[UnidirectionalEntityCompositeKeyKey3], [u5].[Id], [u5].[CollectionInverseId], [u5].[ExtraId], [u5].[Name], [u5].[ReferenceInverseId] + FROM [UnidirectionalEntityCompositeKeyUnidirectionalEntityTwo] AS [u4] + INNER JOIN [UnidirectionalEntityTwos] AS [u5] ON [u4].[TwoSkipSharedId] = [u5].[Id] + ) AS [t] ON [u3].[Key1] = [t].[UnidirectionalEntityCompositeKeyKey1] AND [u3].[Key2] = [t].[UnidirectionalEntityCompositeKeyKey2] AND [u3].[Key3] = [t].[UnidirectionalEntityCompositeKeyKey3] + WHERE [u3].[Key1] < 5 +) AS [t0] ON [u].[Id] = [t0].[LeafId] +ORDER BY [u].[Id], [t0].[LeafId], [t0].[CompositeId1], [t0].[CompositeId2], [t0].[CompositeId3], [t0].[Key1], [t0].[Key2], [t0].[Key3], [t0].[TwoSkipSharedId], [t0].[UnidirectionalEntityCompositeKeyKey1], [t0].[UnidirectionalEntityCompositeKeyKey2], [t0].[UnidirectionalEntityCompositeKeyKey3]"); + } + + public override async Task Filter_include_on_skip_navigation_combined_unidirectional(bool async) + { + await base.Filter_include_on_skip_navigation_combined_unidirectional(async); + + AssertSql( + @"SELECT [e].[Id], [e].[CollectionInverseId], [e].[ExtraId], [e].[Name], [e].[ReferenceInverseId], [t].[OneId], [t].[TwoId], [t].[JoinOneToTwoExtraId], [t].[Id], [t].[Name], [t].[Id0], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name0], [t].[ReferenceInverseId], [t].[Id1], [t].[CollectionInverseId0], [t].[ExtraId0], [t].[Name1], [t].[ReferenceInverseId0] +FROM [EntityTwos] AS [e] +LEFT JOIN ( + SELECT [j].[OneId], [j].[TwoId], [j].[JoinOneToTwoExtraId], [e0].[Id], [e0].[Name], [e1].[Id] AS [Id0], [e1].[CollectionInverseId], [e1].[ExtraId], [e1].[Name] AS [Name0], [e1].[ReferenceInverseId], [e2].[Id] AS [Id1], [e2].[CollectionInverseId] AS [CollectionInverseId0], [e2].[ExtraId] AS [ExtraId0], [e2].[Name] AS [Name1], [e2].[ReferenceInverseId] AS [ReferenceInverseId0] + FROM [JoinOneToTwo] AS [j] + INNER JOIN [EntityOnes] AS [e0] ON [j].[OneId] = [e0].[Id] + LEFT JOIN [EntityTwos] AS [e1] ON [e0].[Id] = [e1].[ReferenceInverseId] + LEFT JOIN [EntityTwos] AS [e2] ON [e0].[Id] = [e2].[CollectionInverseId] + WHERE [e0].[Id] < 10 +) AS [t] ON [e].[Id] = [t].[TwoId] +ORDER BY [e].[Id], [t].[OneId], [t].[TwoId], [t].[Id], [t].[Id0]"); + } + + public override async Task Throws_when_different_filtered_include_unidirectional(bool async) + { + await base.Throws_when_different_filtered_include_unidirectional(async); + + AssertSql(); + } + + public override async Task Includes_accessed_via_different_path_are_merged_unidirectional(bool async) + { + await base.Includes_accessed_via_different_path_are_merged_unidirectional(async); + + AssertSql(); + } + + public override async Task Select_many_over_skip_navigation_where_non_equality_unidirectional(bool async) + { + await base.Select_many_over_skip_navigation_where_non_equality_unidirectional(async); +AssertSql( + @"SELECT [t].[Id], [t].[CollectionInverseId], [t].[ExtraId], [t].[Name], [t].[ReferenceInverseId] +FROM [UnidirectionalEntityOnes] AS [u] +LEFT JOIN ( + SELECT [u1].[Id], [u1].[CollectionInverseId], [u1].[ExtraId], [u1].[Name], [u1].[ReferenceInverseId], [u0].[OneId] + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] +) AS [t] ON [u].[Id] = [t].[OneId] AND [u].[Id] <> [t].[Id]"); + } + + public override async Task Contains_on_skip_collection_navigation_unidirectional(bool async) + { + await base.Contains_on_skip_collection_navigation_unidirectional(async); + + AssertSql( + @"@__entity_equality_two_0_Id='1' (Nullable = true) + +SELECT [u].[Id], [u].[Name] +FROM [UnidirectionalEntityOnes] AS [u] +WHERE EXISTS ( + SELECT 1 + FROM [UnidirectionalJoinOneToTwo] AS [u0] + INNER JOIN [UnidirectionalEntityTwos] AS [u1] ON [u0].[TwoId] = [u1].[Id] + WHERE [u].[Id] = [u0].[OneId] AND [u1].[Id] = @__entity_equality_two_0_Id)"); + } + + public override async Task GetType_in_hierarchy_in_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_base_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], CASE + WHEN [u1].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u0].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' +END AS [Discriminator] +FROM [UnidirectionalRoots] AS [u] +LEFT JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +LEFT JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +WHERE [u1].[Id] IS NULL AND [u0].[Id] IS NULL"); + } + + public override async Task GetType_in_hierarchy_in_intermediate_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_intermediate_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], CASE + WHEN [u1].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u0].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' +END AS [Discriminator] +FROM [UnidirectionalRoots] AS [u] +LEFT JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +LEFT JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +WHERE [u1].[Id] IS NULL AND [u0].[Id] IS NOT NULL"); + } + + public override async Task GetType_in_hierarchy_in_leaf_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_leaf_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], CASE + WHEN [u1].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' + WHEN [u0].[Id] IS NOT NULL THEN N'UnidirectionalEntityBranch' +END AS [Discriminator] +FROM [UnidirectionalRoots] AS [u] +LEFT JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +LEFT JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +WHERE [u1].[Id] IS NOT NULL"); + } + + public override async Task GetType_in_hierarchy_in_querying_base_type_unidirectional(bool async) + { + await base.GetType_in_hierarchy_in_querying_base_type_unidirectional(async); + + AssertSql( + @"SELECT [u].[Id], [u].[Name], [u0].[Number], [u1].[IsGreen], CASE + WHEN [u1].[Id] IS NOT NULL THEN N'UnidirectionalEntityLeaf' +END AS [Discriminator] +FROM [UnidirectionalRoots] AS [u] +INNER JOIN [UnidirectionalBranches] AS [u0] ON [u].[Id] = [u0].[Id] +LEFT JOIN [UnidirectionalLeaves] AS [u1] ON [u].[Id] = [u1].[Id] +WHERE 0 = 1"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs b/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs index 694508715e1..bb419c1e078 100644 --- a/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/ManyToManyTestBase.cs @@ -445,6 +445,192 @@ public virtual void Throws_for_conflicting_many_to_one_on_right() .HasMany(o => o.Categories).WithMany(c => c.Products)).Message); } + [ConditionalFact] + public virtual void Many_to_many_with_only_Has_navigation_configured() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity().HasMany(e => e.Products).WithMany(); + + var model = modelBuilder.FinalizeModel(); + + var manyToManyA = model.FindEntityType(typeof(UniCategory))!; + var manyToManyB = model.FindEntityType(typeof(UniProduct))!; + var joinEntityType = model.GetEntityTypes() + .Where(et => et.ClrType == Model.DefaultPropertyBagType) + .Single(); + Assert.Equal("UniCategoryUniProduct", joinEntityType.Name); + + var navigationOnManyToManyA = manyToManyA.GetSkipNavigations().Single(); + var navigationOnManyToManyB = manyToManyB.GetSkipNavigations().Single(); + Assert.Equal("Products", navigationOnManyToManyA.Name); + Assert.Equal("UniCategory", navigationOnManyToManyB.Name); + Assert.Same(navigationOnManyToManyA.Inverse, navigationOnManyToManyB); + Assert.Same(navigationOnManyToManyB.Inverse, navigationOnManyToManyA); + Assert.False(navigationOnManyToManyA.IsShadowProperty()); + Assert.True(navigationOnManyToManyB.IsShadowProperty()); + + var manyToManyAForeignKey = navigationOnManyToManyA.ForeignKey; + var manyToManyBForeignKey = navigationOnManyToManyB.ForeignKey; + Assert.NotNull(manyToManyAForeignKey); + Assert.NotNull(manyToManyBForeignKey); + Assert.Equal(2, joinEntityType.GetForeignKeys().Count()); + Assert.Equal(manyToManyAForeignKey.DeclaringEntityType, joinEntityType); + Assert.Equal(manyToManyBForeignKey.DeclaringEntityType, joinEntityType); + + var key = joinEntityType.FindPrimaryKey()!; + Assert.Equal( + new[] + { + "ProductsId", + "UniCategoryId" + }, + key.Properties.Select(p => p.Name)); + + Assert.DoesNotContain(joinEntityType.GetProperties(), p => !p.IsIndexerProperty()); + } + + [ConditionalFact] + public virtual void Many_to_many_with_no_navigations_configured() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity().HasMany().WithMany(); + + var model = modelBuilder.FinalizeModel(); + + var manyToManyA = model.FindEntityType(typeof(NoCategory))!; + var manyToManyB = model.FindEntityType(typeof(NoProduct))!; + var joinEntityType = model.GetEntityTypes() + .Where(et => et.ClrType == Model.DefaultPropertyBagType) + .Single(); + Assert.Equal("NoCategoryNoProduct", joinEntityType.Name); + + var navigationOnManyToManyA = manyToManyA.GetSkipNavigations().Single(); + var navigationOnManyToManyB = manyToManyB.GetSkipNavigations().Single(); + Assert.Equal("NoProduct", navigationOnManyToManyA.Name); + Assert.Equal("NoCategory", navigationOnManyToManyB.Name); + Assert.Same(navigationOnManyToManyA.Inverse, navigationOnManyToManyB); + Assert.Same(navigationOnManyToManyB.Inverse, navigationOnManyToManyA); + Assert.True(navigationOnManyToManyA.IsShadowProperty()); + Assert.True(navigationOnManyToManyB.IsShadowProperty()); + + var manyToManyAForeignKey = navigationOnManyToManyA.ForeignKey; + var manyToManyBForeignKey = navigationOnManyToManyB.ForeignKey; + Assert.NotNull(manyToManyAForeignKey); + Assert.NotNull(manyToManyBForeignKey); + Assert.Equal(2, joinEntityType.GetForeignKeys().Count()); + Assert.Equal(manyToManyAForeignKey.DeclaringEntityType, joinEntityType); + Assert.Equal(manyToManyBForeignKey.DeclaringEntityType, joinEntityType); + + var key = joinEntityType.FindPrimaryKey()!; + Assert.Equal( + new[] + { + "NoCategoryId", + "NoProductId" + }, + key.Properties.Select(p => p.Name)); + + Assert.DoesNotContain(joinEntityType.GetProperties(), p => !p.IsIndexerProperty()); + } + + [ConditionalFact] + public virtual void Many_to_many_with_a_shadow_navigation() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Ignore(); + modelBuilder.Ignore(); + modelBuilder.Entity().Ignore(d => d.ManyToManyPrincipals); + + modelBuilder.Entity() + .HasMany(d => d.Dependents) + .WithMany("Shadow"); + + var model = modelBuilder.FinalizeModel(); + + var manyToManyA = model.FindEntityType(typeof(ManyToManyNavPrincipal))!; + var manyToManyB = model.FindEntityType(typeof(NavDependent))!; + var joinEntityType = model.GetEntityTypes() + .Where(et => et.ClrType == Model.DefaultPropertyBagType) + .Single(); + Assert.Equal("ManyToManyNavPrincipalNavDependent", joinEntityType.Name); + + var navigationOnManyToManyA = manyToManyA.GetSkipNavigations().Single(); + var navigationOnManyToManyB = manyToManyB.GetSkipNavigations().Single(); + Assert.Equal("Dependents", navigationOnManyToManyA.Name); + Assert.Equal("Shadow", navigationOnManyToManyB.Name); + Assert.Same(navigationOnManyToManyA.Inverse, navigationOnManyToManyB); + Assert.Same(navigationOnManyToManyB.Inverse, navigationOnManyToManyA); + Assert.False(navigationOnManyToManyA.IsShadowProperty()); + Assert.True(navigationOnManyToManyB.IsShadowProperty()); + + var manyToManyAForeignKey = navigationOnManyToManyA.ForeignKey; + var manyToManyBForeignKey = navigationOnManyToManyB.ForeignKey; + Assert.NotNull(manyToManyAForeignKey); + Assert.NotNull(manyToManyBForeignKey); + Assert.Equal(2, joinEntityType.GetForeignKeys().Count()); + Assert.Equal(manyToManyAForeignKey.DeclaringEntityType, joinEntityType); + Assert.Equal(manyToManyBForeignKey.DeclaringEntityType, joinEntityType); + + var key = joinEntityType.FindPrimaryKey()!; + Assert.Equal( + new[] + { + "DependentsId", + "ShadowId" + }, + key.Properties.Select(p => p.Name)); + + Assert.DoesNotContain(joinEntityType.GetProperties(), p => !p.IsIndexerProperty()); + } + + [ConditionalFact] + public virtual void Many_to_many_with_only_With_navigation_configured() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity().HasMany().WithMany(c => c.Products); + + var model = modelBuilder.FinalizeModel(); + + var manyToManyA = model.FindEntityType(typeof(UniProduct))!; + var manyToManyB = model.FindEntityType(typeof(UniCategory))!; + var joinEntityType = model.GetEntityTypes() + .Where(et => et.ClrType == Model.DefaultPropertyBagType) + .Single(); + Assert.Equal("UniCategoryUniProduct", joinEntityType.Name); + + var navigationOnManyToManyA = manyToManyA.GetSkipNavigations().Single(); + var navigationOnManyToManyB = manyToManyB.GetSkipNavigations().Single(); + Assert.Equal("UniCategory", navigationOnManyToManyA.Name); + Assert.Equal("Products", navigationOnManyToManyB.Name); + Assert.Same(navigationOnManyToManyA.Inverse, navigationOnManyToManyB); + Assert.Same(navigationOnManyToManyB.Inverse, navigationOnManyToManyA); + Assert.True(navigationOnManyToManyA.IsShadowProperty()); + Assert.False(navigationOnManyToManyB.IsShadowProperty()); + + var manyToManyAForeignKey = navigationOnManyToManyA.ForeignKey; + var manyToManyBForeignKey = navigationOnManyToManyB.ForeignKey; + Assert.NotNull(manyToManyAForeignKey); + Assert.NotNull(manyToManyBForeignKey); + Assert.Equal(2, joinEntityType.GetForeignKeys().Count()); + Assert.Equal(manyToManyAForeignKey.DeclaringEntityType, joinEntityType); + Assert.Equal(manyToManyBForeignKey.DeclaringEntityType, joinEntityType); + + var key = joinEntityType.FindPrimaryKey()!; + Assert.Equal( + new[] + { + "ProductsId", + "UniCategoryId" + }, + key.Properties.Select(p => p.Name)); + + Assert.DoesNotContain(joinEntityType.GetProperties(), p => !p.IsIndexerProperty()); + } + [ConditionalFact] public virtual void Throws_for_self_ref_with_same_navigation() { diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs index a44cae7bfb5..a7727e3a1ae 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderGenericTest.cs @@ -169,7 +169,7 @@ public override IMutableEntityType Metadata protected virtual TestEntityTypeBuilder Wrap(EntityTypeBuilder entityTypeBuilder) => new GenericTestEntityTypeBuilder(entityTypeBuilder); - + protected virtual TestPropertyBuilder Wrap(PropertyBuilder propertyBuilder) => new GenericTestPropertyBuilder(propertyBuilder); @@ -575,7 +575,7 @@ public override TestPropertyBuilder HasConversion(ValueConverter? con public override TestPropertyBuilder HasConversion() => Wrap(PropertyBuilder.HasConversion()); - + public override TestPropertyBuilder HasConversion() => Wrap(PropertyBuilder.HasConversion()); @@ -707,7 +707,7 @@ public override TestReferenceCollectionBuilder WithOne( CollectionNavigationBuilder.WithOne(navigationExpression)); public override TestCollectionCollectionBuilder WithMany( - string navigationName) + string? navigationName = null) => new GenericTestCollectionCollectionBuilder( CollectionNavigationBuilder.WithMany(navigationName)); diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs index 31814560084..72339a741ec 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderNonGenericTest.cs @@ -632,10 +632,10 @@ public override TestPropertyBuilder HasConversion( public override TestPropertyBuilder HasConversion(ValueConverter converter) => Wrap(PropertyBuilder.HasConversion(converter)); - + public override TestPropertyBuilder HasConversion(ValueConverter converter, ValueComparer? valueComparer) => Wrap(PropertyBuilder.HasConversion(converter, valueComparer)); - + public override TestPropertyBuilder HasConversion( ValueConverter converter, ValueComparer? valueComparer, @@ -787,7 +787,7 @@ public override TestReferenceCollectionBuilder WithOne( navigationExpression?.GetMemberAccess().GetSimpleMemberName())); public override TestCollectionCollectionBuilder WithMany( - string navigationName) + string? navigationName = null) => new NonGenericTestCollectionCollectionBuilder( CollectionNavigationBuilder.WithMany(navigationName)); diff --git a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs index 0a49457809f..5cffaf9c89e 100644 --- a/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/ModelBuilderTestBase.cs @@ -422,14 +422,14 @@ public abstract TestPropertyBuilder HasConversion( ValueConverter converter, ValueComparer? valueComparer, ValueComparer? providerComparerType); - + public abstract TestPropertyBuilder HasConversion(ValueConverter? converter); public abstract TestPropertyBuilder HasConversion(ValueConverter? converter, ValueComparer? valueComparer); public abstract TestPropertyBuilder HasConversion(ValueConverter? converter, ValueComparer? valueComparer, ValueComparer? providerComparerType); public abstract TestPropertyBuilder HasConversion() where TComparer : ValueComparer; - + public abstract TestPropertyBuilder HasConversion() where TComparer : ValueComparer where TProviderComparer : ValueComparer; @@ -453,7 +453,7 @@ public abstract class TestCollectionNavigationBuilder public abstract TestReferenceCollectionBuilder WithOne( Expression>? navigationExpression = null); - public abstract TestCollectionCollectionBuilder WithMany(string navigationName); + public abstract TestCollectionCollectionBuilder WithMany(string? navigationName = null); public abstract TestCollectionCollectionBuilder WithMany( Expression?>> navigationExpression); diff --git a/test/EFCore.Tests/ModelBuilding/TestModel.cs b/test/EFCore.Tests/ModelBuilding/TestModel.cs index a059ea58ca2..9bda4b1902c 100644 --- a/test/EFCore.Tests/ModelBuilding/TestModel.cs +++ b/test/EFCore.Tests/ModelBuilding/TestModel.cs @@ -169,6 +169,27 @@ private class OrderProduct public virtual Product Product { get; set; } = null!; } + protected class UniProduct + { + public int Id { get; set; } + } + + protected class UniCategory + { + public int Id { get; set; } + public virtual ICollection? Products { get; set; } + } + + protected class NoProduct + { + public int Id { get; set; } + } + + protected class NoCategory + { + public int Id { get; set; } + } + [NotMapped] protected class Product {