@@ -113,8 +113,10 @@ private static readonly MethodInfo CollectionAccessorAddMethodInfo
113
113
private readonly IDictionary < ParameterExpression , IDictionary < IProperty , int > > _materializationContextBindings
114
114
= new Dictionary < ParameterExpression , IDictionary < IProperty , int > > ( ) ;
115
115
116
- private readonly IDictionary < ParameterExpression , int > _entityTypeIdentifyingExpressionOffsets
117
- = new Dictionary < ParameterExpression , int > ( ) ;
116
+ private readonly IDictionary < ParameterExpression , object > _entityTypeIdentifyingExpressionInfo
117
+ = new Dictionary < ParameterExpression , object > ( ) ;
118
+ private readonly IDictionary < ProjectionBindingExpression , string > _singleEntityTypeDiscriminatorValues
119
+ = new Dictionary < ProjectionBindingExpression , string > ( ) ;
118
120
119
121
public ShaperProcessingExpressionVisitor (
120
122
RelationalShapedQueryCompilingExpressionVisitor parentVisitor ,
@@ -359,7 +361,13 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression)
359
361
360
362
var propertyMap = ( IDictionary < IProperty , int > ) GetProjectionIndex ( projectionBindingExpression ) ;
361
363
_materializationContextBindings [ parameterExpression ] = propertyMap ;
362
- _entityTypeIdentifyingExpressionOffsets [ parameterExpression ] = propertyMap . Values . Max ( ) + 1 ;
364
+ _entityTypeIdentifyingExpressionInfo [ parameterExpression ] =
365
+ // If single entity type is being selected in hierarchy then we use the value directly else we store the offset to
366
+ // read discriminator value.
367
+ _singleEntityTypeDiscriminatorValues . TryGetValue ( projectionBindingExpression , out var value )
368
+ ? value
369
+ : propertyMap . Values . Max ( ) + 1 ;
370
+
363
371
364
372
var updatedExpression = newExpression . Update (
365
373
new [ ] { Expression . Constant ( ValueBuffer . Empty ) , newExpression . Arguments [ 1 ] } ) ;
@@ -388,6 +396,16 @@ protected override Expression VisitExtension(Expression extensionExpression)
388
396
{
389
397
var entityParameter = Expression . Parameter ( entityShaperExpression . Type ) ;
390
398
_variables . Add ( entityParameter ) ;
399
+ if ( entityShaperExpression . EntityType . GetMappingStrategy ( ) == "TPC" )
400
+ {
401
+ var concreteTypes = entityShaperExpression . EntityType . GetDerivedTypesInclusive ( ) . Where ( e => ! e . IsAbstract ( ) ) . ToArray ( ) ;
402
+ // Single concrete TPC entity type won't have discriminator column.
403
+ // We store the value here and inject it directly rather than reading from server.
404
+ if ( concreteTypes . Length == 1 )
405
+ _singleEntityTypeDiscriminatorValues [ ( ProjectionBindingExpression ) entityShaperExpression . ValueBufferExpression ]
406
+ = concreteTypes [ 0 ] . ShortName ( ) ;
407
+ }
408
+
391
409
var entityMaterializationExpression = _parentVisitor . InjectEntityMaterializers ( entityShaperExpression ) ;
392
410
entityMaterializationExpression = Visit ( entityMaterializationExpression ) ;
393
411
@@ -867,12 +885,27 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
867
885
{
868
886
var property = methodCallExpression . Arguments [ 2 ] . GetConstantValue < IProperty ? > ( ) ;
869
887
var mappingParameter = ( ParameterExpression ) ( ( MethodCallExpression ) methodCallExpression . Arguments [ 0 ] ) . Object ! ;
870
- var projectionIndex = property == null
871
- ? _entityTypeIdentifyingExpressionOffsets [ mappingParameter ]
872
- + methodCallExpression . Arguments [ 1 ] . GetConstantValue < int > ( )
873
- : _materializationContextBindings [ mappingParameter ] [ property ] ;
874
- var projection = _selectExpression . Projection [ projectionIndex ] ;
888
+ int projectionIndex ;
889
+ if ( property == null )
890
+ {
891
+ // This is trying to read the computed discriminator value
892
+ var storedInfo = _entityTypeIdentifyingExpressionInfo [ mappingParameter ] ;
893
+ if ( storedInfo is string s )
894
+ {
895
+ // If the value is fixed then there is single entity type and discriminator is not present in query
896
+ // We just return the value as-is.
897
+ return Expression . Constant ( s ) ;
898
+ }
875
899
900
+ projectionIndex = ( int ) _entityTypeIdentifyingExpressionInfo [ mappingParameter ]
901
+ + methodCallExpression . Arguments [ 1 ] . GetConstantValue < int > ( ) ;
902
+ }
903
+ else
904
+ {
905
+ projectionIndex = _materializationContextBindings [ mappingParameter ] [ property ] ;
906
+ }
907
+
908
+ var projection = _selectExpression . Projection [ projectionIndex ] ;
876
909
var nullable = IsNullableProjection ( projection ) ;
877
910
878
911
Check . DebugAssert (
0 commit comments