1 package org.hibernate.loader; 3 4 import java.util.ArrayList ; 5 import java.util.Arrays ; 6 import java.util.HashSet ; 7 import java.util.Iterator ; 8 import java.util.List ; 9 import java.util.Map ; 10 import java.util.Set ; 11 12 import org.hibernate.FetchMode; 13 import org.hibernate.LockMode; 14 import org.hibernate.MappingException; 15 import org.hibernate.dialect.Dialect; 16 import org.hibernate.engine.JoinHelper; 17 import org.hibernate.engine.SessionFactoryImplementor; 18 import org.hibernate.persister.collection.CollectionPersister; 19 import org.hibernate.persister.collection.QueryableCollection; 20 import org.hibernate.persister.entity.EntityPersister; 21 import org.hibernate.persister.entity.Joinable; 22 import org.hibernate.persister.entity.Loadable; 23 import org.hibernate.persister.entity.OuterJoinLoadable; 24 import org.hibernate.sql.ConditionFragment; 25 import org.hibernate.sql.DisjunctionFragment; 26 import org.hibernate.sql.InFragment; 27 import org.hibernate.sql.JoinFragment; 28 import org.hibernate.type.AbstractComponentType; 29 import org.hibernate.type.AssociationType; 30 import org.hibernate.type.EntityType; 31 import org.hibernate.type.ForeignKeyDirection; 32 import org.hibernate.type.Type; 33 import org.hibernate.util.ArrayHelper; 34 import org.hibernate.util.StringHelper; 35 36 43 public class JoinWalker { 44 45 private final SessionFactoryImplementor factory; 46 protected final List associations = new ArrayList (); 47 private final Set visitedAssociationKeys = new HashSet (); 48 private final Map enabledFilters; 49 50 protected String [] suffixes; 51 protected String [] collectionSuffixes; 52 protected Loadable[] persisters; 53 protected int[] owners; 54 protected EntityType[] ownerAssociationTypes; 55 protected CollectionPersister[] collectionPersisters; 56 protected int[] collectionOwners; 57 protected String [] aliases; 58 protected LockMode[] lockModeArray; 59 protected String sql; 60 61 public String [] getCollectionSuffixes() { 62 return collectionSuffixes; 63 } 64 65 public void setCollectionSuffixes(String [] collectionSuffixes) { 66 this.collectionSuffixes = collectionSuffixes; 67 } 68 69 public LockMode[] getLockModeArray() { 70 return lockModeArray; 71 } 72 73 public void setLockModeArray(LockMode[] lockModeArray) { 74 this.lockModeArray = lockModeArray; 75 } 76 77 public String [] getSuffixes() { 78 return suffixes; 79 } 80 81 public void setSuffixes(String [] suffixes) { 82 this.suffixes = suffixes; 83 } 84 85 public String [] getAliases() { 86 return aliases; 87 } 88 89 public void setAliases(String [] aliases) { 90 this.aliases = aliases; 91 } 92 93 public int[] getCollectionOwners() { 94 return collectionOwners; 95 } 96 97 public void setCollectionOwners(int[] collectionOwners) { 98 this.collectionOwners = collectionOwners; 99 } 100 101 public CollectionPersister[] getCollectionPersisters() { 102 return collectionPersisters; 103 } 104 105 public void setCollectionPersisters(CollectionPersister[] collectionPersisters) { 106 this.collectionPersisters = collectionPersisters; 107 } 108 109 public EntityType[] getOwnerAssociationTypes() { 110 return ownerAssociationTypes; 111 } 112 113 public void setOwnerAssociationTypes(EntityType[] ownerAssociationType) { 114 this.ownerAssociationTypes = ownerAssociationType; 115 } 116 117 public int[] getOwners() { 118 return owners; 119 } 120 121 public void setOwners(int[] owners) { 122 this.owners = owners; 123 } 124 125 public Loadable[] getPersisters() { 126 return persisters; 127 } 128 129 public void setPersisters(Loadable[] persisters) { 130 this.persisters = persisters; 131 } 132 133 public String getSQLString() { 134 return sql; 135 } 136 137 public void setSql(String sql) { 138 this.sql = sql; 139 } 140 141 protected SessionFactoryImplementor getFactory() { 142 return factory; 143 } 144 145 protected Dialect getDialect() { 146 return factory.getDialect(); 147 } 148 149 protected Map getEnabledFilters() { 150 return enabledFilters; 151 } 152 153 protected JoinWalker(SessionFactoryImplementor factory, Map enabledFilters) { 154 this.factory = factory; 155 this.enabledFilters = enabledFilters; 156 } 157 158 162 private void addAssociationToJoinTreeIfNecessary( 163 final AssociationType type, 164 final String [] aliasedLhsColumns, 165 final String alias, 166 final String path, 167 int currentDepth, 168 final int joinType) 169 throws MappingException { 170 171 if (joinType>=0) { 172 addAssociationToJoinTree( 173 type, 174 aliasedLhsColumns, 175 alias, 176 path, 177 currentDepth, 178 joinType 179 ); 180 } 181 182 } 183 184 188 private void addAssociationToJoinTree( 189 final AssociationType type, 190 final String [] aliasedLhsColumns, 191 final String alias, 192 final String path, 193 final int currentDepth, 194 final int joinType) 195 throws MappingException { 196 197 Joinable joinable = type.getAssociatedJoinable( getFactory() ); 198 199 String subalias = generateTableAlias( 200 associations.size()+1, path, 202 joinable 203 ); 204 205 OuterJoinableAssociation assoc = new OuterJoinableAssociation( 206 type, 207 alias, 208 aliasedLhsColumns, 209 subalias, 210 joinType, 211 getFactory(), 212 enabledFilters 213 ); 214 assoc.validateJoin(path); 215 associations.add(assoc); 216 217 int nextDepth = currentDepth+1; 218 if ( !joinable.isCollection() ) { 219 if (joinable instanceof OuterJoinLoadable) { 220 walkEntityTree( 221 (OuterJoinLoadable) joinable, 222 subalias, 223 path, 224 nextDepth 225 ); 226 } 227 } 228 else { 229 if (joinable instanceof QueryableCollection) { 230 walkCollectionTree( 231 (QueryableCollection) joinable, 232 subalias, 233 path, 234 nextDepth 235 ); 236 } 237 } 238 239 } 240 241 244 protected final void walkEntityTree(OuterJoinLoadable persister, String alias) 245 throws MappingException { 246 walkEntityTree(persister, alias, "", 0); 247 } 248 249 252 protected final void walkCollectionTree(QueryableCollection persister, String alias) 253 throws MappingException { 254 walkCollectionTree(persister, alias, "", 0); 255 } 257 258 261 private void walkCollectionTree( 262 final QueryableCollection persister, 263 final String alias, 264 final String path, 265 final int currentDepth) 266 throws MappingException { 267 268 if ( persister.isOneToMany() ) { 269 walkEntityTree( 270 (OuterJoinLoadable) persister.getElementPersister(), 271 alias, 272 path, 273 currentDepth 274 ); 275 } 276 else { 277 Type type = persister.getElementType(); 278 if ( type.isAssociationType() ) { 279 AssociationType associationType = (AssociationType) type; 283 String [] aliasedLhsColumns = persister.getElementColumnNames(alias); 284 String [] lhsColumns = persister.getElementColumnNames(); 285 boolean useInnerJoin = currentDepth == 0; 289 final int joinType = getJoinType( 290 associationType, 291 persister.getFetchMode(), 292 path, 293 persister.getTableName(), 294 lhsColumns, 295 !useInnerJoin, 296 currentDepth - 1 297 ); 298 addAssociationToJoinTreeIfNecessary( 299 associationType, 300 aliasedLhsColumns, 301 alias, 302 path, 303 currentDepth - 1, 304 joinType 305 ); 306 } 307 else if ( type.isComponentType() ) { 308 walkCompositeElementTree( 309 (AbstractComponentType) type, 310 persister.getElementColumnNames(), 311 persister, 312 alias, 313 path, 314 currentDepth 315 ); 316 } 317 } 318 319 } 320 321 324 private final void walkEntityAssociationTree( 325 final AssociationType associationType, 326 final OuterJoinLoadable persister, 327 final int propertyNumber, 328 final String alias, 329 final String path, 330 final boolean nullable, 331 final int currentDepth) 332 throws MappingException { 333 334 String [] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames( 335 associationType, alias, propertyNumber, persister, getFactory() 336 ); 337 338 String [] lhsColumns = JoinHelper.getLHSColumnNames( 339 associationType, propertyNumber, persister, getFactory() 340 ); 341 String lhsTable = JoinHelper.getLHSTableName(associationType, propertyNumber, persister); 342 343 String subpath = subPath( path, persister.getSubclassPropertyName(propertyNumber) ); 344 int joinType = getJoinType( 345 associationType, 346 persister.getFetchMode(propertyNumber), 347 subpath, 348 lhsTable, 349 lhsColumns, 350 nullable, 351 currentDepth 352 ); 353 addAssociationToJoinTreeIfNecessary( 354 associationType, 355 aliasedLhsColumns, 356 alias, 357 subpath, 358 currentDepth, 359 joinType 360 ); 361 362 } 363 364 368 private final void walkEntityTree( 369 final OuterJoinLoadable persister, 370 final String alias, 371 final String path, 372 final int currentDepth) 373 throws MappingException { 374 375 int n = persister.countSubclassProperties(); 376 for ( int i=0; i<n; i++ ) { 377 Type type = persister.getSubclassPropertyType(i); 378 if ( type.isAssociationType() ) { 379 walkEntityAssociationTree( 380 (AssociationType) type, 381 persister, 382 i, 383 alias, 384 path, 385 persister.isSubclassPropertyNullable(i), 386 currentDepth 387 ); 388 } 389 else if ( type.isComponentType() ) { 390 walkComponentTree( 391 (AbstractComponentType) type, 392 i, 393 0, 394 persister, 395 alias, 396 subPath( path, persister.getSubclassPropertyName(i) ), 397 currentDepth 398 ); 399 } 400 } 401 } 402 403 406 private void walkComponentTree( 407 final AbstractComponentType componentType, 408 final int propertyNumber, 409 int begin, 410 final OuterJoinLoadable persister, 411 final String alias, 412 final String path, 413 final int currentDepth 414 ) throws MappingException { 415 416 Type[] types = componentType.getSubtypes(); 417 String [] propertyNames = componentType.getPropertyNames(); 418 for ( int i=0; i <types.length; i++ ) { 419 420 if ( types[i].isAssociationType() ) { 421 AssociationType associationType = (AssociationType) types[i]; 422 423 String [] aliasedLhsColumns = JoinHelper.getAliasedLHSColumnNames( 424 associationType, alias, propertyNumber, begin, persister, getFactory() 425 ); 426 427 String [] lhsColumns = JoinHelper.getLHSColumnNames( 428 associationType, propertyNumber, begin, persister, getFactory() 429 ); 430 String lhsTable = JoinHelper.getLHSTableName(associationType, propertyNumber, persister); 431 432 String subpath = subPath( path, propertyNames[i] ); 433 final boolean[] propertyNullability = componentType.getPropertyNullability(); 434 final int joinType = getJoinType( 435 associationType, 436 componentType.getFetchMode(i), 437 subpath, 438 lhsTable, 439 lhsColumns, 440 propertyNullability==null || propertyNullability[i], 441 currentDepth 442 ); 443 addAssociationToJoinTreeIfNecessary( 444 associationType, 445 aliasedLhsColumns, 446 alias, 447 subpath, 448 currentDepth, 449 joinType 450 ); 451 452 } 453 else if ( types[i].isComponentType() ) { 454 String subpath = subPath( path, propertyNames[i] ); 455 walkComponentTree( 456 (AbstractComponentType) types[i], 457 propertyNumber, 458 begin, 459 persister, 460 alias, 461 subpath, 462 currentDepth 463 ); 464 } 465 466 begin+=types[i].getColumnSpan( getFactory() ); 467 } 468 469 } 470 471 474 private void walkCompositeElementTree( 475 final AbstractComponentType compositeType, 476 final String [] cols, 477 final QueryableCollection persister, 478 final String alias, 479 final String path, 480 final int currentDepth) 481 throws MappingException { 482 483 Type[] types = compositeType.getSubtypes(); 484 String [] propertyNames = compositeType.getPropertyNames(); 485 int begin = 0; 486 for ( int i=0; i <types.length; i++ ) { 487 int length = types[i].getColumnSpan( getFactory() ); 488 String [] lhsColumns = ArrayHelper.slice(cols, begin, length); 489 490 if ( types[i].isAssociationType() ) { 491 AssociationType associationType = (AssociationType) types[i]; 492 493 String [] aliasedLhsColumns = StringHelper.qualify(alias, lhsColumns); 496 497 String subpath = subPath( path, propertyNames[i] ); 498 final boolean[] propertyNullability = compositeType.getPropertyNullability(); 499 final int joinType = getJoinType( 500 associationType, 501 compositeType.getFetchMode(i), 502 subpath, 503 persister.getTableName(), 504 lhsColumns, 505 propertyNullability==null || propertyNullability[i], 506 currentDepth 507 ); 508 addAssociationToJoinTreeIfNecessary( 509 associationType, 510 aliasedLhsColumns, 511 alias, 512 subpath, 513 currentDepth, 514 joinType 515 ); 516 } 517 else if ( types[i].isComponentType() ) { 518 String subpath = subPath( path, propertyNames[i] ); 519 walkCompositeElementTree( 520 (AbstractComponentType) types[i], 521 lhsColumns, 522 persister, 523 alias, 524 subpath, 525 currentDepth 526 ); 527 } 528 begin+=length; 529 } 530 531 } 532 533 536 private static String subPath(String path, String property) { 537 if ( path==null || path.length()==0) { 538 return property; 539 } 540 else { 541 return StringHelper.qualify(path, property); 542 } 543 } 544 545 550 protected int getJoinType( 551 AssociationType type, 552 FetchMode config, 553 String path, 554 String lhsTable, 555 String [] lhsColumns, 556 boolean nullable, 557 int currentDepth) 558 throws MappingException { 559 560 if ( !isJoinedFetchEnabled(type, config) ) return -1; 561 562 if ( isTooDeep(currentDepth) ) return -1; 563 564 final boolean dupe = isDuplicateAssociation(lhsTable, lhsColumns, type); 565 if (dupe) return -1; 566 567 return getJoinType(nullable, currentDepth); 568 569 } 570 571 575 protected int getJoinType(boolean nullable, int currentDepth) { 576 return !nullable && currentDepth==0 ? 579 JoinFragment.INNER_JOIN : 580 JoinFragment.LEFT_OUTER_JOIN; 581 } 582 583 protected boolean isTooDeep(int currentDepth) { 584 Integer maxFetchDepth = getFactory().getSettings().getMaximumFetchDepth(); 585 return maxFetchDepth!=null && currentDepth >= maxFetchDepth.intValue(); 586 } 587 588 592 protected boolean isJoinedFetchEnabledInMapping(FetchMode config, AssociationType type) 593 throws MappingException { 594 if ( !type.isEntityType() && !type.isCollectionType() ) { 595 return false; 596 } 597 else { 598 if (config==FetchMode.JOIN) return true; 599 if (config==FetchMode.SELECT) return false; 600 if ( type.isEntityType() ) { 601 EntityType entityType =(EntityType) type; 604 EntityPersister persister = getFactory().getEntityPersister( entityType.getAssociatedEntityName() ); 605 return !persister.hasProxy(); 606 } 607 else { 608 return false; 609 } 610 } 611 } 612 613 617 protected boolean isJoinedFetchEnabled(AssociationType type, FetchMode config) { 618 return type.isEntityType() && isJoinedFetchEnabledInMapping(config, type) ; 619 } 620 621 protected String generateTableAlias( 622 final int n, 623 final String path, 624 final Joinable joinable 625 ) { 626 return StringHelper.generateAlias( joinable.getName(), n ); 627 } 628 629 protected String generateRootAlias(final String description) { 630 return StringHelper.generateAlias(description, 0); 631 } 632 633 637 protected boolean isDuplicateAssociation( 638 final String foreignKeyTable, 639 final String [] foreignKeyColumns 640 ) { 641 AssociationKey associationKey = new AssociationKey(foreignKeyColumns, foreignKeyTable); 642 return !visitedAssociationKeys.add( associationKey ); 643 } 644 645 649 protected boolean isDuplicateAssociation( 650 final String lhsTable, 651 final String [] lhsColumnNames, 652 final AssociationType type 653 ) { 654 final String foreignKeyTable; 655 final String [] foreignKeyColumns; 656 if ( type.getForeignKeyDirection()==ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) { 657 foreignKeyTable = lhsTable; 658 foreignKeyColumns = lhsColumnNames; 659 } 660 else { 661 foreignKeyTable = type.getAssociatedJoinable( getFactory() ).getTableName(); 662 foreignKeyColumns = JoinHelper.getRHSColumnNames( type, getFactory() ); 663 } 664 return isDuplicateAssociation(foreignKeyTable, foreignKeyColumns); 665 } 666 667 671 private static final class AssociationKey { 672 private String [] columns; 673 private String table; 674 private AssociationKey(String [] columns, String table) { 675 this.columns = columns; 676 this.table = table; 677 } 678 public boolean equals(Object other) { 679 AssociationKey that = (AssociationKey) other; 680 return that.table.equals(table) && Arrays.equals(columns, that.columns); 681 } 682 public int hashCode() { 683 return table.hashCode(); } 685 } 686 687 690 protected boolean isJoinable( 691 final int joinType, 692 final Set visitedAssociationKeys, 693 final String lhsTable, 694 final String [] lhsColumnNames, 695 final AssociationType type, 696 final int depth 697 ) { 698 if (joinType<0) return false; 699 700 if (joinType==JoinFragment.INNER_JOIN) return true; 701 702 Integer maxFetchDepth = getFactory().getSettings().getMaximumFetchDepth(); 703 final boolean tooDeep = maxFetchDepth!=null && 704 depth >= maxFetchDepth.intValue(); 705 706 return !tooDeep && !isDuplicateAssociation(lhsTable, lhsColumnNames, type); 707 } 708 709 protected String orderBy(final List associations, final String orderBy) { 710 String fullOrderBy = orderBy(associations); 711 if ( fullOrderBy.length()== 0 ) { 712 fullOrderBy = orderBy; 713 } 714 else if ( orderBy.length()!=0 ) { 715 fullOrderBy = fullOrderBy + ", " + orderBy; 716 } 717 return fullOrderBy; 718 } 719 720 723 protected final JoinFragment mergeOuterJoins(List associations) 724 throws MappingException { 725 JoinFragment outerjoin = getDialect().createOuterJoinFragment(); 726 Iterator iter = associations.iterator(); 727 OuterJoinableAssociation last = null; 728 while ( iter.hasNext() ) { 729 OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); 730 if ( last != null && last.isManyToManyWith( oj ) ) { 731 oj.addManyToManyJoin( outerjoin, ( QueryableCollection ) last.getJoinable() ); 732 } 733 else { 734 oj.addJoins(outerjoin); 735 } 736 last = oj; 737 } 738 last = null; 739 return outerjoin; 740 } 741 742 746 protected static final int countEntityPersisters(List associations) 747 throws MappingException { 748 int result = 0; 749 Iterator iter = associations.iterator(); 750 while ( iter.hasNext() ) { 751 OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); 752 if ( oj.getJoinable().consumesEntityAlias() ) { 753 result++; 754 } 755 } 756 return result; 757 } 758 759 764 protected static final int countCollectionPersisters(List associations) 765 throws MappingException { 766 int result = 0; 767 Iterator iter = associations.iterator(); 768 while ( iter.hasNext() ) { 769 OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); 770 if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN && oj.getJoinable().isCollection() ) { 771 result++; 772 } 773 } 774 return result; 775 } 776 777 780 protected static final String orderBy(List associations) 781 throws MappingException { 782 StringBuffer buf = new StringBuffer (); 783 Iterator iter = associations.iterator(); 784 while ( iter.hasNext() ) { 785 OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); 786 if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN && oj.getJoinable().isCollection() ) { 787 final QueryableCollection queryableCollection = (QueryableCollection) oj.getJoinable(); 788 if ( queryableCollection.hasOrdering() ) { 789 final String orderByString = queryableCollection.getSQLOrderByString( oj.getRHSAlias() ); 790 buf.append( orderByString ).append(", "); 791 } 792 } 793 } 794 if ( buf.length()>0 ) buf.setLength( buf.length()-2 ); 795 return buf.toString(); 796 } 797 798 801 protected StringBuffer whereString(String alias, String [] columnNames, int batchSize) { 802 if ( columnNames.length==1 ) { 803 InFragment in = new InFragment().setColumn( alias, columnNames[0] ); 806 for ( int i=0; i<batchSize; i++ ) in.addValue("?"); 807 return new StringBuffer ( in.toFragmentString() ); 808 } 809 else { 810 ConditionFragment byId = new ConditionFragment() 812 .setTableAlias(alias) 813 .setCondition( columnNames, "?" ); 814 815 StringBuffer whereString = new StringBuffer (); 816 if ( batchSize==1 ) { 817 whereString.append( byId.toFragmentString() ); 819 } 820 else { 821 whereString.append('('); DisjunctionFragment df = new DisjunctionFragment(); 824 for ( int i=0; i<batchSize; i++ ) { 825 df.addCondition(byId); 826 } 827 whereString.append( df.toFragmentString() ); 828 whereString.append(')'); } 830 return whereString; 831 } 832 } 833 834 protected void initPersisters(final List associations, final LockMode lockMode) throws MappingException { 835 836 final int joins = countEntityPersisters(associations); 837 final int collections = countCollectionPersisters(associations); 838 839 collectionOwners = collections==0 ? null : new int[collections]; 840 collectionPersisters = collections==0 ? null : new CollectionPersister[collections]; 841 collectionSuffixes = BasicLoader.generateSuffixes( joins + 1, collections ); 842 843 persisters = new Loadable[joins]; 844 aliases = new String [joins]; 845 owners = new int[joins]; 846 ownerAssociationTypes = new EntityType[joins]; 847 lockModeArray = ArrayHelper.fillArray(lockMode, joins); 848 849 int i=0; 850 int j=0; 851 Iterator iter = associations.iterator(); 852 while ( iter.hasNext() ) { 853 final OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); 854 if ( !oj.isCollection() ) { 855 856 persisters[i] = (Loadable) oj.getJoinable(); 857 aliases[i] = oj.getRHSAlias(); 858 owners[i] = oj.getOwner(associations); 859 ownerAssociationTypes[i] = (EntityType) oj.getJoinableType(); 860 i++; 861 862 } 863 else { 864 865 QueryableCollection collPersister = (QueryableCollection) oj.getJoinable(); 866 if ( oj.getJoinType()==JoinFragment.LEFT_OUTER_JOIN ) { 867 collectionPersisters[j] = collPersister; 869 collectionOwners[j] = oj.getOwner(associations); 870 j++; 871 } 872 873 if ( collPersister.isOneToMany() ) { 874 persisters[i] = (Loadable) collPersister.getElementPersister(); 875 aliases[i] = oj.getRHSAlias(); 876 i++; 877 } 878 } 879 } 880 881 if ( ArrayHelper.isAllNegative(owners) ) owners = null; 882 if ( collectionOwners!=null && ArrayHelper.isAllNegative(collectionOwners) ) { 883 collectionOwners = null; 884 } 885 } 886 887 890 protected final String selectString(List associations) 891 throws MappingException { 892 893 if ( associations.size()==0 ) { 894 return ""; 895 } 896 else { 897 StringBuffer buf = new StringBuffer ( associations.size() * 100 ) 898 .append(", "); 899 int entityAliasCount=0; 900 int collectionAliasCount=0; 901 for ( int i=0; i<associations.size(); i++ ) { 902 OuterJoinableAssociation join = (OuterJoinableAssociation) associations.get(i); 903 OuterJoinableAssociation next = (i == associations.size() - 1) 904 ? null 905 : ( OuterJoinableAssociation ) associations.get( i + 1 ); 906 final Joinable joinable = join.getJoinable(); 907 final String entitySuffix = ( suffixes == null || entityAliasCount >= suffixes.length ) 908 ? null 909 : suffixes[entityAliasCount]; 910 final String collectionSuffix = ( collectionSuffixes == null || collectionAliasCount >= collectionSuffixes.length ) 911 ? null 912 : collectionSuffixes[collectionAliasCount]; 913 final String selectFragment = joinable.selectFragment( 914 next == null ? null : next.getJoinable(), 915 next == null ? null : next.getRHSAlias(), 916 join.getRHSAlias(), 917 entitySuffix, 918 collectionSuffix, 919 join.getJoinType()==JoinFragment.LEFT_OUTER_JOIN 920 ); 921 buf.append(selectFragment); 922 if ( joinable.consumesEntityAlias() ) entityAliasCount++; 923 if ( joinable.consumesCollectionAlias() && join.getJoinType()==JoinFragment.LEFT_OUTER_JOIN ) collectionAliasCount++; 924 if ( 925 i<associations.size()-1 && 926 selectFragment.trim().length()>0 927 ) { 928 buf.append(", "); 929 } 930 } 931 return buf.toString(); 932 } 933 } 934 935 } 936 | Popular Tags |