private void renderEntityJoin(Join join, JoinFragment joinFragment) { final EntityQuerySpace rightHandSide = (EntityQuerySpace) join.getRightHandSide(); // see if there is already aliases registered for this entity query space (collection joins) EntityReferenceAliases aliases = aliasResolutionContext.resolveEntityReferenceAliases( rightHandSide.getUid() ); if ( aliases == null ) { aliasResolutionContext.generateEntityReferenceAliases( rightHandSide.getUid(), rightHandSide.getEntityPersister() ); } final Joinable joinable = (Joinable) rightHandSide.getEntityPersister(); addJoins( join, joinFragment, joinable ); }
private String resolveAdditionalJoinCondition(String rhsTableAlias, String withClause, Joinable joinable, AssociationType associationType) { // turns out that the call to AssociationType#getOnCondition in the initial code really just translates to // calls to the Joinable.filterFragment() method where the Joinable is either the entity or // collection persister final String filter = associationType!=null? associationType.getOnCondition( rhsTableAlias, factory, buildingParameters.getQueryInfluencers().getEnabledFilters() ): joinable.filterFragment( rhsTableAlias, buildingParameters.getQueryInfluencers().getEnabledFilters() ); if ( StringHelper.isEmpty( withClause ) && StringHelper.isEmpty( filter ) ) { return ""; } else if ( StringHelper.isNotEmpty( withClause ) && StringHelper.isNotEmpty( filter ) ) { return filter + " and " + withClause; } else { // only one is non-empty... return StringHelper.isNotEmpty( filter ) ? filter : withClause; } }
public String selectFragment( Joinable rhs, String rhsAlias, String lhsAlias, String entitySuffix, String collectionSuffix, boolean includeCollectionColumns) { // we need to determine the best way to know that two joinables // represent a single many-to-many... if ( rhs != null && isManyToMany() && !rhs.isCollection() ) { AssociationType elementType = ( ( AssociationType ) getElementType() ); if ( rhs.equals( elementType.getAssociatedJoinable( getFactory() ) ) ) { return manyToManySelectFragment( rhs, rhsAlias, lhsAlias, collectionSuffix ); } } return includeCollectionColumns ? selectFragment( lhsAlias, collectionSuffix ) : ""; }
public String selectFragment( Joinable rhs, String rhsAlias, String lhsAlias, String entitySuffix, String collectionSuffix, boolean includeCollectionColumns) { StringBuilder buf = new StringBuilder(); if ( includeCollectionColumns ) { // buf.append( selectFragment( lhsAlias, "" ) )//ignore suffix for collection columns! buf.append( selectFragment( lhsAlias, collectionSuffix ) ) .append( ", " ); } OuterJoinLoadable ojl = ( OuterJoinLoadable ) getElementPersister(); return buf.append( ojl.selectFragment( lhsAlias, entitySuffix ) )//use suffix for the entity columns .toString(); }
public String selectFragment( Joinable rhs, String rhsAlias, String lhsAlias, String entitySuffix, String collectionSuffix, boolean includeCollectionColumns) { StringBuffer buf = new StringBuffer(); if ( includeCollectionColumns ) { // buf.append( selectFragment( lhsAlias, "" ) )//ignore suffix for collection columns! buf.append( selectFragment( lhsAlias, collectionSuffix ) ) .append( ", " ); } OuterJoinLoadable ojl = ( OuterJoinLoadable ) getElementPersister(); return buf.append( ojl.selectFragment( lhsAlias, entitySuffix ) )//use suffix for the entity columns .toString(); }
/** * Generate a select list of columns containing all properties of the entity classes */ protected final String selectString(List associations) throws MappingException { if ( associations.size()==0 ) { return ""; } else { StringBuilder buf = new StringBuilder( associations.size() * 100 ); int entityAliasCount=0; int collectionAliasCount=0; for ( int i=0; i<associations.size(); i++ ) { OuterJoinableAssociation join = (OuterJoinableAssociation) associations.get(i); OuterJoinableAssociation next = (i == associations.size() - 1) ? null : ( OuterJoinableAssociation ) associations.get( i + 1 ); final Joinable joinable = join.getJoinable(); final String entitySuffix = ( suffixes == null || entityAliasCount >= suffixes.length ) ? null : suffixes[entityAliasCount]; final String collectionSuffix = ( collectionSuffixes == null || collectionAliasCount >= collectionSuffixes.length ) ? null : collectionSuffixes[collectionAliasCount]; final String selectFragment = joinable.selectFragment( next == null ? null : next.getJoinable(), next == null ? null : next.getRHSAlias(), join.getRHSAlias(), entitySuffix, collectionSuffix, join.getJoinType()==JoinType.LEFT_OUTER_JOIN ); if (selectFragment.trim().length() > 0) { buf.append(", ").append(selectFragment); } if ( joinable.consumesEntityAlias() ) entityAliasCount++; if ( joinable.consumesCollectionAlias() && join.getJoinType()==JoinType.LEFT_OUTER_JOIN ) collectionAliasCount++; } return buf.toString(); } }
protected void applyRootReturnWhereJoinRestrictions(SelectStatementBuilder selectStatementBuilder) { final Joinable joinable = (OuterJoinLoadable) getRootEntityReturn().getEntityPersister(); selectStatementBuilder.appendRestrictions( joinable.whereJoinFragment( entityReferenceAliases.getTableAlias(), true, true ) ); }
private void addJoins( Join join, JoinFragment joinFragment, Joinable joinable) { final String rhsTableAlias = aliasResolutionContext.resolveSqlTableAliasFromQuerySpaceUid( join.getRightHandSide().getUid() ); if ( StringHelper.isEmpty( rhsTableAlias ) ) { throw new IllegalStateException( "Join's RHS table alias cannot be empty" ); } final String lhsTableAlias = aliasResolutionContext.resolveSqlTableAliasFromQuerySpaceUid( join.getLeftHandSide().getUid() ); if ( lhsTableAlias == null ) { throw new IllegalStateException( "QuerySpace with that UID was not yet registered in the AliasResolutionContext" ); } // add join fragments from the collection table -> element entity table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ final String additionalJoinConditions = resolveAdditionalJoinCondition( rhsTableAlias, join.getAnyAdditionalJoinConditions( rhsTableAlias ), joinable, getJoinedAssociationTypeOrNull( join ) ); joinFragment.addJoin( joinable.getTableName(), rhsTableAlias, join.resolveAliasedLeftHandSideJoinConditionColumns( lhsTableAlias ), join.resolveNonAliasedRightHandSideJoinConditionColumns(), join.isRightHandSideRequired() ? JoinType.INNER_JOIN : JoinType.LEFT_OUTER_JOIN, additionalJoinConditions ); joinFragment.addJoins( joinable.fromJoinFragment( rhsTableAlias, false, true ), joinable.whereJoinFragment( rhsTableAlias, false, true ) ); }
private void renderManyToManyJoin( Join join, JoinFragment joinFragment) { // for many-to-many we have 3 table aliases. By way of example, consider a normal m-n: User<->Role // where User is the FetchOwner and Role (User.roles) is the Fetch. We'd have: // 1) the owner's table : user - in terms of rendering the joins (not the fetch select fragments), the // lhs table alias is only needed to qualify the lhs join columns, but we already have the qualified // columns here (aliasedLhsColumnNames) //final String ownerTableAlias = ...; // 2) the m-n table : user_role // 3) the element table : role final EntityPersister entityPersister = ( (EntityQuerySpace) join.getRightHandSide() ).getEntityPersister(); final String entityTableAlias = aliasResolutionContext.resolveSqlTableAliasFromQuerySpaceUid( join.getRightHandSide().getUid() ); if ( StringHelper.isEmpty( entityTableAlias ) ) { throw new IllegalStateException( "Collection element (many-to-many) table alias cannot be empty" ); } if ( JoinDefinedByMetadata.class.isInstance( join ) && CollectionPropertyNames.COLLECTION_ELEMENTS.equals( ( (JoinDefinedByMetadata) join ).getJoinedPropertyName() ) ) { final CollectionQuerySpace leftHandSide = (CollectionQuerySpace) join.getLeftHandSide(); final CollectionPersister persister = leftHandSide.getCollectionPersister(); final String manyToManyFilter = persister.getManyToManyFilterFragment( entityTableAlias, buildingParameters.getQueryInfluencers().getEnabledFilters() ); joinFragment.addCondition( manyToManyFilter ); } addJoins( join, joinFragment, (Joinable) entityPersister ); }
@Override public void startingEntity(EntityDefinition entityDefinition) { // see if the EntityDefinition is a root... final boolean isRoot = fetchSourceStack.isEmpty(); if ( ! isRoot ) { // if not, this call should represent a fetch which should have been handled in #startingAttribute return; } // if we get here, it is a root log.tracef( "%s Starting root entity : %s", StringHelper.repeat( ">>", fetchSourceStack.size() ), entityDefinition.getEntityPersister().getEntityName() ); if ( !supportsRootEntityReturns() ) { throw new HibernateException( "This strategy does not support root entity returns" ); } final EntityReturnImpl entityReturn = new EntityReturnImpl( entityDefinition, querySpaces ); addRootReturn( entityReturn ); pushToStack( entityReturn ); // also add an AssociationKey for the root so we can later on recognize circular references back to the root. final Joinable entityPersister = (Joinable) entityDefinition.getEntityPersister(); associationKeyRegistered( new AssociationKey( entityPersister.getTableName(), entityPersister.getKeyColumnNames() ) ); }
@Override public void startingCollection(CollectionDefinition collectionDefinition) { // see if the EntityDefinition is a root... final boolean isRoot = fetchSourceStack.isEmpty(); if ( ! isRoot ) { // if not, this call should represent a fetch which should have been handled in #startingAttribute return; } log.tracef( "%s Starting root collection : %s", StringHelper.repeat( ">>", fetchSourceStack.size() ), collectionDefinition.getCollectionPersister().getRole() ); // if we get here, it is a root if ( ! supportsRootCollectionReturns() ) { throw new HibernateException( "This strategy does not support root collection returns" ); } final CollectionReturn collectionReturn = new CollectionReturnImpl( collectionDefinition, querySpaces ); pushToCollectionStack( collectionReturn ); addRootReturn( collectionReturn ); associationKeyRegistered( new AssociationKey( ( (Joinable) collectionDefinition.getCollectionPersister() ).getTableName(), ( (Joinable) collectionDefinition.getCollectionPersister() ).getKeyColumnNames() ) ); }
@Override public void foundCircularAssociation(AssociationAttributeDefinition attributeDefinition) { final FetchStrategy fetchStrategy = determineFetchStrategy( attributeDefinition ); if ( fetchStrategy.getStyle() != FetchStyle.JOIN ) { return; // nothing to do } final AssociationKey associationKey = attributeDefinition.getAssociationKey(); // go ahead and build the bidirectional fetch if ( attributeDefinition.getAssociationNature() == AssociationAttributeDefinition.AssociationNature.ENTITY ) { final Joinable currentEntityPersister = (Joinable) currentSource().resolveEntityReference().getEntityPersister(); final AssociationKey currentEntityReferenceAssociationKey = new AssociationKey( currentEntityPersister.getTableName(), currentEntityPersister.getKeyColumnNames() ); // if associationKey is equal to currentEntityReferenceAssociationKey // that means that the current EntityPersister has a single primary key attribute // (i.e., derived attribute) which is mapped by attributeDefinition. // This is not a bidirectional association. // TODO: AFAICT, to avoid an overflow, the associated entity must already be loaded into the session, or // it must be loaded when the ID for the dependent entity is resolved. Is there some other way to // deal with this??? final FetchSource registeredFetchSource = registeredFetchSource( associationKey ); if ( registeredFetchSource != null && ! associationKey.equals( currentEntityReferenceAssociationKey ) ) { currentSource().buildBidirectionalEntityReference( attributeDefinition, fetchStrategy, registeredFetchSource( associationKey ).resolveEntityReference() ); } } else { // Do nothing for collection } }
private String manyToManySelectFragment( Joinable rhs, String rhsAlias, String lhsAlias, String collectionSuffix) { SelectFragment frag = generateSelectFragment( lhsAlias, collectionSuffix ); String[] elementColumnNames = rhs.getKeyColumnNames(); frag.addColumns( rhsAlias, elementColumnNames, elementColumnAliases ); appendIndexColumns( frag, lhsAlias ); appendIdentifierColumns( frag, lhsAlias ); return frag.toFragmentString() .substring( 2 ); //strip leading ',' }
@Override public String fromJoinFragment( String alias, boolean innerJoin, boolean includeSubclasses, Set<String> treatAsDeclarations) { return ( (Joinable) getElementPersister() ).fromJoinFragment( alias, innerJoin, includeSubclasses, treatAsDeclarations ); }
@Override public String whereJoinFragment( String alias, boolean innerJoin, boolean includeSubclasses, Set<String> treatAsDeclarations) { return ( (Joinable) getElementPersister() ).whereJoinFragment( alias, innerJoin, includeSubclasses, treatAsDeclarations ); }
@Override public String filterFragment(String alias) throws MappingException { String result = super.filterFragment( alias ); if ( getElementPersister() instanceof Joinable ) { result += ( ( Joinable ) getElementPersister() ).oneToManyFilterFragment( alias ); } return result; }
@Override protected String filterFragment(String alias, Set<String> treatAsDeclarations) throws MappingException { String result = super.filterFragment( alias ); if ( getElementPersister() instanceof Joinable ) { result += ( ( Joinable ) getElementPersister() ).oneToManyFilterFragment( alias, treatAsDeclarations ); } return result; }
@Override public AssociationKey getAssociationKey() { final AssociationType type = getType(); if ( type.isAnyType() ) { return new AssociationKey( JoinHelper.getLHSTableName( type, attributeNumber(), (OuterJoinLoadable) getSource() ), JoinHelper.getLHSColumnNames( type, attributeNumber(), 0, (OuterJoinLoadable) getSource(), sessionFactory() ) ); } final Joinable joinable = type.getAssociatedJoinable( sessionFactory() ); if ( type.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT ) { final String lhsTableName; final String[] lhsColumnNames; if ( joinable.isCollection() ) { final QueryableCollection collectionPersister = (QueryableCollection) joinable; lhsTableName = collectionPersister.getTableName(); lhsColumnNames = collectionPersister.getElementColumnNames(); } else { final OuterJoinLoadable entityPersister = (OuterJoinLoadable) source(); lhsTableName = getLHSTableName( type, attributeNumber(), entityPersister ); lhsColumnNames = getLHSColumnNames( type, attributeNumber(), entityPersister, sessionFactory() ); } return new AssociationKey( lhsTableName, lhsColumnNames ); } else { return new AssociationKey( joinable.getTableName(), getRHSColumnNames( type, sessionFactory() ) ); } }
protected Joinable getJoinable() { if ( getAssociationNature() == AssociationNature.ANY ) { throw new WalkingException( "Cannot resolve AnyType to a Joinable" ); } if ( joinable == null ) { joinable = getType().getAssociatedJoinable( sessionFactory() ); } return joinable; }
/** * Get the columns of the associated table which are to be used in the join * * @param type The type * @param factory The SessionFactory * * @return The columns for the right-hand-side of the join */ public static String[] getRHSColumnNames(AssociationType type, SessionFactoryImplementor factory) { final String uniqueKeyPropertyName = type.getRHSUniqueKeyPropertyName(); final Joinable joinable = type.getAssociatedJoinable( factory ); if ( uniqueKeyPropertyName == null ) { return joinable.getKeyColumnNames(); } else { return ( (OuterJoinLoadable) joinable ).getPropertyColumnNames( uniqueKeyPropertyName ); } }
@SuppressWarnings("SimplifiableIfStatement") private boolean isManyToManyRoot(Joinable joinable) { if ( joinable != null && joinable.isCollection() ) { return ( (QueryableCollection) joinable ).isManyToMany(); } return false; }
private void addSubclassJoins( JoinFragment joinFragment, String alias, Joinable joinable, boolean innerJoin, boolean includeSubclassJoins, Set<String> treatAsDeclarations) { final boolean include = includeSubclassJoins && isIncluded( alias ); joinFragment.addJoins( joinable.fromJoinFragment( alias, innerJoin, include, treatAsDeclarations ), joinable.whereJoinFragment( alias, innerJoin, include, treatAsDeclarations ) ); }
private Map<String,String> mergeAliasMaps(SessionFactoryImplementor factory){ Map<String,String> ret = new HashMap<String, String>(); if (aliasTableMap != null){ ret.putAll(aliasTableMap); } if (aliasEntityMap != null){ for (Map.Entry<String, String> entry : aliasEntityMap.entrySet()){ ret.put(entry.getKey(), Joinable.class.cast(factory.getEntityPersister(entry.getValue())).getTableName()); } } return ret; }
private FromElement createAndAddFromElement( String className, String classAlias, EntityPersister entityPersister, EntityType type, String tableAlias) { if ( !( entityPersister instanceof Joinable ) ) { throw new IllegalArgumentException( "EntityPersister " + entityPersister + " does not implement Joinable!" ); } FromElement element = createFromElement( entityPersister ); initializeAndAddFromElement( element, className, classAlias, entityPersister, type, tableAlias ); return element; }
private FromElement createFromElement(EntityPersister entityPersister) { Joinable joinable = (Joinable) entityPersister; String text = joinable.getTableName(); AST ast = createFromElement( text ); FromElement element = (FromElement) ast; return element; }
protected String generateTableAlias( final int n, final String path, final Joinable joinable ) { return StringHelper.generateAlias( joinable.getName(), n ); }
protected String generateTableAlias(int n, String path, Joinable joinable) { if ( joinable.consumesEntityAlias() ) { final Criteria subcriteria = translator.getCriteria(path); String sqlAlias = subcriteria==null ? null : translator.getSQLAlias(subcriteria); if (sqlAlias!=null) { userAliasList.add( subcriteria.getAlias() ); //alias may be null return sqlAlias; //EARLY EXIT } else { userAliasList.add(null); } } return super.generateTableAlias( n + translator.getSQLAliasCount(), path, joinable ); }
public String filterFragment(String alias) throws MappingException { String result = super.filterFragment( alias ); if ( getElementPersister() instanceof Joinable ) { result += ( ( Joinable ) getElementPersister() ).oneToManyFilterFragment( alias ); } return result; }
/** * Get the columns of the associated table which are to * be used in the join */ public static String[] getRHSColumnNames(AssociationType type, SessionFactoryImplementor factory) { String uniqueKeyPropertyName = type.getRHSUniqueKeyPropertyName(); Joinable joinable = type.getAssociatedJoinable(factory); if (uniqueKeyPropertyName==null) { return joinable.getKeyColumnNames(); } else { return ( (OuterJoinLoadable) joinable ).getPropertyColumnNames(uniqueKeyPropertyName); } }
private boolean isManyToManyRoot(Joinable joinable) { if ( joinable != null && joinable.isCollection() ) { QueryableCollection persister = ( QueryableCollection ) joinable; return persister.isManyToMany(); } return false; }
private FromElement createFromElement(EntityPersister entityPersister) { Joinable joinable = ( Joinable ) entityPersister; String text = joinable.getTableName(); AST ast = createFromElement( text ); FromElement element = ( FromElement ) ast; return element; }
public JoinSequence getJoinSequence() { if ( joinSequence != null ) { return joinSequence; } // Class names in the FROM clause result in a JoinSequence (the old FromParser does this). if ( persister instanceof Joinable ) { Joinable joinable = ( Joinable ) persister; return fromElement.getSessionFactoryHelper().createJoinSequence().setRoot( joinable, getTableAlias() ); } else { return null; // TODO: Should this really return null? If not, figure out something better to do here. } }
public static String getTableName(Class hqlType, Session session) { SessionFactory factory = session.getSessionFactory(); MetamodelImpl model = (MetamodelImpl) factory.getMetamodel(); EntityPersister ep = model.entityPersister(hqlType); if (ep instanceof Joinable) { Joinable joinable = (Joinable) ep; return joinable.getTableName(); } throw new SystemException("Couldn't get table name for class " + hqlType.getName()); }
/** * Add on association (one-to-one, many-to-one, or a collection) to a list * of associations to be fetched by outerjoin */ private void addAssociationToJoinTree( final AssociationType type, final String[] aliasedLhsColumns, final String alias, final PropertyPath path, final int currentDepth, final JoinType joinType) throws MappingException { Joinable joinable = type.getAssociatedJoinable( getFactory() ); // important to generate alias based on size of association collection // *before* adding this join to that collection String subalias = generateTableAlias( associations.size() + 1, path, joinable ); // NOTE : it should be fine to continue to pass only filters below // (instead of LoadQueryInfluencers) since "from that point on" we // only need to worry about restrictions (and not say adding more // joins) OuterJoinableAssociation assoc = new OuterJoinableAssociation( path, type, alias, aliasedLhsColumns, subalias, joinType, getWithClause(path), hasRestriction( path ), getFactory(), loadQueryInfluencers.getEnabledFilters() ); assoc.validateJoin( path.getFullPath() ); associations.add( assoc ); int nextDepth = currentDepth + 1; // path = ""; if ( !joinable.isCollection() ) { if (joinable instanceof OuterJoinLoadable) { walkEntityTree( (OuterJoinLoadable) joinable, subalias, path, nextDepth ); } } else { if (joinable instanceof QueryableCollection) { walkCollectionTree( (QueryableCollection) joinable, subalias, path, nextDepth ); } } }