Skip to content

Commit 1ef0cd2

Browse files
committed
Query: Make keyless entity type materialization checks part of DiscriminatorCondition
If DiscriminatorCondition returns null for IEntityType then return null instance. Part of #18923
1 parent 707a67a commit 1ef0cd2

File tree

2 files changed

+39
-50
lines changed

2 files changed

+39
-50
lines changed

src/EFCore/Query/EntityShaperExpression.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,7 @@ protected EntityShaperExpression(
4545

4646
if (discriminatorCondition == null)
4747
{
48-
// Generate condition to discriminator if TPH
49-
discriminatorCondition = GenerateDiscriminatorCondition(entityType);
50-
48+
discriminatorCondition = GenerateDiscriminatorCondition(entityType, nullable);
5149
}
5250
else if (discriminatorCondition.Parameters.Count != 1
5351
|| discriminatorCondition.Parameters[0].Type != typeof(ValueBuffer)
@@ -63,11 +61,11 @@ protected EntityShaperExpression(
6361
DiscriminatorCondition = discriminatorCondition;
6462
}
6563

66-
private LambdaExpression GenerateDiscriminatorCondition(IEntityType entityType)
64+
private LambdaExpression GenerateDiscriminatorCondition(IEntityType entityType, bool nullable)
6765
{
6866
var valueBufferParameter = Parameter(typeof(ValueBuffer));
6967
Expression body;
70-
var concreteEntityTypes = entityType.GetConcreteDerivedTypesInclusive().ToList();
68+
var concreteEntityTypes = entityType.GetConcreteDerivedTypesInclusive().ToArray();
7169
var discriminatorProperty = entityType.GetDiscriminatorProperty();
7270
if (discriminatorProperty != null)
7371
{
@@ -80,8 +78,8 @@ private LambdaExpression GenerateDiscriminatorCondition(IEntityType entityType)
8078
discriminatorProperty.ClrType, discriminatorProperty.GetIndex(), discriminatorProperty))
8179
};
8280

83-
var switchCases = new SwitchCase[concreteEntityTypes.Count];
84-
for (var i = 0; i < concreteEntityTypes.Count; i++)
81+
var switchCases = new SwitchCase[concreteEntityTypes.Length];
82+
for (var i = 0; i < concreteEntityTypes.Length; i++)
8583
{
8684
var discriminatorValue = Constant(concreteEntityTypes[i].GetDiscriminatorValue(), discriminatorProperty.ClrType);
8785
switchCases[i] = SwitchCase(Constant(concreteEntityTypes[i], typeof(IEntityType)), discriminatorValue);
@@ -97,7 +95,20 @@ private LambdaExpression GenerateDiscriminatorCondition(IEntityType entityType)
9795
}
9896
else
9997
{
100-
body = Constant(concreteEntityTypes.Count == 1 ? concreteEntityTypes[0] : entityType, typeof(IEntityType));
98+
body = Constant(concreteEntityTypes.Length == 1 ? concreteEntityTypes[0] : entityType, typeof(IEntityType));
99+
}
100+
101+
if (entityType.FindPrimaryKey() == null
102+
&& nullable)
103+
{
104+
body = Condition(
105+
entityType.GetProperties()
106+
.Select(p => NotEqual(
107+
valueBufferParameter.CreateValueBufferReadValueExpression(typeof(object), p.GetIndex(), p),
108+
Constant(null)))
109+
.Aggregate((a, b) => OrElse(a, b)),
110+
body,
111+
Default(typeof(IEntityType)));
101112
}
102113

103114
return Lambda(body, valueBufferParameter);
@@ -128,7 +139,8 @@ public virtual EntityShaperExpression WithEntityType([NotNull] IEntityType entit
128139

129140
public virtual EntityShaperExpression MarkAsNullable()
130141
=> !IsNullable
131-
? new EntityShaperExpression(EntityType, ValueBufferExpression, true, DiscriminatorCondition)
142+
// Marking nullable requires recomputation of Discriminator condition
143+
? new EntityShaperExpression(EntityType, ValueBufferExpression, true)
132144
: this;
133145

134146
public virtual EntityShaperExpression Update([NotNull] Expression valueBufferExpression)

src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs

Lines changed: 18 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -414,29 +414,9 @@ private Expression ProcessEntityShaper(EntityShaperExpression entityShaperExpres
414414
}
415415
else
416416
{
417-
if (entityShaperExpression.IsNullable)
418-
{
419-
expressions.Add(
420-
Expression.IfThen(
421-
entityType.GetProperties()
422-
.Select(
423-
p =>
424-
Expression.NotEqual(
425-
valueBufferExpression.CreateValueBufferReadValueExpression(
426-
typeof(object),
427-
p.GetIndex(),
428-
p),
429-
Expression.Constant(null)))
430-
.Aggregate((a, b) => Expression.OrElse(a, b)),
431-
MaterializeEntity(
432-
entityShaperExpression, materializationContextVariable, concreteEntityTypeVariable, instanceVariable, null)));
433-
}
434-
else
435-
{
436-
expressions.Add(
437-
MaterializeEntity(
438-
entityShaperExpression, materializationContextVariable, concreteEntityTypeVariable, instanceVariable, null));
439-
}
417+
expressions.Add(
418+
MaterializeEntity(
419+
entityShaperExpression, materializationContextVariable, concreteEntityTypeVariable, instanceVariable, null));
440420
}
441421
}
442422

@@ -476,30 +456,27 @@ private Expression MaterializeEntity(
476456
valueBufferExpression,
477457
entityShaperExpression.DiscriminatorCondition.Body)));
478458

479-
var concreteEntityTypes = entityType.GetConcreteDerivedTypesInclusive().ToList();
459+
var concreteEntityTypes = entityType.GetConcreteDerivedTypesInclusive().ToArray();
480460
var discriminatorProperty = entityType.GetDiscriminatorProperty();
481-
if (discriminatorProperty != null)
461+
if (discriminatorProperty == null
462+
&& concreteEntityTypes.Length > 1)
482463
{
483-
var switchCases = new SwitchCase[concreteEntityTypes.Count];
484-
for (var i = 0; i < concreteEntityTypes.Count; i++)
485-
{
486-
switchCases[i] = Expression.SwitchCase(
487-
CreateFullMaterializeExpression(concreteEntityTypes[i], expressionContext),
488-
Expression.Constant(concreteEntityTypes[i], typeof(IEntityType)));
489-
}
490-
491-
materializationExpression = Expression.Switch(
492-
concreteEntityTypeVariable,
493-
Expression.Constant(null, returnType),
494-
switchCases);
464+
concreteEntityTypes = new [] { entityType };
495465
}
496-
else
466+
467+
var switchCases = new SwitchCase[concreteEntityTypes.Length];
468+
for (var i = 0; i < concreteEntityTypes.Length; i++)
497469
{
498-
materializationExpression = CreateFullMaterializeExpression(
499-
concreteEntityTypes.Count == 1 ? concreteEntityTypes[0] : entityType,
500-
expressionContext);
470+
switchCases[i] = Expression.SwitchCase(
471+
CreateFullMaterializeExpression(concreteEntityTypes[i], expressionContext),
472+
Expression.Constant(concreteEntityTypes[i], typeof(IEntityType)));
501473
}
502474

475+
materializationExpression = Expression.Switch(
476+
concreteEntityTypeVariable,
477+
Expression.Constant(null, returnType),
478+
switchCases);
479+
503480
expressions.Add(Expression.Assign(instanceVariable, materializationExpression));
504481

505482
if (_trackQueryResults

0 commit comments

Comments
 (0)