@@ -45,7 +45,7 @@ public sealed partial class SelectExpression : TableExpressionBase
45
45
46
46
private readonly List < ( ColumnExpression Column , ValueComparer Comparer ) > _identifier = new ( ) ;
47
47
private readonly List < ( ColumnExpression Column , ValueComparer Comparer ) > _childIdentifiers = new ( ) ;
48
- private readonly List < int > _tptLeftJoinTables = new ( ) ;
48
+ private readonly List < int > _removableJoinTables = new ( ) ;
49
49
private readonly Dictionary < TpcTablesExpression , ( ColumnExpression , List < string > ) > _tpcDiscriminatorValues
50
50
= new ( ReferenceEqualityComparer . Instance ) ;
51
51
@@ -165,7 +165,7 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre
165
165
. Aggregate ( ( l , r ) => sqlExpressionFactory . AndAlso ( l , r ) ) ;
166
166
167
167
var joinExpression = new LeftJoinExpression ( tableExpression , joinPredicate ) ;
168
- _tptLeftJoinTables . Add ( _tables . Count ) ;
168
+ _removableJoinTables . Add ( _tables . Count ) ;
169
169
AddTable ( joinExpression , tableReferenceExpression ) ;
170
170
}
171
171
@@ -187,7 +187,7 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre
187
187
if ( entityTypes . Length == 1 )
188
188
{
189
189
// For single entity case, we don't need discriminator.
190
- var table = GetTableBase ( entityTypes [ 0 ] ) ;
190
+ var table = entityTypes [ 0 ] . GetViewOrTableMappings ( ) . Single ( ) . Table ;
191
191
var tableExpression = new TableExpression ( table ) ;
192
192
193
193
var tableReferenceExpression = new TableReferenceExpression ( this , tableExpression . Alias ! ) ;
@@ -212,7 +212,7 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre
212
212
}
213
213
else
214
214
{
215
- var tables = entityTypes . Select ( e => GetTableBase ( e ) ) . ToArray ( ) ;
215
+ var tables = entityTypes . Select ( e => e . GetViewOrTableMappings ( ) . Single ( ) . Table ) . ToArray ( ) ;
216
216
var properties = GetAllPropertiesInHierarchy ( entityType ) . ToArray ( ) ;
217
217
var propertyNamesMap = new Dictionary < IProperty , string > ( ) ;
218
218
for ( var i = 0 ; i < entityTypes . Length ; i ++ )
@@ -314,47 +314,106 @@ internal SelectExpression(IEntityType entityType, ISqlExpressionFactory sqlExpre
314
314
default :
315
315
{
316
316
// Also covers TPH
317
- ITableBase table ;
318
- TableExpressionBase tableExpression ;
319
317
if ( entityType . GetFunctionMappings ( ) . SingleOrDefault ( e => e . IsDefaultFunctionMapping ) is IFunctionMapping functionMapping )
320
318
{
321
319
var storeFunction = functionMapping . Table ;
322
320
323
- table = storeFunction ;
324
- tableExpression = new TableValuedFunctionExpression ( ( IStoreFunction ) storeFunction , Array . Empty < SqlExpression > ( ) ) ;
321
+ GenerateNonHierarchyNonSplittingEntityType (
322
+ storeFunction , new TableValuedFunctionExpression ( ( IStoreFunction ) storeFunction , Array . Empty < SqlExpression > ( ) ) ) ;
325
323
}
326
324
else
327
325
{
328
- table = GetTableBase ( entityType ) ;
329
- tableExpression = new TableExpression ( table ) ;
330
- }
326
+ var mappings = entityType . GetViewOrTableMappings ( ) . ToList ( ) ;
327
+ if ( mappings . Count == 1 )
328
+ {
329
+ var table = mappings [ 0 ] . Table ;
331
330
332
- var tableReferenceExpression = new TableReferenceExpression ( this , tableExpression . Alias ! ) ;
333
- AddTable ( tableExpression , tableReferenceExpression ) ;
331
+ GenerateNonHierarchyNonSplittingEntityType ( table , new TableExpression ( table ) ) ;
332
+ }
333
+ else
334
+ {
335
+ // table splitting
336
+ var keyProperties = entityType . FindPrimaryKey ( ) ! . Properties ;
337
+ List < ColumnExpression > joinColumns = default ! ;
338
+ var columns = new Dictionary < IProperty , ColumnExpression > ( ) ;
339
+ var tableReferenceExpressionMap = new Dictionary < ITableBase , TableReferenceExpression > ( ) ;
340
+ foreach ( var mapping in mappings )
341
+ {
342
+ var table = mapping . Table ;
343
+ var tableExpression = new TableExpression ( table ) ;
344
+ var tableReferenceExpression = new TableReferenceExpression ( this , tableExpression . Alias ) ;
345
+ tableReferenceExpressionMap [ table ] = tableReferenceExpression ;
334
346
335
- var propertyExpressions = new Dictionary < IProperty , ColumnExpression > ( ) ;
336
- foreach ( var property in GetAllPropertiesInHierarchy ( entityType ) )
337
- {
338
- propertyExpressions [ property ] = CreateColumnExpression ( property , table , tableReferenceExpression , nullable : false ) ;
339
- }
347
+ if ( _tables . Count == 0 )
348
+ {
349
+ AddTable ( tableExpression , tableReferenceExpression ) ;
350
+ joinColumns = new List < ColumnExpression > ( ) ;
351
+ foreach ( var property in keyProperties )
352
+ {
353
+ var columnExpression = CreateColumnExpression ( property , table , tableReferenceExpression , nullable : false ) ;
354
+ columns [ property ] = columnExpression ;
355
+ joinColumns . Add ( columnExpression ) ;
356
+ _identifier . Add ( ( columnExpression , property . GetKeyValueComparer ( ) ) ) ;
357
+ }
358
+ }
359
+ else
360
+ {
361
+ var innerColumns = keyProperties . Select (
362
+ p => CreateColumnExpression ( p , table , tableReferenceExpression , nullable : false ) ) ;
340
363
341
- var entityProjection = new EntityProjectionExpression ( entityType , propertyExpressions ) ;
342
- _projectionMapping [ new ProjectionMember ( ) ] = entityProjection ;
364
+ var joinPredicate = joinColumns . Zip ( innerColumns , ( l , r ) => sqlExpressionFactory . Equal ( l , r ) )
365
+ . Aggregate ( ( l , r ) => sqlExpressionFactory . AndAlso ( l , r ) ) ;
343
366
344
- var primaryKey = entityType . FindPrimaryKey ( ) ;
345
- if ( primaryKey != null )
346
- {
347
- foreach ( var property in primaryKey . Properties )
348
- {
349
- _identifier . Add ( ( propertyExpressions [ property ] , property . GetKeyValueComparer ( ) ) ) ;
367
+ var joinExpression = new InnerJoinExpression ( tableExpression , joinPredicate ) ;
368
+ _removableJoinTables . Add ( _tables . Count ) ;
369
+ AddTable ( joinExpression , tableReferenceExpression ) ;
370
+ }
371
+ }
372
+
373
+ foreach ( var property in entityType . GetProperties ( ) )
374
+ {
375
+ if ( property . IsPrimaryKey ( ) )
376
+ {
377
+ continue ;
378
+ }
379
+
380
+ var columnBase = mappings . Select ( e => e . Table . FindColumn ( property ) ) . First ( e => e != null ) ! ;
381
+ columns [ property ] = CreateColumnExpression (
382
+ property , columnBase , tableReferenceExpressionMap [ columnBase . Table ] , nullable : false ) ;
383
+ }
384
+
385
+ var entityProjection = new EntityProjectionExpression ( entityType , columns ) ;
386
+ _projectionMapping [ new ProjectionMember ( ) ] = entityProjection ;
350
387
}
351
388
}
352
389
}
353
390
354
391
break ;
355
392
}
356
393
357
- static ITableBase GetTableBase ( IEntityType entityType ) => entityType . GetViewOrTableMappings ( ) . Single ( ) . Table ;
394
+ void GenerateNonHierarchyNonSplittingEntityType ( ITableBase table , TableExpressionBase tableExpression )
395
+ {
396
+ var tableReferenceExpression = new TableReferenceExpression ( this , tableExpression . Alias ! ) ;
397
+ AddTable ( tableExpression , tableReferenceExpression ) ;
398
+
399
+ var propertyExpressions = new Dictionary < IProperty , ColumnExpression > ( ) ;
400
+ foreach ( var property in GetAllPropertiesInHierarchy ( entityType ) )
401
+ {
402
+ propertyExpressions [ property ] = CreateColumnExpression ( property , table , tableReferenceExpression , nullable : false ) ;
403
+ }
404
+
405
+ var entityProjection = new EntityProjectionExpression ( entityType , propertyExpressions ) ;
406
+ _projectionMapping [ new ProjectionMember ( ) ] = entityProjection ;
407
+
408
+ var primaryKey = entityType . FindPrimaryKey ( ) ;
409
+ if ( primaryKey != null )
410
+ {
411
+ foreach ( var property in primaryKey . Properties )
412
+ {
413
+ _identifier . Add ( ( propertyExpressions [ property ] , property . GetKeyValueComparer ( ) ) ) ;
414
+ }
415
+ }
416
+ }
358
417
359
418
static ITableBase GetTableBaseFiltered ( IEntityType entityType , List < ITableBase > existingTables )
360
419
=> entityType . GetViewOrTableMappings ( ) . Single ( m => ! existingTables . Contains ( m . Table ) ) . Table ;
@@ -1713,8 +1772,8 @@ private void ApplySetOperation(SetOperationType setOperationType, SelectExpressi
1713
1772
_projectionMapping . Clear ( ) ;
1714
1773
select1 . _identifier . AddRange ( _identifier ) ;
1715
1774
_identifier . Clear ( ) ;
1716
- select1 . _tptLeftJoinTables . AddRange ( _tptLeftJoinTables ) ;
1717
- _tptLeftJoinTables . Clear ( ) ;
1775
+ select1 . _removableJoinTables . AddRange ( _removableJoinTables ) ;
1776
+ _removableJoinTables . Clear ( ) ;
1718
1777
foreach ( var kvp in _tpcDiscriminatorValues )
1719
1778
{
1720
1779
select1 . _tpcDiscriminatorValues [ kvp . Key ] = kvp . Value ;
@@ -2902,8 +2961,8 @@ private SqlRemappingVisitor PushdownIntoSubqueryInternal()
2902
2961
Having = null ;
2903
2962
Offset = null ;
2904
2963
Limit = null ;
2905
- subquery . _tptLeftJoinTables . AddRange ( _tptLeftJoinTables ) ;
2906
- _tptLeftJoinTables . Clear ( ) ;
2964
+ subquery . _removableJoinTables . AddRange ( _removableJoinTables ) ;
2965
+ _removableJoinTables . Clear ( ) ;
2907
2966
foreach ( var kvp in _tpcDiscriminatorValues )
2908
2967
{
2909
2968
subquery . _tpcDiscriminatorValues [ kvp . Key ] = kvp . Value ;
@@ -3213,14 +3272,17 @@ private SelectExpression Prune(IReadOnlyCollection<string>? referencedColumns)
3213
3272
var columnExpressionFindingExpressionVisitor = new ColumnExpressionFindingExpressionVisitor ( ) ;
3214
3273
var columnsMap = columnExpressionFindingExpressionVisitor . FindColumns ( this ) ;
3215
3274
var removedTableCount = 0 ;
3275
+ // Start at 1 because we don't drop main table.
3276
+ // Dropping main table is more complex because other tables need to unwrap joins to be main
3216
3277
for ( var i = 0 ; i < _tables . Count ; i ++ )
3217
3278
{
3218
3279
var table = _tables [ i ] ;
3219
3280
var tableAlias = GetAliasFromTableExpressionBase ( table ) ;
3220
3281
if ( columnsMap [ tableAlias ] == null
3221
3282
&& ( table is LeftJoinExpression
3222
- || table is OuterApplyExpression )
3223
- && _tptLeftJoinTables ? . Contains ( i + removedTableCount ) == true )
3283
+ || table is OuterApplyExpression
3284
+ || table is InnerJoinExpression ) // This is only valid for removable join table which are from entity splitting
3285
+ && _removableJoinTables ? . Contains ( i + removedTableCount ) == true )
3224
3286
{
3225
3287
_tables . RemoveAt ( i ) ;
3226
3288
_tableReferences . RemoveAt ( i ) ;
@@ -3341,7 +3403,14 @@ private static ConcreteColumnExpression CreateColumnExpression(
3341
3403
ITableBase table ,
3342
3404
TableReferenceExpression tableExpression ,
3343
3405
bool nullable )
3344
- => new ( property , table . FindColumn ( property ) ! , tableExpression , nullable ) ;
3406
+ => CreateColumnExpression ( property , table . FindColumn ( property ) ! , tableExpression , nullable ) ;
3407
+
3408
+ private static ConcreteColumnExpression CreateColumnExpression (
3409
+ IProperty property ,
3410
+ IColumnBase columnBase ,
3411
+ TableReferenceExpression tableExpression ,
3412
+ bool nullable )
3413
+ => new ( property , columnBase , tableExpression , nullable ) ;
3345
3414
3346
3415
private ConcreteColumnExpression GenerateOuterColumn (
3347
3416
TableReferenceExpression tableReferenceExpression ,
@@ -3578,7 +3647,7 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
3578
3647
_usedAliases = _usedAliases ,
3579
3648
} ;
3580
3649
newSelectExpression . _mutable = false ;
3581
- newSelectExpression . _tptLeftJoinTables . AddRange ( _tptLeftJoinTables ) ;
3650
+ newSelectExpression . _removableJoinTables . AddRange ( _removableJoinTables ) ;
3582
3651
foreach ( var kvp in newTpcDiscriminatorValues )
3583
3652
{
3584
3653
newSelectExpression . _tpcDiscriminatorValues [ kvp . Key ] = kvp . Value ;
0 commit comments