@@ -15,6 +15,8 @@ namespace NHibernate.Loader
15
15
public class JoinWalker
16
16
{
17
17
private readonly ISessionFactoryImplementor factory ;
18
+ protected Queue < QueueEntry > joinQueue = new Queue < QueueEntry > ( ) ;
19
+ private int depth ;
18
20
protected readonly IList < OuterJoinableAssociation > associations = new List < OuterJoinableAssociation > ( ) ;
19
21
private readonly HashSet < AssociationKey > visitedAssociationKeys = new HashSet < AssociationKey > ( ) ;
20
22
private readonly IDictionary < string , IFilter > enabledFilters ;
@@ -180,29 +182,40 @@ private void AddAssociationToJoinTree(IAssociationType type, string[] aliasedLhs
180
182
subalias ,
181
183
joinType ,
182
184
//for many-to-many with clause is applied with OuterJoinableAssociation created for entity persister so simply skip it here
183
- qc ? . IsManyToMany == true ? null : GetWithClause ( path , pathAlias ) ,
185
+ qc ? . IsManyToMany == true ? null : GetWithClause ( path , pathAlias ) ,
184
186
Factory ,
185
187
enabledFilters ,
186
188
GetSelectMode ( path ) ) ,
187
189
path ) ;
188
190
assoc . ValidateJoin ( path ) ;
189
191
AddAssociation ( assoc ) ;
190
192
191
- int nextDepth = currentDepth + 1 ;
192
-
193
- if ( qc == null )
193
+ if ( qc != null )
194
194
{
195
- IOuterJoinLoadable pjl = joinable as IOuterJoinLoadable ;
196
- if ( pjl != null )
197
- WalkEntityTree ( pjl , subalias , path , nextDepth ) ;
195
+ joinQueue . Enqueue (
196
+ new CollectionQueueEntry ( )
197
+ {
198
+ Persister = qc ,
199
+ Alias = subalias ,
200
+ Path = path ,
201
+ PathAlias = pathAlias ,
202
+ }
203
+ ) ;
198
204
}
199
- else
205
+ else if ( joinable is IOuterJoinLoadable jl )
200
206
{
201
- WalkCollectionTree ( qc , subalias , path , pathAlias , nextDepth ) ;
207
+ joinQueue . Enqueue (
208
+ new EntityQueueEntry ( )
209
+ {
210
+ Persister = jl ,
211
+ Alias = subalias ,
212
+ Path = path ,
213
+ }
214
+ ) ;
202
215
}
203
216
}
204
217
205
- protected virtual SelectMode GetSelectMode ( string path )
218
+ protected virtual SelectMode GetSelectMode ( string path )
206
219
{
207
220
return SelectMode . Undefined ;
208
221
}
@@ -211,7 +224,7 @@ protected virtual ISet<string> GetEntityFetchLazyProperties(string path)
211
224
{
212
225
return null ;
213
226
}
214
-
227
+
215
228
private struct DependentAlias2
216
229
{
217
230
public DependentAlias2 ( string alias , ICollection < string > dependsOn )
@@ -299,16 +312,55 @@ private void AddAssociation(OuterJoinableAssociation association)
299
312
/// </summary>
300
313
protected void WalkEntityTree ( IOuterJoinLoadable persister , string alias )
301
314
{
302
- WalkEntityTree ( persister , alias , string . Empty , 0 ) ;
315
+ joinQueue . Enqueue (
316
+ new EntityQueueEntry ( )
317
+ {
318
+ Persister = persister ,
319
+ Alias = alias ,
320
+ }
321
+ ) ;
322
+
323
+ WalkTree ( ) ;
303
324
}
304
325
305
326
/// <summary>
306
327
/// For a collection role, return a list of associations to be fetched by outerjoin
307
328
/// </summary>
308
329
protected void WalkCollectionTree ( IQueryableCollection persister , string alias )
309
330
{
310
- WalkCollectionTree ( persister , alias , string . Empty , string . Empty , 0 ) ;
311
- //TODO: when this is the entry point, we should use an INNER_JOIN for fetching the many-to-many elements!
331
+ joinQueue . Enqueue (
332
+ new CollectionQueueEntry ( )
333
+ {
334
+ Persister = persister ,
335
+ Alias = alias ,
336
+ }
337
+ ) ;
338
+
339
+ WalkTree ( ) ;
340
+ }
341
+
342
+ protected void WalkTree ( )
343
+ {
344
+ while ( joinQueue . Count > 0 )
345
+ {
346
+ QueueEntry entry = joinQueue . Dequeue ( ) ;
347
+
348
+ switch ( entry )
349
+ {
350
+ case CollectionQueueEntry ce :
351
+ WalkCollectionTree ( ce . Persister , ce . Alias , ce . Path , ce . PathAlias , depth ) ;
352
+ break ;
353
+ case PropertyQueueEntry pe :
354
+ WalkPropertyTree ( pe . Persister , pe . Type , pe . Index , pe . Alias , pe . Path , depth ) ;
355
+ break ;
356
+ case EntityQueueEntry eqe :
357
+ WalkEntityTree ( eqe . Persister , eqe . Alias , eqe . Path , depth ) ;
358
+ break ;
359
+ default :
360
+ depth ++ ;
361
+ break ;
362
+ }
363
+ }
312
364
}
313
365
314
366
/// <summary>
@@ -318,7 +370,7 @@ private void WalkCollectionTree(IQueryableCollection persister, string alias, st
318
370
{
319
371
if ( persister . IsOneToMany )
320
372
{
321
- WalkEntityTree ( ( IOuterJoinLoadable ) persister . ElementPersister , alias , path , currentDepth ) ;
373
+ WalkEntityTree ( ( IOuterJoinLoadable ) persister . ElementPersister , alias , path , currentDepth ) ;
322
374
}
323
375
else
324
376
{
@@ -388,7 +440,7 @@ internal void AddExplicitEntityJoinAssociation(
388
440
GetWithClause ( path , pathAlias ) ,
389
441
Factory ,
390
442
enabledFilters ,
391
- GetSelectMode ( path ) ) { ForceFilter = true } ,
443
+ GetSelectMode ( path ) ) { ForceFilter = true } ,
392
444
path ) ;
393
445
AddAssociation ( assoc ) ;
394
446
}
@@ -442,21 +494,42 @@ private void WalkEntityAssociationTree(IAssociationType associationType, IOuterJ
442
494
protected virtual void WalkEntityTree ( IOuterJoinLoadable persister , string alias , string path , int currentDepth )
443
495
{
444
496
int n = persister . CountSubclassProperties ( ) ;
497
+
445
498
for ( int i = 0 ; i < n ; i ++ )
446
499
{
447
500
IType type = persister . GetSubclassPropertyType ( i ) ;
448
- ILhsAssociationTypeSqlInfo associationTypeSQLInfo = JoinHelper . GetLhsSqlInfo ( alias , i , persister , Factory ) ;
449
- if ( type . IsAssociationType )
450
- {
451
- WalkEntityAssociationTree ( ( IAssociationType ) type , persister , i , alias , path ,
452
- persister . IsSubclassPropertyNullable ( i ) , currentDepth , associationTypeSQLInfo ) ;
453
- }
454
- else if ( type . IsComponentType )
501
+
502
+ if ( type . IsAssociationType || type . IsComponentType )
455
503
{
456
- WalkComponentTree ( ( IAbstractComponentType ) type , 0 , alias , SubPath ( path , persister . GetSubclassPropertyName ( i ) ) ,
457
- currentDepth , associationTypeSQLInfo ) ;
504
+ joinQueue . Enqueue (
505
+ new PropertyQueueEntry ( )
506
+ {
507
+ Persister = persister ,
508
+ Alias = alias ,
509
+ Path = path ,
510
+ Index = i ,
511
+ Type = type ,
512
+ }
513
+ ) ;
458
514
}
459
515
}
516
+ joinQueue . Enqueue ( null ) ;
517
+ }
518
+
519
+ protected void WalkPropertyTree ( IOuterJoinLoadable persister , IType type , int index , string alias , string path , int currentDepth )
520
+ {
521
+ ILhsAssociationTypeSqlInfo associationTypeSQLInfo = JoinHelper . GetLhsSqlInfo ( alias , index , persister , Factory ) ;
522
+
523
+ if ( type . IsAssociationType )
524
+ {
525
+ WalkEntityAssociationTree ( ( IAssociationType ) type , persister , index , alias , path ,
526
+ persister . IsSubclassPropertyNullable ( index ) , currentDepth , associationTypeSQLInfo ) ;
527
+ }
528
+ else if ( type . IsComponentType )
529
+ {
530
+ WalkComponentTree ( ( IAbstractComponentType ) type , 0 , alias , SubPath ( path , persister . GetSubclassPropertyName ( index ) ) ,
531
+ currentDepth , associationTypeSQLInfo ) ;
532
+ }
460
533
}
461
534
462
535
/// <summary>
@@ -680,7 +753,7 @@ protected bool IsJoinedFetchEnabledInMapping(FetchMode config, IAssociationType
680
753
{
681
754
//TODO: look at the owning property and check that it
682
755
// isn't lazy (by instrumentation)
683
- EntityType entityType = ( EntityType ) type ;
756
+ EntityType entityType = ( EntityType ) type ;
684
757
IEntityPersister persister = factory . GetEntityPersister ( entityType . GetAssociatedEntityName ( ) ) ;
685
758
return ! persister . HasProxy ;
686
759
}
@@ -849,7 +922,7 @@ protected JoinFragment MergeOuterJoins(IList<OuterJoinableAssociation> associati
849
922
}
850
923
}
851
924
852
- if ( TableGroupJoinHelper . ProcessAsTableGroupJoin ( new [ ] { oj } , new [ ] { oj . On , filter } , true , outerjoin , alias => true , factory ) )
925
+ if ( TableGroupJoinHelper . ProcessAsTableGroupJoin ( new [ ] { oj } , new [ ] { oj . On , filter } , true , outerjoin , alias => true , factory ) )
853
926
continue ;
854
927
855
928
oj . AddJoins ( outerjoin ) ;
@@ -954,7 +1027,7 @@ protected SqlString OrderBy(IList<OuterJoinableAssociation> associations)
954
1027
}
955
1028
956
1029
if ( buf . Count > 0 ) {
957
- buf . RemoveAt ( buf . Count - 1 ) ;
1030
+ buf . RemoveAt ( buf . Count - 1 ) ;
958
1031
}
959
1032
960
1033
return buf . ToSqlString ( ) ;
@@ -980,7 +1053,7 @@ protected SqlStringBuilder WhereString(string alias, string[] columnNames, int b
980
1053
var qualifiedName = ! string . IsNullOrEmpty ( tableAlias )
981
1054
? tableAlias + StringHelper . Dot + columnName
982
1055
: columnName ;
983
-
1056
+
984
1057
var whereString = new SqlStringBuilder ( batchSize * 5 ) ;
985
1058
whereString . Add ( qualifiedName ) ;
986
1059
if ( batchSize == 1 )
@@ -1101,7 +1174,7 @@ protected void InitPersisters(IList<OuterJoinableAssociation> associations, Lock
1101
1174
}
1102
1175
else
1103
1176
{
1104
- IQueryableCollection collPersister = ( IQueryableCollection ) oj . Joinable ;
1177
+ IQueryableCollection collPersister = ( IQueryableCollection ) oj . Joinable ;
1105
1178
if ( oj . ShouldFetchCollectionPersister ( ) )
1106
1179
{
1107
1180
//it must be a collection fetch
@@ -1186,5 +1259,30 @@ protected static string GetSelectFragment(OuterJoinableAssociation join, string
1186
1259
{
1187
1260
return join . GetSelectFragment ( entitySuffix , collectionSuffix , next ) ;
1188
1261
}
1262
+
1263
+ protected abstract class QueueEntry { }
1264
+
1265
+ protected abstract class QueueEntry < T > : QueueEntry where T : IJoinable
1266
+ {
1267
+ public string Alias { get ; set ; }
1268
+ public T Persister { get ; set ; }
1269
+ }
1270
+
1271
+ protected class EntityQueueEntry < T > : QueueEntry < T > where T : IJoinable
1272
+ {
1273
+ public string Path { get ; set ; }
1274
+ }
1275
+ protected class EntityQueueEntry : EntityQueueEntry < IOuterJoinLoadable > { }
1276
+
1277
+ protected class CollectionQueueEntry : EntityQueueEntry < IQueryableCollection >
1278
+ {
1279
+ public string PathAlias { get ; set ; }
1280
+ }
1281
+
1282
+ protected class PropertyQueueEntry : EntityQueueEntry
1283
+ {
1284
+ public int Index { get ; set ; }
1285
+ public IType Type { get ; set ; }
1286
+ }
1189
1287
}
1190
1288
}
0 commit comments