diff --git a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
index a82b0b7286e..6ad7fec2d3c 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
+++ b/src/EFCore.Relational/Properties/RelationalStrings.Designer.cs
@@ -53,20 +53,6 @@ public static string BadSequenceType
public static string CannotChangeWhenOpen
=> GetString("CannotChangeWhenOpen");
- ///
- /// Comparing complex types to null is not supported.
- ///
- public static string CannotCompareComplexTypeToNull
- => GetString("CannotCompareComplexTypeToNull");
-
- ///
- /// You are attempting to project out complex type '{complexType}' via an optional navigation; that is currently not supported. Either project out the complex type in a non-optional context, or project the containing entity type along with the complex type.
- ///
- public static string CannotProjectNullableComplexType(object? complexType)
- => string.Format(
- GetString("CannotProjectNullableComplexType", nameof(complexType)),
- complexType);
-
///
/// Join expressions have no aliases; set the alias on the enclosed table expression.
///
diff --git a/src/EFCore.Relational/Properties/RelationalStrings.resx b/src/EFCore.Relational/Properties/RelationalStrings.resx
index 75e42be0127..5be7983829e 100644
--- a/src/EFCore.Relational/Properties/RelationalStrings.resx
+++ b/src/EFCore.Relational/Properties/RelationalStrings.resx
@@ -130,12 +130,6 @@
The instance of DbConnection is currently in use. The connection can only be changed when the existing connection is not being used.
-
- Comparing complex types to null is not supported.
-
-
- You are attempting to project out complex type '{complexType}' via an optional navigation; that is currently not supported. Either project out the complex type in a non-optional context, or project the containing entity type along with the complex type.
-
Join expressions have no aliases; set the alias on the enclosed table expression.
diff --git a/src/EFCore.Relational/Query/Internal/RelationalStructuralTypeMaterializerSource.cs b/src/EFCore.Relational/Query/Internal/RelationalStructuralTypeMaterializerSource.cs
index 43400fe11c1..b61477d3aad 100644
--- a/src/EFCore.Relational/Query/Internal/RelationalStructuralTypeMaterializerSource.cs
+++ b/src/EFCore.Relational/Query/Internal/RelationalStructuralTypeMaterializerSource.cs
@@ -1,9 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+
namespace Microsoft.EntityFrameworkCore.Query.Internal;
-#pragma warning disable EF1001 // EntityMaterializerSource is pubternal
+#pragma warning disable EF1001 // StructuralTypeMaterializerSource is pubternal
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -15,39 +16,9 @@ public class RelationalStructuralTypeMaterializerSource(StructuralTypeMaterializ
: StructuralTypeMaterializerSource(dependencies)
{
///
- /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
- /// the same compatibility standards as public APIs. It may be changed or removed without notice in
- /// any release. You should only use it directly in your code with extreme caution and knowing that
- /// doing so can result in application failures when updating to a new Entity Framework Core release.
- ///
- protected override void AddInitializeExpression(
- IPropertyBase property,
- ParameterBindingInfo bindingInfo,
- Expression instanceVariable,
- MethodCallExpression valueBufferExpression,
- List blockExpressions)
- {
- // JSON complex properties are not handled in the initial materialization expression, since they're not
- // simply e.g. DbDataReader.GetFieldValue<>() calls. So they're handled afterwards in the shaper, and need
- // to be skipped here.
- if (property is IComplexProperty { ComplexType: var complexType } && complexType.IsMappedToJson())
- {
- return;
- }
-
- base.AddInitializeExpression(property, bindingInfo, instanceVariable, valueBufferExpression, blockExpressions);
- }
-
- ///
- /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
- /// the same compatibility standards as public APIs. It may be changed or removed without notice in
- /// any release. You should only use it directly in your code with extreme caution and knowing that
- /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ /// JSON complex properties are not handled in the initial materialization expression,
+ /// since they're not simply e.g. DbDataReader.GetFieldValue calls.
+ /// So they're handled afterwards in the shaper, and need to be skipped.
///
- [EntityFrameworkInternal]
- public static readonly MethodInfo MaterializeJsonComplexTypeMethod
- = typeof(RelationalStructuralTypeMaterializerSource).GetTypeInfo().GetDeclaredMethod(nameof(MaterializeJsonComplexType))!;
-
- private static T MaterializeJsonComplexType(in ValueBuffer valueBuffer, IComplexProperty complexProperty)
- => throw new UnreachableException();
+ protected override bool ReadComplexTypeDirectly(IComplexType complexType) => !complexType.IsMappedToJson();
}
diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs
index f199ebc0d41..93491a9102e 100644
--- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs
+++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs
@@ -311,15 +311,6 @@ bool TryRewriteComplexTypeEquality(bool collection, [NotNullWhen(true)] out SqlE
Check.DebugAssert(complexType != null, "We checked that at least one side is a complex type before calling this function");
- // Comparison to null needs to be handled in a special way for table splitting, but for JSON mapping is handled via
- // the regular JSON flow below.
- if ((IsNullSqlConstantExpression(left) || IsNullSqlConstantExpression(right)) && !complexType.IsMappedToJson())
- {
- // TODO: when we support optional complex types with table splitting - or projecting required complex types via optional
- // navigations - we'll be able to translate this, #31376
- throw new InvalidOperationException(RelationalStrings.CannotCompareComplexTypeToNull);
- }
-
// If a complex type is the result of a subquery, then comparing its columns would mean duplicating the subquery, which would
// be potentially very inefficient.
// TODO: Enable this by extracting the subquery out to a common table expressions (WITH), #31237
diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
index 4f96e4f6eb2..eef7e91c6a5 100644
--- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
+++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
@@ -492,12 +492,6 @@ public void ApplyProjection()
void AddStructuralTypeProjection(StructuralTypeProjectionExpression projection)
{
- if (_projection.Count == 0
- && projection is { StructuralType: IComplexType complexType, IsNullable: true })
- {
- throw new InvalidOperationException(RelationalStrings.CannotProjectNullableComplexType(complexType.DisplayName()));
- }
-
ProcessTypeProjection(projection);
void ProcessTypeProjection(StructuralTypeProjectionExpression projection)
@@ -1367,11 +1361,6 @@ Expression CopyProjectionToOuter(SelectExpression innerSelectExpression, Express
ConstantExpression AddStructuralTypeProjection(StructuralTypeProjectionExpression projection)
{
- if (projection is { StructuralType: IComplexType complexType, IsNullable: true })
- {
- throw new InvalidOperationException(RelationalStrings.CannotProjectNullableComplexType(complexType.DisplayName()));
- }
-
// JSON entity that had some query operations applied on it - it has been converted to a query root via OPENJSON/json_each
// so it requires different materialization path than regular entity
// e.g. we need to also add all the child navigations, JSON entity builds all the includes as part of it's own materializer
diff --git a/src/EFCore/Query/EntityMaterializerSourceParameters.cs b/src/EFCore/Query/EntityMaterializerSourceParameters.cs
index 88677025bbf..659e5606bbc 100644
--- a/src/EFCore/Query/EntityMaterializerSourceParameters.cs
+++ b/src/EFCore/Query/EntityMaterializerSourceParameters.cs
@@ -8,12 +8,14 @@ namespace Microsoft.EntityFrameworkCore.Query;
///
/// The entity or complex type being materialized.
/// The name of the instance being materialized.
+/// Whether nullable result is allowed.
///
/// The query tracking behavior, or if this materialization is not from a query.
///
public readonly record struct StructuralTypeMaterializerSourceParameters(
ITypeBase StructuralType,
string InstanceName,
+ bool? AllowNullable,
QueryTrackingBehavior? QueryTrackingBehavior);
///
diff --git a/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs b/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs
index 2745b19b62d..5c98ed229d9 100644
--- a/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs
+++ b/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs
@@ -95,28 +95,46 @@ public Expression CreateMaterializeExpression(
properties.Remove(consumedProperty);
}
- var constructorExpression = constructorBinding.CreateConstructorExpression(bindingInfo);
-
- if (_materializationInterceptor == null
- // TODO: This currently applies the materialization interceptor only on the root structural type - any contained complex types
- // don't get intercepted. #35883
- || structuralType is not IEntityType)
+ var materializationExpression = HandleMaterializationInterception();
+
+ return
+ structuralType is IComplexType complexType && ReadComplexTypeDirectly(complexType)
+ && (IsNullable(complexType) || parameters.AllowNullable == true)
+ ? HandleNullableComplexTypeMaterialization(
+ complexType,
+ complexType.ClrType,
+ materializationExpression,
+ bindingInfo)
+ : materializationExpression;
+
+ Expression HandleMaterializationInterception()
{
- return properties.Count == 0 && blockExpressions.Count == 0
- ? constructorExpression
- : CreateMaterializeExpression(blockExpressions, instanceVariable, constructorExpression, properties, bindingInfo);
+ var constructorExpression = constructorBinding.CreateConstructorExpression(bindingInfo);
+
+ return _materializationInterceptor == null
+ // TODO: This currently applies the materialization interceptor only on the root structural type - any contained complex types
+ // don't get intercepted. #35883
+ || structuralType is not IEntityType
+ ? properties.Count == 0 && blockExpressions.Count == 0
+ ? constructorExpression
+ : CreateMaterializeExpression(blockExpressions, instanceVariable, constructorExpression, properties, bindingInfo)
+ : CreateInterceptionMaterializeExpression(
+ structuralType,
+ properties,
+ _materializationInterceptor,
+ bindingInfo,
+ constructorExpression,
+ instanceVariable,
+ blockExpressions);
}
-
- return CreateInterceptionMaterializeExpression(
- structuralType,
- properties,
- _materializationInterceptor,
- bindingInfo,
- constructorExpression,
- instanceVariable,
- blockExpressions);
}
+ ///
+ /// Should complex type be read directly using e.g. DbDataReader.GetFieldValue
+ /// or is it going to be handled separately (i.e. relational JSON).
+ ///
+ protected virtual bool ReadComplexTypeDirectly(IComplexType complexType) => true;
+
///
/// 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
@@ -130,11 +148,17 @@ protected virtual void AddInitializeExpression(
MethodCallExpression valueBufferExpression,
List blockExpressions)
{
+ if (property is IComplexProperty cp && !ReadComplexTypeDirectly(cp.ComplexType))
+ {
+ return;
+ }
+
var memberInfo = property.GetMemberInfo(forMaterialization: true, forSet: true);
var valueExpression = property switch
{
- IProperty p => valueBufferExpression.CreateValueBufferReadValueExpression(memberInfo.GetMemberType(), p.GetIndex(), p),
+ IProperty p
+ => valueBufferExpression.CreateValueBufferReadValueExpression(memberInfo.GetMemberType(), p.GetIndex(), p),
IServiceProperty serviceProperty
=> serviceProperty.ParameterBinding.BindToParameter(bindingInfo),
@@ -143,9 +167,7 @@ IServiceProperty serviceProperty
=> Default(complexProperty.ClrType), // Initialize collections to null, they'll be populated separately
IComplexProperty complexProperty
- => CreateMaterializeExpression(
- new StructuralTypeMaterializerSourceParameters(complexProperty.ComplexType, "complexType", QueryTrackingBehavior: null),
- bindingInfo.MaterializationContextExpression),
+ => CreateComplexTypeMaterializeExpression(complexProperty, bindingInfo),
_ => throw new UnreachableException()
};
@@ -193,6 +215,21 @@ static Expression CreateMemberAssignment(Expression parameter, MemberInfo member
value)
: MakeMemberAccess(parameter, memberInfo).Assign(value);
}
+
+ Expression CreateComplexTypeMaterializeExpression(IComplexProperty complexProperty, ParameterBindingInfo bindingInfo)
+ {
+ var materializeExpression = CreateMaterializeExpression(
+ new StructuralTypeMaterializerSourceParameters(complexProperty.ComplexType, "complexType", null, QueryTrackingBehavior: null),
+ bindingInfo.MaterializationContextExpression);
+
+ return IsNullable(complexProperty)
+ ? HandleNullableComplexTypeMaterialization(
+ complexProperty.ComplexType,
+ complexProperty.ClrType,
+ materializeExpression,
+ bindingInfo)
+ : materializeExpression;
+ }
}
private void AddInitializeExpressions(
@@ -493,15 +530,14 @@ BlockExpression CreateInitializeExpression()
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
- public virtual Func GetMaterializer(
- IEntityType entityType)
+ public virtual Func GetMaterializer(IEntityType entityType)
{
var materializationContextParameter
= Parameter(typeof(MaterializationContext), "materializationContext");
return Lambda>(
((IStructuralTypeMaterializerSource)this).CreateMaterializeExpression(
- new StructuralTypeMaterializerSourceParameters(entityType, "instance", null), materializationContextParameter),
+ new StructuralTypeMaterializerSourceParameters(entityType, "instance", null, null), materializationContextParameter),
materializationContextParameter)
.Compile();
}
@@ -518,7 +554,7 @@ public virtual Func GetMaterializer(IComplexType
return Lambda>(
((IStructuralTypeMaterializerSource)this).CreateMaterializeExpression(
- new StructuralTypeMaterializerSourceParameters(complexType, "instance", null), materializationContextParameter),
+ new StructuralTypeMaterializerSourceParameters(complexType, "instance", null, null), materializationContextParameter),
materializationContextParameter)
.Compile();
}
@@ -572,7 +608,7 @@ public virtual Func GetEmptyMaterializer(
var materializationContextExpression = Parameter(typeof(MaterializationContext), "mc");
var bindingInfo = new ParameterBindingInfo(
- new StructuralTypeMaterializerSourceParameters(entityType, "instance", null), materializationContextExpression);
+ new StructuralTypeMaterializerSourceParameters(entityType, "instance", null, null), materializationContextExpression);
var blockExpressions = new List();
var instanceVariable = Variable(binding.RuntimeType, "instance");
@@ -644,4 +680,50 @@ private static void CreateServiceInstances(
}
}
}
+
+ private Expression HandleNullableComplexTypeMaterialization(IComplexType complexType, Type clrType, Expression materializeExpression, ParameterBindingInfo bindingInfo)
+ {
+ var valueBufferExpression = Call(
+ bindingInfo.MaterializationContextExpression,
+ MaterializationContext.GetValueBufferMethod);
+
+ // Get all scalar properties of the complex type (including nested ones).
+ var allScalarProperties = complexType.GetFlattenedProperties().ToList();
+
+ if (allScalarProperties is [])
+ {
+ // If no scalar properties, just create the instance.
+ return CreateMaterializeExpression(
+ new StructuralTypeMaterializerSourceParameters(complexType, "complexType", null, QueryTrackingBehavior: null),
+ bindingInfo.MaterializationContextExpression);
+ }
+
+ var requiredProperty = allScalarProperties.Where(p => !p.IsNullable).FirstOrDefault();
+ var nullCheck = requiredProperty is not null
+ // If there's a required property, it's enough to check just that one for null.
+ ? Equal(
+ valueBufferExpression.CreateValueBufferReadValueExpression(typeof(object), requiredProperty.GetIndex(), requiredProperty),
+ Constant(null, typeof(object)))
+ // Create null checks for all scalar properties.
+ : allScalarProperties
+ .Select(p =>
+ Equal(
+ valueBufferExpression.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p),
+ Constant(null, typeof(object))))
+ .Aggregate(AndAlso);
+
+ // If property/properties are null, return default (to handle structs); otherwise materialize the complex type.
+ return Condition(
+ nullCheck,
+ Default(clrType),
+ materializeExpression);
+ }
+
+ private static bool IsNullable(IComplexType complexType)
+ => IsNullable(complexType.ComplexProperty);
+
+ private static bool IsNullable(IComplexProperty complexProperty)
+ => complexProperty.IsNullable
+ || (complexProperty.DeclaringType is IComplexType complexType
+ && IsNullable(complexType.ComplexProperty));
}
diff --git a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
index bf13c3e75c8..3dba903bf1f 100644
--- a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
+++ b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
@@ -659,7 +659,7 @@ private Expression MaterializeEntity(
{
var concreteStructuralType = concreteStructuralTypes[i];
switchCases[i] = SwitchCase(
- CreateFullMaterializeExpression(concreteStructuralTypes[i], expressionContext),
+ CreateFullMaterializeExpression(concreteStructuralTypes[i], shaper.IsNullable, expressionContext),
supportsPrecompiledQuery
? liftableConstantFactory.CreateLiftableConstant(
concreteStructuralTypes[i],
@@ -712,6 +712,7 @@ private Expression MaterializeEntity(
private BlockExpression CreateFullMaterializeExpression(
ITypeBase concreteStructuralType,
+ bool shaperIsNullable,
(Type ReturnType,
ParameterExpression MaterializationContextVariable,
ParameterExpression ConcreteEntityTypeVariable,
@@ -727,7 +728,7 @@ private BlockExpression CreateFullMaterializeExpression(
var materializer = materializerSource
.CreateMaterializeExpression(
new StructuralTypeMaterializerSourceParameters(
- concreteStructuralType, "instance", queryTrackingBehavior), materializationContextVariable);
+ concreteStructuralType, "instance", shaperIsNullable, queryTrackingBehavior), materializationContextVariable);
// TODO: Properly support shadow properties for complex types #35613
if (_queryStateManager
diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionCosmosTest.cs
index aef5c28ad88..c83866193b0 100644
--- a/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionCosmosTest.cs
+++ b/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionCosmosTest.cs
@@ -190,6 +190,10 @@ FROM root c
}
}
+ [ConditionalTheory(Skip = "This type of projection does not make sense for Cosmos.")]
+ public override Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ => base.Select_required_related_via_optional_navigation(queryTrackingBehavior);
+
#endregion Non-collection
#region Collection
diff --git a/test/EFCore.Relational.Specification.Tests/Query/ComplexTypeQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/ComplexTypeQueryRelationalTestBase.cs
index 9482eae1632..e9cd422bb42 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/ComplexTypeQueryRelationalTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/ComplexTypeQueryRelationalTestBase.cs
@@ -39,15 +39,6 @@ public override async Task Union_two_different_complex_type(bool async)
AssertSql();
}
- public override async Task Complex_type_equals_null(bool async)
- {
- var exception = await Assert.ThrowsAsync(() => base.Complex_type_equals_null(async));
-
- Assert.Equal(RelationalStrings.CannotCompareComplexTypeToNull, exception.Message);
-
- AssertSql();
- }
-
public override async Task Subquery_over_struct_complex_type(bool async)
{
var exception = await Assert.ThrowsAsync(() => base.Subquery_over_struct_complex_type(async));
diff --git a/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousRelationalTestBase.cs
index 54ec7285792..b781ff85492 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousRelationalTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousRelationalTestBase.cs
@@ -15,10 +15,6 @@ public ComplexTableSplittingMiscellaneousRelationalTestBase(TFixture fixture, IT
fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
- // TODO: Optional complex properties not yet supported (#31376)
- public override Task Where_optional_related_property()
- => AssertTranslationFailed(() => base.Where_optional_related_property());
-
protected void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
diff --git a/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionRelationalTestBase.cs
index 3ff62477ccd..7e7bd3ec641 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionRelationalTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionRelationalTestBase.cs
@@ -16,31 +16,27 @@ public ComplexTableSplittingProjectionRelationalTestBase(TFixture fixture, ITest
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
- // Complex JSON collections, update pipeline not yet supported so no seeding, #31237
+ // Collections are not supported with table splitting, only JSON
public override Task Select_related_collection(QueryTrackingBehavior queryTrackingBehavior)
=> Assert.ThrowsAsync(() => base.Select_related_collection(queryTrackingBehavior));
- // Complex JSON collections, update pipeline not yet supported so no seeding, #31237
+ // Collections are not supported with table splitting, only JSON
public override Task Select_nested_collection_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
=> Assert.ThrowsAsync(() => base.Select_nested_collection_on_required_related(queryTrackingBehavior));
- // Optional complex types, #31376
- public override Task Select_optional_nested_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
- => Assert.ThrowsAsync(() => base.Select_optional_nested_on_required_related(queryTrackingBehavior));
+ // Collections are not supported with table splitting, only JSON
+ public override Task Select_nested_collection_on_optional_related(QueryTrackingBehavior queryTrackingBehavior)
+ => Assert.ThrowsAsync(() => base.Select_nested_collection_on_optional_related(queryTrackingBehavior));
- // Optional complex types, #31376
- public override Task Select_subquery_required_related_FirstOrDefault(QueryTrackingBehavior queryTrackingBehavior)
- => Assert.ThrowsAsync(() => base.Select_subquery_required_related_FirstOrDefault(queryTrackingBehavior));
-
- // Complex JSON collections, update pipeline not yet supported so no seeding, #31237
+ // Collections are not supported with table splitting, only JSON
public override Task SelectMany_related_collection(QueryTrackingBehavior queryTrackingBehavior)
=> Assert.ThrowsAsync(() => base.SelectMany_related_collection(queryTrackingBehavior));
- // Optional complex types, #31376
+ // Collections are not supported with table splitting, only JSON
public override Task SelectMany_nested_collection_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
=> Assert.ThrowsAsync(() => base.SelectMany_nested_collection_on_required_related(queryTrackingBehavior));
- // Optional complex types, #31376
+ // Collections are not supported with table splitting, only JSON
public override Task SelectMany_nested_collection_on_optional_related(QueryTrackingBehavior queryTrackingBehavior)
=> Assert.ThrowsAsync(() => base.SelectMany_nested_collection_on_optional_related(queryTrackingBehavior));
diff --git a/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingRelationalFixtureBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingRelationalFixtureBase.cs
index b032125a503..ce92afb4449 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingRelationalFixtureBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingRelationalFixtureBase.cs
@@ -17,20 +17,6 @@ public abstract class ComplexTableSplittingRelationalFixtureBase : ComplexProper
{
protected override string StoreName => "ComplexTableSplittingQueryTest";
- protected override RelationshipsData CreateData()
- {
- var data = new RelationshipsData();
-
- // TODO: Optional complex properties not yet supported (#31376), remove them from the seeding data
- foreach (var rootEntity in data.RootEntities)
- {
- rootEntity.OptionalRelated = null;
- rootEntity.RequiredRelated.OptionalNested = null;
- }
-
- return data;
- }
-
protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
{
base.OnModelCreating(modelBuilder, context);
@@ -40,16 +26,20 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
b.ComplexProperty(e => e.RequiredRelated, rrb =>
{
rrb.ComplexProperty(r => r.RequiredNested);
-
- // TODO: Optional complex properties not yet supported: #31376
- rrb.Ignore(r => r.OptionalNested);
+ rrb.ComplexProperty(r => r.OptionalNested);
// Collections are not supported with table splitting, only JSON
rrb.Ignore(r => r.NestedCollection);
});
- // TODO: Optional complex properties not yet supported: #31376
- b.Ignore(r => r.OptionalRelated);
+ b.ComplexProperty(e => e.OptionalRelated, orb =>
+ {
+ orb.ComplexProperty(o => o.RequiredNested);
+ orb.ComplexProperty(o => o.OptionalNested);
+
+ // Collections are not supported with table splitting, only JSON
+ orb.Ignore(o => o.NestedCollection);
+ });
// Collections are not supported with table splitting, only JSON
b.Ignore(r => r.RelatedCollection);
diff --git a/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityRelationalTestBase.cs
index 852dd8202d4..27b8b2ef261 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityRelationalTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualityRelationalTestBase.cs
@@ -15,36 +15,17 @@ public ComplexTableSplittingStructuralEqualityRelationalTestBase(TFixture fixtur
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
- // TODO: All the tests below rely on access OptionalRelated, but optional complex properties not yet supported (#31376)
-
- public override Task Two_related()
- => Assert.ThrowsAsync(() => base.Two_related());
-
- public override Task Two_nested()
- => Assert.ThrowsAsync(() => base.Two_nested());
-
- public override Task Not_equals()
- => Assert.ThrowsAsync(() => base.Not_equals());
-
- public override Task Related_with_inline_null()
- => Assert.ThrowsAsync(() => base.Related_with_inline_null());
-
- public override Task Related_with_parameter_null()
- => Assert.ThrowsAsync(() => base.Related_with_parameter_null());
-
- public override Task Nested_with_inline_null()
- => Assert.ThrowsAsync(() => base.Nested_with_inline_null());
-
- public override Task Two_nested_collections()
- => Assert.ThrowsAsync(() => base.Two_nested_collections());
+ // Collections are not supported with table splitting, only JSON
+ public override Task Nested_collection_with_parameter()
+ => Assert.ThrowsAsync(base.Nested_collection_with_parameter);
- // Collection equality with owned collections is not supported
+ // Collections are not supported with table splitting, only JSON
public override Task Nested_collection_with_inline()
- => Assert.ThrowsAsync(() => base.Nested_collection_with_inline());
+ => Assert.ThrowsAsync(base.Nested_collection_with_inline);
- // Collection equality with owned collections is not supported
- public override Task Nested_collection_with_parameter()
- => Assert.ThrowsAsync(() => base.Nested_collection_with_parameter());
+ // Collections are not supported with table splitting, only JSON
+ public override Task Two_nested_collections()
+ => Assert.ThrowsAsync(base.Two_nested_collections);
protected void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
diff --git a/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedJson/OwnedJsonProjectionRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedJson/OwnedJsonProjectionRelationalTestBase.cs
index 46c5807dd33..1a5b3d2ebd4 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedJson/OwnedJsonProjectionRelationalTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedJson/OwnedJsonProjectionRelationalTestBase.cs
@@ -15,6 +15,11 @@ public OwnedJsonProjectionRelationalTestBase(TFixture fixture, ITestOutputHelper
fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
+ public override Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ => AssertOwnedTrackingQuery(
+ queryTrackingBehavior,
+ () => base.Select_required_related_via_optional_navigation(queryTrackingBehavior));
+
protected void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
}
diff --git a/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionRelationalTestBase.cs
index b4c5a469d0d..97374646526 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionRelationalTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionRelationalTestBase.cs
@@ -14,6 +14,11 @@ public OwnedNavigationsProjectionRelationalTestBase(TFixture fixture, ITestOutpu
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
+ public override Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ => AssertOwnedTrackingQuery(
+ queryTrackingBehavior,
+ () => base.Select_required_related_via_optional_navigation(queryTrackingBehavior));
+
// Traditional relational collections navigations projected from null instances are returned as empty collections rather than null.
// This is in contrast to client evaluation behavior - and also the JSON collection behavior - where we get null instance (coalescing).
public override Task Select_nested_collection_on_optional_related(QueryTrackingBehavior queryTrackingBehavior)
diff --git a/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedTableSplitting/OwnedTableSplittingProjectionRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedTableSplitting/OwnedTableSplittingProjectionRelationalTestBase.cs
index f99d261232f..5dad021a7fe 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedTableSplitting/OwnedTableSplittingProjectionRelationalTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedTableSplitting/OwnedTableSplittingProjectionRelationalTestBase.cs
@@ -16,6 +16,11 @@ public OwnedTableSplittingProjectionRelationalTestBase(TFixture fixture, ITestOu
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
+ public override Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ => AssertOwnedTrackingQuery(
+ queryTrackingBehavior,
+ () => base.Select_required_related_via_optional_navigation(queryTrackingBehavior));
+
// Traditional relational collections navigations can't be compared reliably.
// The failure below is because collections on from null instances are returned as empty collections rather than null; but
// even disregarding that, elements in the collection don't preserve ordering and so can't be compared reliably.
diff --git a/test/EFCore.Specification.Tests/Query/ComplexTypeQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/ComplexTypeQueryFixtureBase.cs
index 7207c5fa501..857e0dd3ac2 100644
--- a/test/EFCore.Specification.Tests/Query/ComplexTypeQueryFixtureBase.cs
+++ b/test/EFCore.Specification.Tests/Query/ComplexTypeQueryFixtureBase.cs
@@ -76,8 +76,8 @@ public ISetSource GetExpectedData()
{ typeof(ValuedCustomerGroup), (Func)(e => e.Id) },
// Complex types - still need comparers for cases where they are projected directly
- { typeof(Address), (Func)(e => e.ZipCode) },
- { typeof(Country), (Func)(e => e.Code) },
+ { typeof(Address), (Func)(e => e?.ZipCode ?? 0) },
+ { typeof(Country), (Func)(e => e?.Code ?? string.Empty) },
{ typeof(AddressStruct), (Func)(e => e.ZipCode) },
{ typeof(CountryStruct), (Func)(e => e.Code) }
}.ToDictionary(e => e.Key, e => e.Value);
diff --git a/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
index 7248a7f96ac..489de9ba4fe 100644
--- a/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
@@ -67,7 +67,8 @@ public virtual Task Filter_on_required_property_inside_required_complex_type_on_
public virtual Task Project_complex_type_via_optional_navigation(bool async)
=> AssertQuery(
async,
- ss => ss.Set().Select(cg => cg.OptionalCustomer!.ShippingAddress));
+ ss => ss.Set().Select(cg => cg.OptionalCustomer!.ShippingAddress),
+ ss => ss.Set().Select(cg => cg.OptionalCustomer != null ? cg.OptionalCustomer.ShippingAddress : default));
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
@@ -172,13 +173,6 @@ public virtual Task Complex_type_equals_parameter(bool async)
&& c.ShippingAddress.Tags.SequenceEqual(new List { "foo", "bar" })));
}
- [ConditionalTheory]
- [MemberData(nameof(IsAsyncData))]
- public virtual Task Complex_type_equals_null(bool async)
- => AssertQuery(
- async,
- ss => ss.Set().Where(c => c.ShippingAddress == null));
-
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual Task Subquery_over_complex_type(bool async)
@@ -338,7 +332,8 @@ public virtual Task Filter_on_required_property_inside_required_struct_complex_t
public virtual Task Project_struct_complex_type_via_optional_navigation(bool async)
=> AssertQuery(
async,
- ss => ss.Set().Select(cg => cg.OptionalCustomer!.ShippingAddress));
+ ss => ss.Set().Select(cg => cg.OptionalCustomer!.ShippingAddress),
+ ss => ss.Set().Select(cg => cg.OptionalCustomer != null ? cg.OptionalCustomer.ShippingAddress : default));
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
diff --git a/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsData.cs b/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsData.cs
index 0c7a8777495..50f90b7c9ca 100644
--- a/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsData.cs
+++ b/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsData.cs
@@ -10,7 +10,7 @@ public RelationshipsData()
RootEntities = CreateRootEntities();
RelatedTypes = [];
NestedTypes = [];
- PreRootEntities = [];
+ RootReferencingEntities = CreateRootReferencingEntities(RootEntities);
}
public List RootEntities { get; }
@@ -19,7 +19,7 @@ public RelationshipsData()
public List RelatedTypes { get; }
public List NestedTypes { get; }
- public List PreRootEntities { get; }
+ public List RootReferencingEntities { get; }
public static List CreateRootEntities()
{
@@ -334,6 +334,23 @@ RootEntity CreateRootEntity(int id, string? description, Action? cus
}
}
+ public static List CreateRootReferencingEntities(IEnumerable rootEntities)
+ {
+ var rootReferencingEntities = new List();
+
+ var id = 1;
+
+ rootReferencingEntities.Add(new() { Id = id++, Root = null });
+ foreach (var rootEntity in rootEntities)
+ {
+ var rootReferencingEntity = new RootReferencingEntity { Id = id++, Root = rootEntity };
+ rootEntity.RootReferencingEntity = rootReferencingEntity;
+ rootReferencingEntities.Add(rootReferencingEntity);
+ }
+
+ return rootReferencingEntities;
+ }
+
public IQueryable Set()
where TEntity : class
=> typeof(TEntity) switch
@@ -341,7 +358,7 @@ public IQueryable Set()
var t when t == typeof(RootEntity) => (IQueryable)RootEntities.AsQueryable(),
var t when t == typeof(RelatedType) => (IQueryable)RelatedTypes.AsQueryable(),
var t when t == typeof(NestedType) => (IQueryable)NestedTypes.AsQueryable(),
- var t when t == typeof(RootReferencingEntity) => (IQueryable)PreRootEntities.AsQueryable(),
+ var t when t == typeof(RootReferencingEntity) => (IQueryable)RootReferencingEntities.AsQueryable(),
_ => throw new InvalidOperationException("Invalid entity type: " + typeof(TEntity))
};
diff --git a/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsProjectionTestBase.cs b/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsProjectionTestBase.cs
index 3f7c53f65d8..efa3310802f 100644
--- a/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsProjectionTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsProjectionTestBase.cs
@@ -92,6 +92,13 @@ public virtual Task Select_optional_nested_on_optional_related(QueryTrackingBeha
ss => ss.Set().Select(x => x.OptionalRelated!.OptionalNested),
queryTrackingBehavior: queryTrackingBehavior);
+ [ConditionalTheory]
+ [MemberData(nameof(TrackingData))]
+ public virtual Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ => AssertQuery(
+ ss => ss.Set().Select(e => e.Root!.RequiredRelated),
+ queryTrackingBehavior: queryTrackingBehavior);
+
#endregion Non-collection
#region Collection
diff --git a/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsQueryFixtureBase.cs b/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsQueryFixtureBase.cs
index ad850c79138..680db19a12e 100644
--- a/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsQueryFixtureBase.cs
+++ b/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsQueryFixtureBase.cs
@@ -34,6 +34,10 @@ protected virtual RelationshipsData CreateData()
protected override Task SeedAsync(PoolableDbContext context)
{
context.Set().AddRange(_data.RootEntities);
+ if (context.Model.FindEntityType(typeof(RootReferencingEntity)) is not null)
+ {
+ context.Set().AddRange(_data.RootReferencingEntities);
+ }
return context.SaveChangesAsync();
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
index 776c0446f1e..7b31606e0e9 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
@@ -107,14 +107,16 @@ WHERE [c0].[ShippingAddress_ZipCode] <> 7728
""");
}
- // This test fails because when OptionalCustomer is null, we get all-null results because of the LEFT JOIN, and we materialize this
- // as an empty ShippingAddress instead of null (see SQL). The proper solution here would be to project the Customer ID just for the
- // purpose of knowing that it's there.
public override async Task Project_complex_type_via_optional_navigation(bool async)
{
- var exception = await Assert.ThrowsAsync(() => base.Project_complex_type_via_optional_navigation(async));
+ await base.Project_complex_type_via_optional_navigation(async);
- Assert.Equal(RelationalStrings.CannotProjectNullableComplexType("Customer.ShippingAddress#Address"), exception.Message);
+ AssertSql(
+ """
+SELECT [c0].[ShippingAddress_AddressLine1], [c0].[ShippingAddress_AddressLine2], [c0].[ShippingAddress_Tags], [c0].[ShippingAddress_ZipCode], [c0].[ShippingAddress_Country_Code], [c0].[ShippingAddress_Country_FullName]
+FROM [CustomerGroup] AS [c]
+LEFT JOIN [Customer] AS [c0] ON [c].[OptionalCustomerId] = [c0].[Id]
+""");
}
public override async Task Project_complex_type_via_required_navigation(bool async)
@@ -245,13 +247,6 @@ FROM [Customer] AS [c]
""");
}
- public override async Task Complex_type_equals_null(bool async)
- {
- await base.Complex_type_equals_null(async);
-
- AssertSql();
- }
-
public override async Task Subquery_over_complex_type(bool async)
{
await base.Subquery_over_complex_type(async);
@@ -476,15 +471,16 @@ WHERE [v0].[ShippingAddress_ZipCode] <> 7728
""");
}
- // This test fails because when OptionalCustomer is null, we get all-null results because of the LEFT JOIN, and we materialize this
- // as an empty ShippingAddress instead of null (see SQL). The proper solution here would be to project the Customer ID just for the
- // purpose of knowing that it's there.
public override async Task Project_struct_complex_type_via_optional_navigation(bool async)
{
- var exception =
- await Assert.ThrowsAsync(() => base.Project_struct_complex_type_via_optional_navigation(async));
+ await base.Project_struct_complex_type_via_optional_navigation(async);
- Assert.Equal(RelationalStrings.CannotProjectNullableComplexType("ValuedCustomer.ShippingAddress#AddressStruct"), exception.Message);
+ AssertSql(
+ """
+SELECT [v0].[ShippingAddress_AddressLine1], [v0].[ShippingAddress_AddressLine2], [v0].[ShippingAddress_ZipCode], [v0].[ShippingAddress_Country_Code], [v0].[ShippingAddress_Country_FullName]
+FROM [ValuedCustomerGroup] AS [v]
+LEFT JOIN [ValuedCustomer] AS [v0] ON [v].[OptionalCustomerId] = [v0].[Id]
+""");
}
public override async Task Project_struct_complex_type_via_required_navigation(bool async)
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexJson/ComplexJsonProjectionSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexJson/ComplexJsonProjectionSqlServerTest.cs
index fcb5ec2720a..791075c9dce 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexJson/ComplexJsonProjectionSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexJson/ComplexJsonProjectionSqlServerTest.cs
@@ -177,6 +177,18 @@ FROM [RootEntity] AS [r]
""");
}
+ public override async Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_required_related_via_optional_navigation(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT [r0].[RequiredRelated]
+FROM [RootReferencingEntity] AS [r]
+LEFT JOIN [RootEntity] AS [r0] ON [r].[RootEntityId] = [r0].[Id]
+""");
+ }
+
#endregion Non-collection
#region Collection
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqlServerTest.cs
index b0391f6d839..67f0df5075f 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqlServerTest.cs
@@ -8,15 +8,13 @@ public class ComplexTableSplittingMiscellaneousSqlServerTest(
ITestOutputHelper testOutputHelper)
: ComplexTableSplittingMiscellaneousRelationalTestBase(fixture, testOutputHelper)
{
- #region Simple filters
-
public override async Task Where_related_property()
{
await base.Where_related_property();
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
WHERE [r].[RequiredRelated_Int] = 8
""");
@@ -26,7 +24,12 @@ public override async Task Where_optional_related_property()
{
await base.Where_optional_related_property();
- AssertSql();
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+WHERE [r].[OptionalRelated_Int] = 8
+""");
}
public override async Task Where_nested_related_property()
@@ -35,14 +38,12 @@ public override async Task Where_nested_related_property()
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
WHERE [r].[RequiredRelated_RequiredNested_Int] = 8
""");
}
- #endregion Simple filters
-
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqlServerTest.cs
index cfa9adac8b6..038a00678a0 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqlServerTest.cs
@@ -8,19 +8,41 @@ public class ComplexTableSplittingProjectionSqlServerTest(
ITestOutputHelper testOutputHelper)
: ComplexTableSplittingProjectionRelationalTestBase(fixture, testOutputHelper)
{
+ public override async Task Select_related_collection(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_related_collection(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+ORDER BY [r].[Id]
+""");
+ }
+
+ public override async Task Select_nested_collection_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_nested_collection_on_required_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+ORDER BY [r].[Id]
+""");
+ }
+
public override async Task Select_root(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_root(queryTrackingBehavior);
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
""");
}
- #region Simple properties
-
public override async Task Select_property_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_property_on_required_related(queryTrackingBehavior);
@@ -38,7 +60,7 @@ public override async Task Select_property_on_optional_related(QueryTrackingBeha
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[OptionalRelated_String]
FROM [RootEntity] AS [r]
""");
}
@@ -49,7 +71,7 @@ public override async Task Select_value_type_property_on_null_related_throws(Que
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[OptionalRelated_Int]
FROM [RootEntity] AS [r]
""");
}
@@ -60,22 +82,18 @@ public override async Task Select_nullable_value_type_property_on_null_related(Q
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[OptionalRelated_Int]
FROM [RootEntity] AS [r]
""");
}
- #endregion Simple properties
-
- #region Non-collection
-
public override async Task Select_related(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_related(queryTrackingBehavior);
AssertSql(
"""
-SELECT [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
""");
}
@@ -86,7 +104,7 @@ public override async Task Select_optional_related(QueryTrackingBehavior queryTr
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
""");
}
@@ -108,7 +126,7 @@ public override async Task Select_optional_nested_on_required_related(QueryTrack
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String]
FROM [RootEntity] AS [r]
""");
}
@@ -119,7 +137,7 @@ public override async Task Select_required_nested_on_optional_related(QueryTrack
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
""");
}
@@ -130,36 +148,20 @@ public override async Task Select_optional_nested_on_optional_related(QueryTrack
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
-FROM [RootEntity] AS [r]
-""");
- }
-
- #endregion Non-collection
-
- #region Collection
-
- public override async Task Select_related_collection(QueryTrackingBehavior queryTrackingBehavior)
- {
- await base.Select_related_collection(queryTrackingBehavior);
-
- AssertSql(
- """
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String]
FROM [RootEntity] AS [r]
-ORDER BY [r].[Id]
""");
}
- public override async Task Select_nested_collection_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
+ public override async Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
{
- await base.Select_nested_collection_on_required_related(queryTrackingBehavior);
+ await base.Select_required_related_via_optional_navigation(queryTrackingBehavior);
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
-FROM [RootEntity] AS [r]
-ORDER BY [r].[Id]
+SELECT [r0].[RequiredRelated_Id], [r0].[RequiredRelated_Int], [r0].[RequiredRelated_Name], [r0].[RequiredRelated_String], [r0].[RequiredRelated_OptionalNested_Id], [r0].[RequiredRelated_OptionalNested_Int], [r0].[RequiredRelated_OptionalNested_Name], [r0].[RequiredRelated_OptionalNested_String], [r0].[RequiredRelated_RequiredNested_Id], [r0].[RequiredRelated_RequiredNested_Int], [r0].[RequiredRelated_RequiredNested_Name], [r0].[RequiredRelated_RequiredNested_String]
+FROM [RootReferencingEntity] AS [r]
+LEFT JOIN [RootEntity] AS [r0] ON [r].[RootEntityId] = [r0].[Id]
""");
}
@@ -169,7 +171,7 @@ public override async Task Select_nested_collection_on_optional_related(QueryTra
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
ORDER BY [r].[Id]
""");
@@ -196,30 +198,31 @@ public override async Task SelectMany_nested_collection_on_optional_related(Quer
AssertSql();
}
- #endregion Collection
-
- #region Multiple
-
public override async Task Select_root_duplicated(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_root_duplicated(queryTrackingBehavior);
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
""");
}
- #endregion Multiple
-
- #region Subquery
-
public override async Task Select_subquery_required_related_FirstOrDefault(QueryTrackingBehavior queryTrackingBehavior)
{
await base.Select_subquery_required_related_FirstOrDefault(queryTrackingBehavior);
- AssertSql();
+ AssertSql(
+ """
+SELECT [r1].[RequiredRelated_RequiredNested_Id], [r1].[RequiredRelated_RequiredNested_Int], [r1].[RequiredRelated_RequiredNested_Name], [r1].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+OUTER APPLY (
+ SELECT TOP(1) [r0].[RequiredRelated_RequiredNested_Id], [r0].[RequiredRelated_RequiredNested_Int], [r0].[RequiredRelated_RequiredNested_Name], [r0].[RequiredRelated_RequiredNested_String]
+ FROM [RootEntity] AS [r0]
+ ORDER BY [r0].[Id]
+) AS [r1]
+""");
}
public override async Task Select_subquery_optional_related_FirstOrDefault(QueryTrackingBehavior queryTrackingBehavior)
@@ -228,18 +231,16 @@ public override async Task Select_subquery_optional_related_FirstOrDefault(Query
AssertSql(
"""
-SELECT [r1].[Id], [r1].[Name], [r1].[RequiredRelated_Id], [r1].[RequiredRelated_Int], [r1].[RequiredRelated_Name], [r1].[RequiredRelated_String], [r1].[RequiredRelated_RequiredNested_Id], [r1].[RequiredRelated_RequiredNested_Int], [r1].[RequiredRelated_RequiredNested_Name], [r1].[RequiredRelated_RequiredNested_String], [r1].[c]
+SELECT [r1].[OptionalRelated_RequiredNested_Id], [r1].[OptionalRelated_RequiredNested_Int], [r1].[OptionalRelated_RequiredNested_Name], [r1].[OptionalRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
OUTER APPLY (
- SELECT TOP(1) [r0].[Id], [r0].[Name], [r0].[RequiredRelated_Id], [r0].[RequiredRelated_Int], [r0].[RequiredRelated_Name], [r0].[RequiredRelated_String], [r0].[RequiredRelated_RequiredNested_Id], [r0].[RequiredRelated_RequiredNested_Int], [r0].[RequiredRelated_RequiredNested_Name], [r0].[RequiredRelated_RequiredNested_String], 1 AS [c]
+ SELECT TOP(1) [r0].[OptionalRelated_RequiredNested_Id], [r0].[OptionalRelated_RequiredNested_Int], [r0].[OptionalRelated_RequiredNested_Name], [r0].[OptionalRelated_RequiredNested_String]
FROM [RootEntity] AS [r0]
ORDER BY [r0].[Id]
) AS [r1]
""");
}
- #endregion Subquery
-
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqlServerTest.cs
index 9c85421e925..bc12ee0ef53 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqlServerTest.cs
@@ -12,42 +12,72 @@ public override async Task Two_related()
{
await base.Two_related();
- AssertSql();
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+WHERE [r].[RequiredRelated_Id] = [r].[OptionalRelated_Id] AND [r].[RequiredRelated_Int] = [r].[OptionalRelated_Int] AND [r].[RequiredRelated_Name] = [r].[OptionalRelated_Name] AND [r].[RequiredRelated_String] = [r].[OptionalRelated_String] AND ([r].[RequiredRelated_OptionalNested_Id] = [r].[RequiredRelated_OptionalNested_Id] OR [r].[RequiredRelated_OptionalNested_Id] IS NULL) AND ([r].[RequiredRelated_OptionalNested_Int] = [r].[RequiredRelated_OptionalNested_Int] OR [r].[RequiredRelated_OptionalNested_Int] IS NULL) AND ([r].[RequiredRelated_OptionalNested_Name] = [r].[RequiredRelated_OptionalNested_Name] OR [r].[RequiredRelated_OptionalNested_Name] IS NULL) AND ([r].[RequiredRelated_OptionalNested_String] = [r].[RequiredRelated_OptionalNested_String] OR [r].[RequiredRelated_OptionalNested_String] IS NULL) AND [r].[RequiredRelated_RequiredNested_Id] = [r].[RequiredRelated_RequiredNested_Id] AND [r].[RequiredRelated_RequiredNested_Int] = [r].[RequiredRelated_RequiredNested_Int] AND [r].[RequiredRelated_RequiredNested_Name] = [r].[RequiredRelated_RequiredNested_Name] AND [r].[RequiredRelated_RequiredNested_String] = [r].[RequiredRelated_RequiredNested_String]
+""");
}
public override async Task Two_nested()
{
await base.Two_nested();
- AssertSql();
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+WHERE [r].[RequiredRelated_RequiredNested_Id] = [r].[OptionalRelated_RequiredNested_Id] AND [r].[RequiredRelated_RequiredNested_Int] = [r].[OptionalRelated_RequiredNested_Int] AND [r].[RequiredRelated_RequiredNested_Name] = [r].[OptionalRelated_RequiredNested_Name] AND [r].[RequiredRelated_RequiredNested_String] = [r].[OptionalRelated_RequiredNested_String]
+""");
}
public override async Task Not_equals()
{
await base.Not_equals();
- AssertSql();
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+WHERE [r].[RequiredRelated_Id] <> [r].[OptionalRelated_Id] OR [r].[OptionalRelated_Id] IS NULL OR [r].[RequiredRelated_Int] <> [r].[OptionalRelated_Int] OR [r].[OptionalRelated_Int] IS NULL OR [r].[RequiredRelated_Name] <> [r].[OptionalRelated_Name] OR [r].[OptionalRelated_Name] IS NULL OR [r].[RequiredRelated_String] <> [r].[OptionalRelated_String] OR [r].[OptionalRelated_String] IS NULL OR (([r].[RequiredRelated_OptionalNested_Id] <> [r].[RequiredRelated_OptionalNested_Id] OR [r].[RequiredRelated_OptionalNested_Id] IS NULL) AND [r].[RequiredRelated_OptionalNested_Id] IS NOT NULL) OR (([r].[RequiredRelated_OptionalNested_Int] <> [r].[RequiredRelated_OptionalNested_Int] OR [r].[RequiredRelated_OptionalNested_Int] IS NULL) AND [r].[RequiredRelated_OptionalNested_Int] IS NOT NULL) OR (([r].[RequiredRelated_OptionalNested_Name] <> [r].[RequiredRelated_OptionalNested_Name] OR [r].[RequiredRelated_OptionalNested_Name] IS NULL) AND [r].[RequiredRelated_OptionalNested_Name] IS NOT NULL) OR (([r].[RequiredRelated_OptionalNested_String] <> [r].[RequiredRelated_OptionalNested_String] OR [r].[RequiredRelated_OptionalNested_String] IS NULL) AND [r].[RequiredRelated_OptionalNested_String] IS NOT NULL) OR [r].[RequiredRelated_RequiredNested_Id] <> [r].[RequiredRelated_RequiredNested_Id] OR [r].[RequiredRelated_RequiredNested_Id] IS NULL OR [r].[RequiredRelated_RequiredNested_Int] <> [r].[RequiredRelated_RequiredNested_Int] OR [r].[RequiredRelated_RequiredNested_Int] IS NULL OR [r].[RequiredRelated_RequiredNested_Name] <> [r].[RequiredRelated_RequiredNested_Name] OR [r].[RequiredRelated_RequiredNested_Name] IS NULL OR [r].[RequiredRelated_RequiredNested_String] <> [r].[RequiredRelated_RequiredNested_String] OR [r].[RequiredRelated_RequiredNested_String] IS NULL
+""");
}
public override async Task Related_with_inline_null()
{
await base.Related_with_inline_null();
- AssertSql();
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+WHERE [r].[OptionalRelated_Id] IS NULL AND [r].[OptionalRelated_Int] IS NULL AND [r].[OptionalRelated_Name] IS NULL AND [r].[OptionalRelated_String] IS NULL AND [r].[OptionalRelated_OptionalNested_Id] IS NULL AND [r].[OptionalRelated_OptionalNested_Int] IS NULL AND [r].[OptionalRelated_OptionalNested_Name] IS NULL AND [r].[OptionalRelated_OptionalNested_String] IS NULL AND [r].[OptionalRelated_RequiredNested_Id] IS NULL AND [r].[OptionalRelated_RequiredNested_Int] IS NULL AND [r].[OptionalRelated_RequiredNested_Name] IS NULL AND [r].[OptionalRelated_RequiredNested_String] IS NULL
+""");
}
public override async Task Related_with_parameter_null()
{
await base.Related_with_parameter_null();
- AssertSql();
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+WHERE [r].[OptionalRelated_Id] IS NULL AND [r].[OptionalRelated_Int] IS NULL AND [r].[OptionalRelated_Name] IS NULL AND [r].[OptionalRelated_String] IS NULL AND [r].[OptionalRelated_OptionalNested_Id] IS NULL AND [r].[OptionalRelated_OptionalNested_Int] IS NULL AND [r].[OptionalRelated_OptionalNested_Name] IS NULL AND [r].[OptionalRelated_OptionalNested_String] IS NULL AND [r].[OptionalRelated_RequiredNested_Id] IS NULL AND [r].[OptionalRelated_RequiredNested_Int] IS NULL AND [r].[OptionalRelated_RequiredNested_Name] IS NULL AND [r].[OptionalRelated_RequiredNested_String] IS NULL
+""");
}
public override async Task Nested_with_inline_null()
{
await base.Nested_with_inline_null();
- AssertSql();
+ AssertSql(
+ """
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+FROM [RootEntity] AS [r]
+WHERE [r].[RequiredRelated_OptionalNested_Id] IS NULL AND [r].[RequiredRelated_OptionalNested_Int] IS NULL AND [r].[RequiredRelated_OptionalNested_Name] IS NULL AND [r].[RequiredRelated_OptionalNested_String] IS NULL
+""");
}
public override async Task Nested_with_inline()
@@ -56,7 +86,7 @@ public override async Task Nested_with_inline()
AssertSql(
"""
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
WHERE [r].[RequiredRelated_RequiredNested_Id] = 1000 AND [r].[RequiredRelated_RequiredNested_Int] = 8 AND [r].[RequiredRelated_RequiredNested_Name] = N'Root1_RequiredRelated_RequiredNested' AND [r].[RequiredRelated_RequiredNested_String] = N'foo'
""");
@@ -73,7 +103,7 @@ public override async Task Nested_with_parameter()
@entity_equality_nested_Name='?' (Size = 4000)
@entity_equality_nested_String='?' (Size = 4000)
-SELECT [r].[Id], [r].[Name], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
+SELECT [r].[Id], [r].[Name], [r].[OptionalRelated_Id], [r].[OptionalRelated_Int], [r].[OptionalRelated_Name], [r].[OptionalRelated_String], [r].[OptionalRelated_OptionalNested_Id], [r].[OptionalRelated_OptionalNested_Int], [r].[OptionalRelated_OptionalNested_Name], [r].[OptionalRelated_OptionalNested_String], [r].[OptionalRelated_RequiredNested_Id], [r].[OptionalRelated_RequiredNested_Int], [r].[OptionalRelated_RequiredNested_Name], [r].[OptionalRelated_RequiredNested_String], [r].[RequiredRelated_Id], [r].[RequiredRelated_Int], [r].[RequiredRelated_Name], [r].[RequiredRelated_String], [r].[RequiredRelated_OptionalNested_Id], [r].[RequiredRelated_OptionalNested_Int], [r].[RequiredRelated_OptionalNested_Name], [r].[RequiredRelated_OptionalNested_String], [r].[RequiredRelated_RequiredNested_Id], [r].[RequiredRelated_RequiredNested_Int], [r].[RequiredRelated_RequiredNested_Name], [r].[RequiredRelated_RequiredNested_String]
FROM [RootEntity] AS [r]
WHERE [r].[RequiredRelated_RequiredNested_Id] = @entity_equality_nested_Id AND [r].[RequiredRelated_RequiredNested_Int] = @entity_equality_nested_Int AND [r].[RequiredRelated_RequiredNested_Name] = @entity_equality_nested_Name AND [r].[RequiredRelated_RequiredNested_String] = @entity_equality_nested_String
""");
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/Navigations/NavigationsProjectionSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/Navigations/NavigationsProjectionSqlServerTest.cs
index 6212b7a5b07..c04628b63d3 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/Navigations/NavigationsProjectionSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/Navigations/NavigationsProjectionSqlServerTest.cs
@@ -147,6 +147,19 @@ FROM [RootEntity] AS [r]
""");
}
+ public override async Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_required_related_via_optional_navigation(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT [r1].[Id], [r1].[CollectionRootId], [r1].[Int], [r1].[Name], [r1].[OptionalNestedId], [r1].[RequiredNestedId], [r1].[String]
+FROM [RootReferencingEntity] AS [r]
+LEFT JOIN [RootEntity] AS [r0] ON [r].[RootEntityId] = [r0].[Id]
+LEFT JOIN [RelatedType] AS [r1] ON [r0].[RequiredRelatedId] = [r1].[Id]
+""");
+ }
+
#endregion Non-collection
#region Collection
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedJson/OwnedJsonProjectionSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedJson/OwnedJsonProjectionSqlServerTest.cs
index a1a8ccccd75..26bbb973581 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedJson/OwnedJsonProjectionSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedJson/OwnedJsonProjectionSqlServerTest.cs
@@ -151,6 +151,21 @@ FROM [RootEntity] AS [r]
}
}
+ public override async Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_required_related_via_optional_navigation(queryTrackingBehavior);
+
+ if (queryTrackingBehavior is not QueryTrackingBehavior.TrackAll)
+ {
+ AssertSql(
+ """
+SELECT [r0].[RequiredRelated], [r0].[Id]
+FROM [RootReferencingEntity] AS [r]
+LEFT JOIN [RootEntity] AS [r0] ON [r].[RootEntityId] = [r0].[Id]
+""");
+ }
+ }
+
#endregion Non-collection
#region Collection
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionSqlServerTest.cs
index 13875b1d887..0ceb4db4021 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionSqlServerTest.cs
@@ -189,6 +189,26 @@ FROM [RootEntity] AS [r]
}
}
+ public override async Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_required_related_via_optional_navigation(queryTrackingBehavior);
+
+ if (queryTrackingBehavior is not QueryTrackingBehavior.TrackAll)
+ {
+ AssertSql(
+ """
+SELECT [r1].[RootEntityId], [r1].[Id], [r1].[Int], [r1].[Name], [r1].[String], [r].[Id], [r0].[Id], [r2].[RelatedTypeRootEntityId], [r3].[RelatedTypeRootEntityId], [r4].[RelatedTypeRootEntityId], [r4].[Id], [r4].[Int], [r4].[Name], [r4].[String], [r2].[Id], [r2].[Int], [r2].[Name], [r2].[String], [r3].[Id], [r3].[Int], [r3].[Name], [r3].[String]
+FROM [RootReferencingEntity] AS [r]
+LEFT JOIN [RootEntity] AS [r0] ON [r].[RootEntityId] = [r0].[Id]
+LEFT JOIN [RequiredRelated] AS [r1] ON [r0].[Id] = [r1].[RootEntityId]
+LEFT JOIN [RequiredRelated_OptionalNested] AS [r2] ON [r1].[RootEntityId] = [r2].[RelatedTypeRootEntityId]
+LEFT JOIN [RequiredRelated_RequiredNested] AS [r3] ON [r1].[RootEntityId] = [r3].[RelatedTypeRootEntityId]
+LEFT JOIN [RequiredRelated_NestedCollection] AS [r4] ON [r1].[RootEntityId] = [r4].[RelatedTypeRootEntityId]
+ORDER BY [r].[Id], [r0].[Id], [r1].[RootEntityId], [r2].[RelatedTypeRootEntityId], [r3].[RelatedTypeRootEntityId], [r4].[RelatedTypeRootEntityId]
+""");
+ }
+ }
+
#endregion Non-collection
#region Collection
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedTableSplitting/OwnedTableSplittingProjectionSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedTableSplitting/OwnedTableSplittingProjectionSqlServerTest.cs
index fe8d7fcd789..964ecc08892 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedTableSplitting/OwnedTableSplittingProjectionSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedTableSplitting/OwnedTableSplittingProjectionSqlServerTest.cs
@@ -167,6 +167,23 @@ FROM [RootEntity] AS [r]
}
}
+ public override async Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_required_related_via_optional_navigation(queryTrackingBehavior);
+
+ if (queryTrackingBehavior is not QueryTrackingBehavior.TrackAll)
+ {
+ AssertSql(
+ """
+SELECT [r0].[Id], [r0].[RequiredRelated_Id], [r0].[RequiredRelated_Int], [r0].[RequiredRelated_Name], [r0].[RequiredRelated_String], [r].[Id], [r1].[RelatedTypeRootEntityId], [r1].[Id], [r1].[Int], [r1].[Name], [r1].[String], [r0].[RequiredRelated_OptionalNested_Id], [r0].[RequiredRelated_OptionalNested_Int], [r0].[RequiredRelated_OptionalNested_Name], [r0].[RequiredRelated_OptionalNested_String], [r0].[RequiredRelated_RequiredNested_Id], [r0].[RequiredRelated_RequiredNested_Int], [r0].[RequiredRelated_RequiredNested_Name], [r0].[RequiredRelated_RequiredNested_String]
+FROM [RootReferencingEntity] AS [r]
+LEFT JOIN [RootEntity] AS [r0] ON [r].[RootEntityId] = [r0].[Id]
+LEFT JOIN [RequiredRelated_NestedCollection] AS [r1] ON [r0].[Id] = [r1].[RelatedTypeRootEntityId]
+ORDER BY [r].[Id], [r0].[Id], [r1].[RelatedTypeRootEntityId]
+""");
+ }
+ }
+
#endregion Non-collection
#region Collection
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
index 49a75281aa6..7a9a221c9a7 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
@@ -107,14 +107,16 @@ public override async Task Filter_on_required_property_inside_required_complex_t
""");
}
- // This test fails because when OptionalCustomer is null, we get all-null results because of the LEFT JOIN, and we materialize this
- // as an empty ShippingAddress instead of null (see SQL). The proper solution here would be to project the Customer ID just for the
- // purpose of knowing that it's there.
public override async Task Project_complex_type_via_optional_navigation(bool async)
{
- var exception = await Assert.ThrowsAsync(() => base.Project_complex_type_via_optional_navigation(async));
+ await base.Project_complex_type_via_optional_navigation(async);
- Assert.Equal(RelationalStrings.CannotProjectNullableComplexType("Customer.ShippingAddress#Address"), exception.Message);
+ AssertSql(
+ """
+SELECT "c0"."ShippingAddress_AddressLine1", "c0"."ShippingAddress_AddressLine2", "c0"."ShippingAddress_Tags", "c0"."ShippingAddress_ZipCode", "c0"."ShippingAddress_Country_Code", "c0"."ShippingAddress_Country_FullName"
+FROM "CustomerGroup" AS "c"
+LEFT JOIN "Customer" AS "c0" ON "c"."OptionalCustomerId" = "c0"."Id"
+""");
}
public override async Task Project_complex_type_via_required_navigation(bool async)
@@ -245,13 +247,6 @@ public override async Task Complex_type_equals_parameter(bool async)
""");
}
- public override async Task Complex_type_equals_null(bool async)
- {
- await base.Complex_type_equals_null(async);
-
- AssertSql();
- }
-
public override async Task Subquery_over_complex_type(bool async)
{
await base.Subquery_over_complex_type(async);
@@ -476,15 +471,16 @@ public override async Task Filter_on_required_property_inside_required_struct_co
""");
}
- // This test fails because when OptionalCustomer is null, we get all-null results because of the LEFT JOIN, and we materialize this
- // as an empty ShippingAddress instead of null (see SQL). The proper solution here would be to project the Customer ID just for the
- // purpose of knowing that it's there.
public override async Task Project_struct_complex_type_via_optional_navigation(bool async)
{
- var exception =
- await Assert.ThrowsAsync(() => base.Project_struct_complex_type_via_optional_navigation(async));
+ await base.Project_struct_complex_type_via_optional_navigation(async);
- Assert.Equal(RelationalStrings.CannotProjectNullableComplexType("ValuedCustomer.ShippingAddress#AddressStruct"), exception.Message);
+ AssertSql(
+ """
+SELECT "v0"."ShippingAddress_AddressLine1", "v0"."ShippingAddress_AddressLine2", "v0"."ShippingAddress_ZipCode", "v0"."ShippingAddress_Country_Code", "v0"."ShippingAddress_Country_FullName"
+FROM "ValuedCustomerGroup" AS "v"
+LEFT JOIN "ValuedCustomer" AS "v0" ON "v"."OptionalCustomerId" = "v0"."Id"
+""");
}
public override async Task Project_struct_complex_type_via_required_navigation(bool async)
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqliteTest.cs
index 59abab0b7f6..92dcd0cebf5 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqliteTest.cs
@@ -6,4 +6,45 @@ namespace Microsoft.EntityFrameworkCore.Query.Relationships.ComplexTableSplittin
public class ComplexTableSplittingMiscellaneousSqliteTest(
ComplexTableSplittingSqliteFixture fixture,
ITestOutputHelper testOutputHelper)
- : ComplexTableSplittingMiscellaneousRelationalTestBase(fixture, testOutputHelper);
+ : ComplexTableSplittingMiscellaneousRelationalTestBase(fixture, testOutputHelper)
+{
+ public override async Task Where_related_property()
+ {
+ await base.Where_related_property();
+
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."RequiredRelated_Int" = 8
+""");
+ }
+
+ public override async Task Where_optional_related_property()
+ {
+ await base.Where_optional_related_property();
+
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."OptionalRelated_Int" = 8
+""");
+ }
+
+ public override async Task Where_nested_related_property()
+ {
+ await base.Where_nested_related_property();
+
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."RequiredRelated_RequiredNested_Int" = 8
+""");
+ }
+
+ [ConditionalFact]
+ public virtual void Check_all_tests_overridden()
+ => TestHelpers.AssertAllMethodsOverridden(GetType());
+}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqliteTest.cs
index 177104f5a77..c9ad7ff74b5 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqliteTest.cs
@@ -8,9 +8,216 @@ namespace Microsoft.EntityFrameworkCore.Query.Relationships.ComplexTableSplittin
public class ComplexTableSplittingProjectionSqliteTest(ComplexTableSplittingSqliteFixture fixture, ITestOutputHelper testOutputHelper)
: ComplexTableSplittingProjectionRelationalTestBase(fixture, testOutputHelper)
{
+ public override async Task Select_related_collection(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_related_collection(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+ORDER BY "r"."Id"
+""");
+ }
+
+ public override async Task Select_nested_collection_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_nested_collection_on_required_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+ORDER BY "r"."Id"
+""");
+ }
+
+ public override async Task Select_root(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_root(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_property_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_property_on_required_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."RequiredRelated_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_property_on_optional_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_property_on_optional_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."OptionalRelated_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_value_type_property_on_null_related_throws(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_value_type_property_on_null_related_throws(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."OptionalRelated_Int"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_nullable_value_type_property_on_null_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_nullable_value_type_property_on_null_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."OptionalRelated_Int"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_optional_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_optional_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_required_nested_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_required_nested_on_required_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_optional_nested_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_optional_nested_on_required_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_required_nested_on_optional_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_required_nested_on_optional_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_optional_nested_on_optional_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_optional_nested_on_optional_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override async Task Select_required_related_via_optional_navigation(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_required_related_via_optional_navigation(queryTrackingBehavior);
+
+ AssertSql("""
+SELECT "r0"."RequiredRelated_Id", "r0"."RequiredRelated_Int", "r0"."RequiredRelated_Name", "r0"."RequiredRelated_String", "r0"."RequiredRelated_OptionalNested_Id", "r0"."RequiredRelated_OptionalNested_Int", "r0"."RequiredRelated_OptionalNested_Name", "r0"."RequiredRelated_OptionalNested_String", "r0"."RequiredRelated_RequiredNested_Id", "r0"."RequiredRelated_RequiredNested_Int", "r0"."RequiredRelated_RequiredNested_Name", "r0"."RequiredRelated_RequiredNested_String"
+FROM "RootReferencingEntity" AS "r"
+LEFT JOIN "RootEntity" AS "r0" ON "r"."RootEntityId" = "r0"."Id"
+""");
+ }
+
+ public override async Task Select_nested_collection_on_optional_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_nested_collection_on_optional_related(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+ORDER BY "r"."Id"
+""");
+ }
+
+ public override async Task SelectMany_related_collection(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.SelectMany_related_collection(queryTrackingBehavior);
+
+ AssertSql();
+ }
+
+ public override async Task SelectMany_nested_collection_on_required_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.SelectMany_nested_collection_on_required_related(queryTrackingBehavior);
+
+ AssertSql();
+ }
+
+ public override async Task SelectMany_nested_collection_on_optional_related(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.SelectMany_nested_collection_on_optional_related(queryTrackingBehavior);
+
+ AssertSql();
+ }
+
+ public override async Task Select_root_duplicated(QueryTrackingBehavior queryTrackingBehavior)
+ {
+ await base.Select_root_duplicated(queryTrackingBehavior);
+
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+""");
+ }
+
+ public override Task Select_subquery_required_related_FirstOrDefault(QueryTrackingBehavior queryTrackingBehavior)
+ => AssertApplyNotSupported(() => base.Select_subquery_required_related_FirstOrDefault(queryTrackingBehavior));
+
public override Task Select_subquery_optional_related_FirstOrDefault(QueryTrackingBehavior queryTrackingBehavior)
=> AssertApplyNotSupported(() => base.Select_subquery_optional_related_FirstOrDefault(queryTrackingBehavior));
+ [ConditionalFact]
+ public virtual void Check_all_tests_overridden()
+ => TestHelpers.AssertAllMethodsOverridden(GetType());
+
private static async Task AssertApplyNotSupported(Func query)
=> Assert.Equal(
SqliteStrings.ApplyNotSupported,
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqliteTest.cs
index ac1b0875b43..be0e7050262 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqliteTest.cs
@@ -12,42 +12,72 @@ public override async Task Two_related()
{
await base.Two_related();
- AssertSql();
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."RequiredRelated_Id" = "r"."OptionalRelated_Id" AND "r"."RequiredRelated_Int" = "r"."OptionalRelated_Int" AND "r"."RequiredRelated_Name" = "r"."OptionalRelated_Name" AND "r"."RequiredRelated_String" = "r"."OptionalRelated_String" AND ("r"."RequiredRelated_OptionalNested_Id" = "r"."RequiredRelated_OptionalNested_Id" OR "r"."RequiredRelated_OptionalNested_Id" IS NULL) AND ("r"."RequiredRelated_OptionalNested_Int" = "r"."RequiredRelated_OptionalNested_Int" OR "r"."RequiredRelated_OptionalNested_Int" IS NULL) AND ("r"."RequiredRelated_OptionalNested_Name" = "r"."RequiredRelated_OptionalNested_Name" OR "r"."RequiredRelated_OptionalNested_Name" IS NULL) AND ("r"."RequiredRelated_OptionalNested_String" = "r"."RequiredRelated_OptionalNested_String" OR "r"."RequiredRelated_OptionalNested_String" IS NULL) AND "r"."RequiredRelated_RequiredNested_Id" = "r"."RequiredRelated_RequiredNested_Id" AND "r"."RequiredRelated_RequiredNested_Int" = "r"."RequiredRelated_RequiredNested_Int" AND "r"."RequiredRelated_RequiredNested_Name" = "r"."RequiredRelated_RequiredNested_Name" AND "r"."RequiredRelated_RequiredNested_String" = "r"."RequiredRelated_RequiredNested_String"
+""");
}
public override async Task Two_nested()
{
await base.Two_nested();
- AssertSql();
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."RequiredRelated_RequiredNested_Id" = "r"."OptionalRelated_RequiredNested_Id" AND "r"."RequiredRelated_RequiredNested_Int" = "r"."OptionalRelated_RequiredNested_Int" AND "r"."RequiredRelated_RequiredNested_Name" = "r"."OptionalRelated_RequiredNested_Name" AND "r"."RequiredRelated_RequiredNested_String" = "r"."OptionalRelated_RequiredNested_String"
+""");
}
public override async Task Not_equals()
{
await base.Not_equals();
- AssertSql();
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."RequiredRelated_Id" <> "r"."OptionalRelated_Id" OR "r"."OptionalRelated_Id" IS NULL OR "r"."RequiredRelated_Int" <> "r"."OptionalRelated_Int" OR "r"."OptionalRelated_Int" IS NULL OR "r"."RequiredRelated_Name" <> "r"."OptionalRelated_Name" OR "r"."OptionalRelated_Name" IS NULL OR "r"."RequiredRelated_String" <> "r"."OptionalRelated_String" OR "r"."OptionalRelated_String" IS NULL OR (("r"."RequiredRelated_OptionalNested_Id" <> "r"."RequiredRelated_OptionalNested_Id" OR "r"."RequiredRelated_OptionalNested_Id" IS NULL) AND "r"."RequiredRelated_OptionalNested_Id" IS NOT NULL) OR (("r"."RequiredRelated_OptionalNested_Int" <> "r"."RequiredRelated_OptionalNested_Int" OR "r"."RequiredRelated_OptionalNested_Int" IS NULL) AND "r"."RequiredRelated_OptionalNested_Int" IS NOT NULL) OR (("r"."RequiredRelated_OptionalNested_Name" <> "r"."RequiredRelated_OptionalNested_Name" OR "r"."RequiredRelated_OptionalNested_Name" IS NULL) AND "r"."RequiredRelated_OptionalNested_Name" IS NOT NULL) OR (("r"."RequiredRelated_OptionalNested_String" <> "r"."RequiredRelated_OptionalNested_String" OR "r"."RequiredRelated_OptionalNested_String" IS NULL) AND "r"."RequiredRelated_OptionalNested_String" IS NOT NULL) OR "r"."RequiredRelated_RequiredNested_Id" <> "r"."RequiredRelated_RequiredNested_Id" OR "r"."RequiredRelated_RequiredNested_Id" IS NULL OR "r"."RequiredRelated_RequiredNested_Int" <> "r"."RequiredRelated_RequiredNested_Int" OR "r"."RequiredRelated_RequiredNested_Int" IS NULL OR "r"."RequiredRelated_RequiredNested_Name" <> "r"."RequiredRelated_RequiredNested_Name" OR "r"."RequiredRelated_RequiredNested_Name" IS NULL OR "r"."RequiredRelated_RequiredNested_String" <> "r"."RequiredRelated_RequiredNested_String" OR "r"."RequiredRelated_RequiredNested_String" IS NULL
+""");
}
public override async Task Related_with_inline_null()
{
await base.Related_with_inline_null();
- AssertSql();
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."OptionalRelated_Id" IS NULL AND "r"."OptionalRelated_Int" IS NULL AND "r"."OptionalRelated_Name" IS NULL AND "r"."OptionalRelated_String" IS NULL AND "r"."OptionalRelated_OptionalNested_Id" IS NULL AND "r"."OptionalRelated_OptionalNested_Int" IS NULL AND "r"."OptionalRelated_OptionalNested_Name" IS NULL AND "r"."OptionalRelated_OptionalNested_String" IS NULL AND "r"."OptionalRelated_RequiredNested_Id" IS NULL AND "r"."OptionalRelated_RequiredNested_Int" IS NULL AND "r"."OptionalRelated_RequiredNested_Name" IS NULL AND "r"."OptionalRelated_RequiredNested_String" IS NULL
+""");
}
public override async Task Related_with_parameter_null()
{
await base.Related_with_parameter_null();
- AssertSql();
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."OptionalRelated_Id" IS NULL AND "r"."OptionalRelated_Int" IS NULL AND "r"."OptionalRelated_Name" IS NULL AND "r"."OptionalRelated_String" IS NULL AND "r"."OptionalRelated_OptionalNested_Id" IS NULL AND "r"."OptionalRelated_OptionalNested_Int" IS NULL AND "r"."OptionalRelated_OptionalNested_Name" IS NULL AND "r"."OptionalRelated_OptionalNested_String" IS NULL AND "r"."OptionalRelated_RequiredNested_Id" IS NULL AND "r"."OptionalRelated_RequiredNested_Int" IS NULL AND "r"."OptionalRelated_RequiredNested_Name" IS NULL AND "r"."OptionalRelated_RequiredNested_String" IS NULL
+""");
}
public override async Task Nested_with_inline_null()
{
await base.Nested_with_inline_null();
- AssertSql();
+ AssertSql(
+ """
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+FROM "RootEntity" AS "r"
+WHERE "r"."RequiredRelated_OptionalNested_Id" IS NULL AND "r"."RequiredRelated_OptionalNested_Int" IS NULL AND "r"."RequiredRelated_OptionalNested_Name" IS NULL AND "r"."RequiredRelated_OptionalNested_String" IS NULL
+""");
}
public override async Task Nested_with_inline()
@@ -56,7 +86,7 @@ public override async Task Nested_with_inline()
AssertSql(
"""
-SELECT "r"."Id", "r"."Name", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
FROM "RootEntity" AS "r"
WHERE "r"."RequiredRelated_RequiredNested_Id" = 1000 AND "r"."RequiredRelated_RequiredNested_Int" = 8 AND "r"."RequiredRelated_RequiredNested_Name" = 'Root1_RequiredRelated_RequiredNested' AND "r"."RequiredRelated_RequiredNested_String" = 'foo'
""");
@@ -73,7 +103,7 @@ public override async Task Nested_with_parameter()
@entity_equality_nested_Name='?' (Size = 36)
@entity_equality_nested_String='?' (Size = 3)
-SELECT "r"."Id", "r"."Name", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
+SELECT "r"."Id", "r"."Name", "r"."OptionalRelated_Id", "r"."OptionalRelated_Int", "r"."OptionalRelated_Name", "r"."OptionalRelated_String", "r"."OptionalRelated_OptionalNested_Id", "r"."OptionalRelated_OptionalNested_Int", "r"."OptionalRelated_OptionalNested_Name", "r"."OptionalRelated_OptionalNested_String", "r"."OptionalRelated_RequiredNested_Id", "r"."OptionalRelated_RequiredNested_Int", "r"."OptionalRelated_RequiredNested_Name", "r"."OptionalRelated_RequiredNested_String", "r"."RequiredRelated_Id", "r"."RequiredRelated_Int", "r"."RequiredRelated_Name", "r"."RequiredRelated_String", "r"."RequiredRelated_OptionalNested_Id", "r"."RequiredRelated_OptionalNested_Int", "r"."RequiredRelated_OptionalNested_Name", "r"."RequiredRelated_OptionalNested_String", "r"."RequiredRelated_RequiredNested_Id", "r"."RequiredRelated_RequiredNested_Int", "r"."RequiredRelated_RequiredNested_Name", "r"."RequiredRelated_RequiredNested_String"
FROM "RootEntity" AS "r"
WHERE "r"."RequiredRelated_RequiredNested_Id" = @entity_equality_nested_Id AND "r"."RequiredRelated_RequiredNested_Int" = @entity_equality_nested_Int AND "r"."RequiredRelated_RequiredNested_Name" = @entity_equality_nested_Name AND "r"."RequiredRelated_RequiredNested_String" = @entity_equality_nested_String
""");
diff --git a/test/EFCore.Tests/Query/EntityMaterializerSourceTest.cs b/test/EFCore.Tests/Query/EntityMaterializerSourceTest.cs
index 4551fd36bd1..3b27f7be65b 100644
--- a/test/EFCore.Tests/Query/EntityMaterializerSourceTest.cs
+++ b/test/EFCore.Tests/Query/EntityMaterializerSourceTest.cs
@@ -26,7 +26,7 @@ public void Throws_for_abstract_types()
CoreStrings.CannotMaterializeAbstractType(nameof(SomeAbstractEntity)),
Assert.Throws(
() => source.CreateMaterializeExpression(
- new StructuralTypeMaterializerSourceParameters((IEntityType)entityType, "", null), null!))
+ new StructuralTypeMaterializerSourceParameters((IEntityType)entityType, "", null, null), null!))
.Message);
}
@@ -550,7 +550,7 @@ public virtual Func GetMaterializer(
IReadOnlyEntityType entityType)
=> Expression.Lambda>(
source.CreateMaterializeExpression(
- new StructuralTypeMaterializerSourceParameters((IEntityType)entityType, "instance", null),
+ new StructuralTypeMaterializerSourceParameters((IEntityType)entityType, "instance", null, null),
_contextParameter),
_contextParameter)
.Compile();