diff --git a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs
index 35641457b6c..f33c85fd726 100644
--- a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs
+++ b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs
@@ -371,8 +371,13 @@ protected override Expression VisitExtension(Expression extensionExpression)
_projectionMapping[_projectionMembers.Peek()] = projection;
- return shaper.Update(
- new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), typeof(ValueBuffer)));
+ return shaper
+ .Update(new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), typeof(ValueBuffer)))
+#pragma warning disable EF1001
+ // This is to handle have correct type for the shaper expression. It is later fixed in MatchTypes.
+ // This mirrors for structural types what we do for scalars.
+ .MakeClrTypeNullable();
+#pragma warning restore EF1001
}
case IncludeExpression includeExpression:
@@ -658,7 +663,14 @@ private static Expression MatchTypes(Expression expression, Type targetType)
targetType.MakeNullable() == expression.Type,
$"expression has type {expression.Type.Name}, but must be nullable over {targetType.Name}");
- expression = Expression.Convert(expression, targetType);
+ return expression switch
+ {
+#pragma warning disable EF1001
+ RelationalStructuralTypeShaperExpression structuralShaper => structuralShaper.MakeClrTypeNonNullable(),
+#pragma warning restore EF1001
+
+ _ => Expression.Convert(expression, targetType),
+ };
}
return expression;
diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs
index 3429b624107..9d8f54903b9 100644
--- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs
+++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.StructuralEquality.cs
@@ -333,12 +333,12 @@ bool TryRewriteComplexTypeEquality(bool collection, [NotNullWhen(true)] out SqlE
// into complex properties to generate a flattened list of comparisons.
// The moment we reach a a complex property that's mapped to JSON, we stop and generate a single comparison
// for the whole complex type.
- bool TryGenerateComparisons(
- IComplexType type,
- Expression left,
- Expression right,
- [NotNullWhen(true)] ref SqlExpression? comparisons)
+ bool TryGenerateComparisons(IComplexType complexType, Expression left, Expression right, [NotNullWhen(true)] ref SqlExpression? comparisons)
+ => TryGenerateComparisonsRec(complexType, left, right, ref comparisons, out _);
+ bool TryGenerateComparisonsRec(IComplexType type, Expression left, Expression right, [NotNullWhen(true)] ref SqlExpression? comparisons, out bool exitImmediately)
{
+ exitImmediately = false;
+
if (type.IsMappedToJson())
{
var leftScalar = Process(left);
@@ -418,6 +418,17 @@ SqlParameterExpression parameter
{
var comparison = _sqlExpressionFactory.MakeBinary(nodeType, leftTranslation, rightTranslation, boolTypeMapping)!;
+ // If we have a required property and one of the sides is a constant null,
+ // we can use just that property and skip comparing the rest of properties.
+ if (!property.IsNullable
+ && (leftTranslation is SqlConstantExpression { Value: null }
+ || rightTranslation is SqlConstantExpression { Value: null }))
+ {
+ comparisons = comparison;
+ exitImmediately = true;
+ return true;
+ }
+
comparisons = comparisons is null
? comparison
: nodeType == ExpressionType.Equal
@@ -447,10 +458,15 @@ SqlParameterExpression parameter
if (nestedLeft is null
|| nestedRight is null
- || !TryGenerateComparisons(complexProperty.ComplexType, nestedLeft, nestedRight, ref comparisons))
+ || !TryGenerateComparisonsRec(complexProperty.ComplexType, nestedLeft, nestedRight, ref comparisons, out exitImmediately))
{
return false;
}
+
+ if (exitImmediately)
+ {
+ return true;
+ }
}
return comparisons is not null;
diff --git a/src/EFCore.Relational/Query/RelationalStructuralTypeShaperExpression.cs b/src/EFCore.Relational/Query/RelationalStructuralTypeShaperExpression.cs
index 8fd0aede428..6f8d765dc9b 100644
--- a/src/EFCore.Relational/Query/RelationalStructuralTypeShaperExpression.cs
+++ b/src/EFCore.Relational/Query/RelationalStructuralTypeShaperExpression.cs
@@ -24,7 +24,7 @@ public class RelationalStructuralTypeShaperExpression : StructuralTypeShaperExpr
/// An expression of ValueBuffer to get values for properties of the entity.
/// A bool value indicating whether this entity instance can be null.
public RelationalStructuralTypeShaperExpression(ITypeBase structuralType, Expression valueBufferExpression, bool nullable)
- : base(structuralType, valueBufferExpression, nullable, materializationCondition: null)
+ : base(structuralType, valueBufferExpression, nullable)
{
}
@@ -38,12 +38,14 @@ public RelationalStructuralTypeShaperExpression(ITypeBase structuralType, Expres
/// An expression of to determine which entity type to
/// materialize.
///
+ /// CLR type for this expression as returned from .
protected RelationalStructuralTypeShaperExpression(
ITypeBase type,
Expression valueBufferExpression,
bool nullable,
- LambdaExpression? materializationCondition)
- : base(type, valueBufferExpression, nullable, materializationCondition)
+ LambdaExpression? materializationCondition,
+ Type clrType)
+ : base(type, valueBufferExpression, nullable, materializationCondition, clrType)
{
}
@@ -149,7 +151,7 @@ protected override LambdaExpression GenerateMaterializationCondition(ITypeBase t
///
public override StructuralTypeShaperExpression WithType(ITypeBase type)
=> type != StructuralType
- ? new RelationalStructuralTypeShaperExpression(type, ValueBufferExpression, IsNullable)
+ ? new RelationalStructuralTypeShaperExpression(type, ValueBufferExpression, IsNullable, materializationCondition: null, type.ClrType)
: this;
///
@@ -175,12 +177,24 @@ public override StructuralTypeShaperExpression MakeNullable(bool nullable = true
}
// Marking nullable requires re-computation of Discriminator condition
- return new RelationalStructuralTypeShaperExpression(StructuralType, newValueBufferExpression, true);
+ return new RelationalStructuralTypeShaperExpression(StructuralType, newValueBufferExpression, true, materializationCondition: null, Type);
}
///
public override StructuralTypeShaperExpression Update(Expression valueBufferExpression)
=> valueBufferExpression != ValueBufferExpression
- ? new RelationalStructuralTypeShaperExpression(StructuralType, valueBufferExpression, IsNullable, MaterializationCondition)
+ ? new RelationalStructuralTypeShaperExpression(StructuralType, valueBufferExpression, IsNullable, MaterializationCondition, Type)
+ : this;
+
+ ///
+ public override StructuralTypeShaperExpression MakeClrTypeNullable()
+ => Type != Type.MakeNullable()
+ ? new RelationalStructuralTypeShaperExpression(StructuralType, ValueBufferExpression, IsNullable, MaterializationCondition, Type.MakeNullable())
+ : this;
+
+ ///
+ public override StructuralTypeShaperExpression MakeClrTypeNonNullable()
+ => Type != Type.UnwrapNullableType()
+ ? new RelationalStructuralTypeShaperExpression(StructuralType, ValueBufferExpression, IsNullable, MaterializationCondition, Type.UnwrapNullableType())
: this;
}
diff --git a/src/EFCore/Query/EntityMaterializerSourceParameters.cs b/src/EFCore/Query/EntityMaterializerSourceParameters.cs
index 659e5606bbc..95750d7da96 100644
--- a/src/EFCore/Query/EntityMaterializerSourceParameters.cs
+++ b/src/EFCore/Query/EntityMaterializerSourceParameters.cs
@@ -8,14 +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.
+/// CLR type of the result.
///
/// The query tracking behavior, or if this materialization is not from a query.
///
public readonly record struct StructuralTypeMaterializerSourceParameters(
ITypeBase StructuralType,
string InstanceName,
- bool? AllowNullable,
+ Type ClrType,
QueryTrackingBehavior? QueryTrackingBehavior);
///
diff --git a/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs b/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs
index 040ac24b656..3154069780a 100644
--- a/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs
+++ b/src/EFCore/Query/Internal/StructuralTypeMaterializerSource.cs
@@ -95,38 +95,70 @@ public Expression CreateMaterializeExpression(
properties.Remove(consumedProperty);
}
- var materializationExpression = HandleMaterializationInterception();
+ var constructorExpression = constructorBinding.CreateConstructorExpression(bindingInfo);
+ var getValueBufferExpression = Call(bindingInfo.MaterializationContextExpression, MaterializationContext.GetValueBufferMethod);
+ var materializationExpression = _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, getValueBufferExpression, properties, bindingInfo)
+ : CreateInterceptionMaterializeExpression(
+ structuralType,
+ properties,
+ _materializationInterceptor,
+ bindingInfo,
+ constructorExpression,
+ getValueBufferExpression,
+ instanceVariable,
+ blockExpressions);
- return
- structuralType is IComplexType complexType
+ return structuralType is IComplexType complexType
&& ReadComplexTypeDirectly(complexType)
- && (IsNullable(complexType) || parameters.AllowNullable == true)
- ? HandleNullableComplexTypeMaterialization(
- complexType,
- complexType.ClrType,
- materializationExpression,
- bindingInfo)
- : materializationExpression;
-
- Expression HandleMaterializationInterception()
+ && parameters.ClrType.IsNullableType()
+ ? HandleNullableComplexTypeMaterialization(
+ complexType,
+ parameters.ClrType,
+ materializationExpression,
+ getValueBufferExpression)
+ : materializationExpression;
+
+ // Creates a conditional expression that handles materialization of nullable complex types.
+ // For nullable complex types, the method checks if all scalar properties are null
+ // and returns default if they are, otherwise materializes the complex type instance.
+ // If there's a required (non-nullable) property, only that property is checked for efficiency.
+ Expression HandleNullableComplexTypeMaterialization(
+ IComplexType complexType,
+ Type clrType,
+ Expression materializeExpression,
+ MethodCallExpression getValueBufferExpression)
{
- 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);
+ // Get all scalar properties of the complex type (including nested ones).
+ var allScalarProperties = complexType.GetFlattenedProperties().ToList();
+
+ 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(
+ getValueBufferExpression.CreateValueBufferReadValueExpression(typeof(object), requiredProperty.GetIndex(), requiredProperty),
+ Constant(null, typeof(object)))
+ // Create null checks for all scalar properties.
+ : allScalarProperties
+ .Select(p =>
+ Equal(
+ getValueBufferExpression.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),
+ // Materialization expression is always returning a non-nullable type, so we need to convert it to nullable if necessary.
+ clrType.IsNullableType()
+ ? Convert(materializeExpression, clrType)
+ : materializeExpression);
}
}
@@ -147,7 +179,7 @@ protected virtual void AddInitializeExpression(
IPropertyBase property,
ParameterBindingInfo bindingInfo,
Expression instanceVariable,
- MethodCallExpression valueBufferExpression,
+ MethodCallExpression getValueBufferExpression,
List blockExpressions)
{
if (property is IComplexProperty cp && !ReadComplexTypeDirectly(cp.ComplexType))
@@ -160,7 +192,7 @@ protected virtual void AddInitializeExpression(
var valueExpression = property switch
{
IProperty p
- => valueBufferExpression.CreateValueBufferReadValueExpression(memberInfo.GetMemberType(), p.GetIndex(), p),
+ => getValueBufferExpression.CreateValueBufferReadValueExpression(memberInfo.GetMemberType(), p.GetIndex(), p),
IServiceProperty serviceProperty
=> serviceProperty.ParameterBinding.BindToParameter(bindingInfo),
@@ -169,7 +201,9 @@ IServiceProperty serviceProperty
=> Default(complexProperty.ClrType), // Initialize collections to null, they'll be populated separately
IComplexProperty complexProperty
- => CreateComplexTypeMaterializeExpression(complexProperty, bindingInfo),
+ => CreateMaterializeExpression(
+ new StructuralTypeMaterializerSourceParameters(complexProperty.ComplexType, "complexType", complexProperty.ClrType, QueryTrackingBehavior: null),
+ bindingInfo.MaterializationContextExpression),
_ => throw new UnreachableException()
};
@@ -217,37 +251,18 @@ 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(
HashSet properties,
ParameterBindingInfo bindingInfo,
Expression instanceVariable,
+ MethodCallExpression getValueBufferExpression,
List blockExpressions)
{
- var valueBufferExpression = Call(
- bindingInfo.MaterializationContextExpression,
- MaterializationContext.GetValueBufferMethod);
-
foreach (var property in properties)
{
- AddInitializeExpression(property, bindingInfo, instanceVariable, valueBufferExpression, blockExpressions);
+ AddInitializeExpression(property, bindingInfo, instanceVariable, getValueBufferExpression, blockExpressions);
}
}
@@ -333,12 +348,13 @@ private Expression CreateMaterializeExpression(
List blockExpressions,
ParameterExpression instanceVariable,
Expression constructorExpression,
+ MethodCallExpression getValueBufferExpression,
HashSet properties,
ParameterBindingInfo bindingInfo)
{
blockExpressions.Add(Assign(instanceVariable, constructorExpression));
- AddInitializeExpressions(properties, bindingInfo, instanceVariable, blockExpressions);
+ AddInitializeExpressions(properties, bindingInfo, instanceVariable, getValueBufferExpression, blockExpressions);
if (bindingInfo.StructuralType is IEntityType)
{
@@ -356,6 +372,7 @@ private Expression CreateInterceptionMaterializeExpression(
IMaterializationInterceptor materializationInterceptor,
ParameterBindingInfo bindingInfo,
Expression constructorExpression,
+ MethodCallExpression getValueBufferExpression,
ParameterExpression instanceVariable,
List blockExpressions)
{
@@ -460,8 +477,6 @@ BlockExpression CreateAccessorDictionaryExpression()
{
var dictionaryVariable = Variable(
typeof(Dictionary)>), "dictionary");
- var valueBufferExpression = Call(
- bindingInfo.MaterializationContextExpression, MaterializationContext.GetValueBufferMethod);
var snapshotBlockExpressions = new List
{
Assign(
@@ -495,12 +510,12 @@ Expression CreateAccessorReadExpression()
? serviceProperty.ParameterBinding.BindToParameter(bindingInfo)
: (property as IProperty)?.IsPrimaryKey() == true
? Convert(
- valueBufferExpression.CreateValueBufferReadValueExpression(
+ getValueBufferExpression.CreateValueBufferReadValueExpression(
typeof(object),
property.GetIndex(),
property),
property.ClrType)
- : valueBufferExpression.CreateValueBufferReadValueExpression(
+ : getValueBufferExpression.CreateValueBufferReadValueExpression(
property.ClrType,
property.GetIndex(),
property);
@@ -516,7 +531,7 @@ BlockExpression CreateInitializeExpression()
{
var initializeBlockExpressions = new List();
- AddInitializeExpressions(properties, bindingInfo, instanceVariable, initializeBlockExpressions);
+ AddInitializeExpressions(properties, bindingInfo, instanceVariable, getValueBufferExpression, initializeBlockExpressions);
if (bindingInfo.StructuralType is IEntityType)
{
@@ -540,7 +555,7 @@ var materializationContextParameter
return Lambda>(
((IStructuralTypeMaterializerSource)this).CreateMaterializeExpression(
- new StructuralTypeMaterializerSourceParameters(entityType, "instance", null, null), materializationContextParameter),
+ new StructuralTypeMaterializerSourceParameters(entityType, "instance", entityType.ClrType, null), materializationContextParameter),
materializationContextParameter)
.Compile();
}
@@ -557,7 +572,7 @@ public virtual Func GetMaterializer(IComplexType
return Lambda>(
((IStructuralTypeMaterializerSource)this).CreateMaterializeExpression(
- new StructuralTypeMaterializerSourceParameters(complexType, "instance", null, null), materializationContextParameter),
+ new StructuralTypeMaterializerSourceParameters(complexType, "instance", complexType.ClrType, null), materializationContextParameter),
materializationContextParameter)
.Compile();
}
@@ -605,15 +620,13 @@ public virtual Func GetEmptyMaterializer(IComple
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
public virtual Func GetEmptyMaterializer(
- ITypeBase entityType,
- InstantiationBinding binding,
- List serviceProperties)
+ ITypeBase entityType, InstantiationBinding binding, List serviceProperties)
{
binding = ModifyBindings(entityType, binding);
var materializationContextExpression = Parameter(typeof(MaterializationContext), "mc");
var bindingInfo = new ParameterBindingInfo(
- new StructuralTypeMaterializerSourceParameters(entityType, "instance", null, null), materializationContextExpression);
+ new StructuralTypeMaterializerSourceParameters(entityType, "instance", entityType.ClrType, null), materializationContextExpression);
var blockExpressions = new List();
var instanceVariable = Variable(binding.RuntimeType, "instance");
@@ -622,6 +635,7 @@ public virtual Func GetEmptyMaterializer(
CreateServiceInstances(binding, bindingInfo, blockExpressions, serviceProperties);
var constructorExpression = binding.CreateConstructorExpression(bindingInfo);
+ var getValueBufferExpression = Call(bindingInfo.MaterializationContextExpression, MaterializationContext.GetValueBufferMethod);
var properties = new HashSet(serviceProperties);
foreach (var consumedProperty in binding.ParameterBindings.SelectMany(p => p.ConsumedProperties))
@@ -634,13 +648,14 @@ public virtual Func GetEmptyMaterializer(
? properties.Count == 0 && blockExpressions.Count == 0
? constructorExpression
: CreateMaterializeExpression(
- blockExpressions, instanceVariable, constructorExpression, properties, bindingInfo)
+ blockExpressions, instanceVariable, constructorExpression, getValueBufferExpression, properties, bindingInfo)
: CreateInterceptionMaterializeExpression(
entityType,
[],
_materializationInterceptor,
bindingInfo,
constructorExpression,
+ getValueBufferExpression,
instanceVariable,
blockExpressions),
materializationContextExpression)
@@ -686,48 +701,6 @@ 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);
diff --git a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
index 1fa5bffdcd3..b9a3fe4b0c9 100644
--- a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
+++ b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs
@@ -449,7 +449,7 @@ private Expression ProcessStructuralTypeShaper(StructuralTypeShaperExpression sh
var variables = new List();
var typeBase = shaper.StructuralType;
- var clrType = typeBase.ClrType;
+ var clrType = shaper.Type;
var materializationContextVariable = Variable(
typeof(MaterializationContext),
@@ -634,7 +634,7 @@ private Expression MaterializeEntity(
typeof(ISnapshot))
: Constant(Snapshot.Empty, typeof(ISnapshot))));
- var returnType = structuralType.ClrType;
+ var returnType = shaper.Type;
var valueBufferExpression = Call(materializationContextVariable, MaterializationContext.GetValueBufferMethod);
var materializationConditionBody = ReplacingExpressionVisitor.Replace(
@@ -654,7 +654,7 @@ private Expression MaterializeEntity(
{
var concreteStructuralType = concreteStructuralTypes[i];
switchCases[i] = SwitchCase(
- CreateFullMaterializeExpression(concreteStructuralTypes[i], shaper.IsNullable, expressionContext),
+ CreateFullMaterializeExpression(concreteStructuralTypes[i], expressionContext),
supportsPrecompiledQuery
? liftableConstantFactory.CreateLiftableConstant(
concreteStructuralTypes[i],
@@ -707,7 +707,6 @@ private Expression MaterializeEntity(
private BlockExpression CreateFullMaterializeExpression(
ITypeBase concreteStructuralType,
- bool shaperIsNullable,
(Type ReturnType,
ParameterExpression MaterializationContextVariable,
ParameterExpression ConcreteEntityTypeVariable,
@@ -723,7 +722,7 @@ private BlockExpression CreateFullMaterializeExpression(
var materializer = materializerSource
.CreateMaterializeExpression(
new StructuralTypeMaterializerSourceParameters(
- concreteStructuralType, "instance", shaperIsNullable, queryTrackingBehavior), materializationContextVariable);
+ concreteStructuralType, "instance", returnType, queryTrackingBehavior), materializationContextVariable);
// TODO: Properly support shadow properties for complex types #35613
if (_queryStateManager
diff --git a/src/EFCore/Query/StructuralTypeShaperExpression.cs b/src/EFCore/Query/StructuralTypeShaperExpression.cs
index 03006addc9d..5098634f810 100644
--- a/src/EFCore/Query/StructuralTypeShaperExpression.cs
+++ b/src/EFCore/Query/StructuralTypeShaperExpression.cs
@@ -26,6 +26,8 @@ private static readonly MethodInfo CreateUnableToDiscriminateExceptionMethod
private static readonly MethodInfo GetDiscriminatorValueMethod
= typeof(IReadOnlyTypeBase).GetMethod(nameof(IReadOnlyTypeBase.GetDiscriminatorValue))!;
+ private readonly Type _clrType;
+
///
/// 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
@@ -46,7 +48,7 @@ public StructuralTypeShaperExpression(
ITypeBase type,
Expression valueBufferExpression,
bool nullable)
- : this(type, valueBufferExpression, nullable, null)
+ : this(type, valueBufferExpression, nullable, null, type.ClrType)
{
}
@@ -59,11 +61,13 @@ public StructuralTypeShaperExpression(
///
/// An expression of to determine which structural type to materialize.
///
+ /// CLR type for this expression as returned from .
protected StructuralTypeShaperExpression(
ITypeBase type,
Expression valueBufferExpression,
bool nullable,
- LambdaExpression? materializationCondition)
+ LambdaExpression? materializationCondition,
+ Type clrType)
{
if (materializationCondition == null)
{
@@ -80,6 +84,9 @@ protected StructuralTypeShaperExpression(
ValueBufferExpression = valueBufferExpression;
IsNullable = nullable;
MaterializationCondition = materializationCondition!;
+ Check.DebugAssert(clrType == StructuralType.ClrType || clrType == StructuralType.ClrType.MakeNullable(),
+ $"The CLR type '{clrType}' must be equal to the structural type '{StructuralType.ClrType}' or a nullable version of it.");
+ _clrType = clrType;
}
///
@@ -235,7 +242,7 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
/// This expression if the type was not changed, or a new expression with the updated type.
public virtual StructuralTypeShaperExpression WithType(ITypeBase type)
=> type != StructuralType
- ? new StructuralTypeShaperExpression(type, ValueBufferExpression, IsNullable, materializationCondition: null)
+ ? new StructuralTypeShaperExpression(type, ValueBufferExpression, IsNullable, materializationCondition: null, type.ClrType)
: this;
///
@@ -246,7 +253,7 @@ public virtual StructuralTypeShaperExpression WithType(ITypeBase type)
public virtual StructuralTypeShaperExpression MakeNullable(bool nullable = true)
=> IsNullable != nullable
// Marking nullable requires re-computation of materialization condition
- ? new StructuralTypeShaperExpression(StructuralType, ValueBufferExpression, nullable, materializationCondition: null)
+ ? new StructuralTypeShaperExpression(StructuralType, ValueBufferExpression, nullable, materializationCondition: null, Type)
: this;
///
@@ -257,12 +264,30 @@ public virtual StructuralTypeShaperExpression MakeNullable(bool nullable = true)
/// This expression if no children changed, or an expression with the updated children.
public virtual StructuralTypeShaperExpression Update(Expression valueBufferExpression)
=> valueBufferExpression != ValueBufferExpression
- ? new StructuralTypeShaperExpression(StructuralType, valueBufferExpression, IsNullable, MaterializationCondition)
+ ? new StructuralTypeShaperExpression(StructuralType, valueBufferExpression, IsNullable, MaterializationCondition, Type)
: this;
///
public override Type Type
- => StructuralType.ClrType;
+ => _clrType;
+
+ ///
+ /// Changes the of this expression to be nullable.
+ ///
+ [EntityFrameworkInternal]
+ public virtual StructuralTypeShaperExpression MakeClrTypeNullable()
+ => Type != Type.MakeNullable()
+ ? new StructuralTypeShaperExpression(StructuralType, ValueBufferExpression, IsNullable, MaterializationCondition, Type.MakeNullable())
+ : this;
+
+ ///
+ /// Changes the of this expression to be non nullable.
+ ///
+ [EntityFrameworkInternal]
+ public virtual StructuralTypeShaperExpression MakeClrTypeNonNullable()
+ => Type != Type.UnwrapNullableType()
+ ? new StructuralTypeShaperExpression(StructuralType, ValueBufferExpression, IsNullable, MaterializationCondition, Type.UnwrapNullableType())
+ : this;
///
public sealed override ExpressionType NodeType
diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionCosmosTest.cs
index c83866193b0..74e5f4ff677 100644
--- a/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionCosmosTest.cs
+++ b/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsProjectionCosmosTest.cs
@@ -190,9 +190,9 @@ 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);
+ // We don't support (inter-document) navigations with Cosmos.
+ => Assert.ThrowsAsync(() => base.Select_required_related_via_optional_navigation(queryTrackingBehavior));
#endregion Non-collection
diff --git a/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
index 02543feb6b2..23062c6dc78 100644
--- a/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
@@ -297,6 +297,12 @@ public virtual Task Project_struct_complex_type_via_optional_navigation(bool asy
ss => ss.Set().Select(cg => cg.OptionalCustomer!.ShippingAddress),
ss => ss.Set().Select(cg => cg.OptionalCustomer != null ? cg.OptionalCustomer.ShippingAddress : default));
+ [ConditionalTheory, MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_nullable_struct_complex_type_via_optional_navigation(bool async)
+ => AssertQuery(
+ async,
+ ss => ss.Set().Select(cg => cg.OptionalCustomer != null ? cg.OptionalCustomer.ShippingAddress : (AddressStruct?)null));
+
[ConditionalTheory, MemberData(nameof(IsAsyncData))]
public virtual Task Project_struct_complex_type_via_required_navigation(bool async)
=> AssertQuery(
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
index 7b31606e0e9..fb794096cae 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
@@ -483,6 +483,18 @@ FROM [ValuedCustomerGroup] AS [v]
""");
}
+ public override async Task Project_nullable_struct_complex_type_via_optional_navigation(bool async)
+ {
+ await base.Project_nullable_struct_complex_type_via_optional_navigation(async);
+
+ 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)
{
await base.Project_struct_complex_type_via_required_navigation(async);
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqlServerTest.cs
index bc12ee0ef53..dc2c4c98ed2 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqlServerTest.cs
@@ -52,7 +52,7 @@ public override async Task Related_with_inline_null()
"""
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
+WHERE [r].[OptionalRelated_Id] IS NULL
""");
}
@@ -76,7 +76,7 @@ public override async Task Nested_with_inline_null()
"""
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
+WHERE [r].[RequiredRelated_OptionalNested_Id] IS NULL
""");
}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
index 7a9a221c9a7..3d93abac753 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
@@ -483,6 +483,18 @@ public override async Task Project_struct_complex_type_via_optional_navigation(b
""");
}
+ public override async Task Project_nullable_struct_complex_type_via_optional_navigation(bool async)
+ {
+ await base.Project_nullable_struct_complex_type_via_optional_navigation(async);
+
+ 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)
{
await base.Project_struct_complex_type_via_required_navigation(async);
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqliteTest.cs
index 92dcd0cebf5..5a74e7598ea 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqliteTest.cs
@@ -7,44 +7,5 @@ public class ComplexTableSplittingMiscellaneousSqliteTest(
ComplexTableSplittingSqliteFixture fixture,
ITestOutputHelper 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 c9ad7ff74b5..bb68fa057be 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingProjectionSqliteTest.cs
@@ -8,216 +8,12 @@ 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 be0e7050262..8fab931eb9e 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexTableSplitting/ComplexTableSplittingStructuralEqualitySqliteTest.cs
@@ -8,129 +8,4 @@ public class ComplexTableSplittingStructuralEqualitySqliteTest(
ITestOutputHelper testOutputHelper)
: ComplexTableSplittingStructuralEqualityRelationalTestBase(fixture, testOutputHelper)
{
- public override async Task Two_related()
- {
- await base.Two_related();
-
- 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(
- """
-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(
- """
-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(
- """
-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(
- """
-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(
- """
-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()
- {
- await base.Nested_with_inline();
-
- 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" = 1000 AND "r"."RequiredRelated_RequiredNested_Int" = 8 AND "r"."RequiredRelated_RequiredNested_Name" = 'Root1_RequiredRelated_RequiredNested' AND "r"."RequiredRelated_RequiredNested_String" = 'foo'
-""");
- }
-
- public override async Task Nested_with_parameter()
- {
- await base.Nested_with_parameter();
-
- AssertSql(
- """
-@entity_equality_nested_Id='?' (DbType = Int32)
-@entity_equality_nested_Int='?' (DbType = Int32)
-@entity_equality_nested_Name='?' (Size = 36)
-@entity_equality_nested_String='?' (Size = 3)
-
-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
-""");
- }
-
- public override async Task Two_nested_collections()
- {
- await base.Two_nested_collections();
-
- AssertSql();
- }
-
- public override async Task Nested_collection_with_inline()
- {
- await base.Nested_collection_with_inline();
-
- AssertSql();
- }
-
- public override async Task Nested_collection_with_parameter()
- {
- await base.Nested_collection_with_parameter();
-
- AssertSql();
- }
-
- [ConditionalFact]
- public virtual void Check_all_tests_overridden()
- => TestHelpers.AssertAllMethodsOverridden(GetType());
}
diff --git a/test/EFCore.Tests/Query/EntityMaterializerSourceTest.cs b/test/EFCore.Tests/Query/EntityMaterializerSourceTest.cs
index 3b27f7be65b..1afef984c26 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), null!))
+ new StructuralTypeMaterializerSourceParameters((IEntityType)entityType, "", entityType.ClrType, null), null!))
.Message);
}
@@ -550,7 +550,7 @@ public virtual Func GetMaterializer(
IReadOnlyEntityType entityType)
=> Expression.Lambda>(
source.CreateMaterializeExpression(
- new StructuralTypeMaterializerSourceParameters((IEntityType)entityType, "instance", null, null),
+ new StructuralTypeMaterializerSourceParameters((IEntityType)entityType, "instance", entityType.ClrType, null),
_contextParameter),
_contextParameter)
.Compile();