/** * Walk the association tree for an entity, adding associations which should be join fetched to * the {@link #associations} inst var. This form is the entry point into the walking for a given * entity, starting the recursive calls into {@link * #walkEntityTree(org.hibernate.persister.entity.OuterJoinLoadable, String, PropertyPath ,int)}. * * @param persister The persister representing the entity to be walked. * @param alias The (root) alias to use for this entity/persister. * @param path The property path to the entity being walked * @param currentDepth The current join depth * @throws org.hibernate.MappingException ??? */ private void walkEntityTree( final OuterJoinLoadable persister, final String alias, final PropertyPath path, final int currentDepth) throws MappingException { int n = persister.countSubclassProperties(); for (int i = 0; i < n; i++) { Type type = persister.getSubclassPropertyType(i); if (type.isAssociationType()) { walkEntityAssociationTree( (AssociationType) type, persister, i, alias, path, persister.isSubclassPropertyNullable(i), currentDepth); } else if (type.isComponentType()) { walkComponentTree( (CompositeType) type, i, 0, persister, alias, path.append(persister.getSubclassPropertyName(i)), currentDepth); } } // if the entity has a composite identifier, see if we need to handle // its sub-properties separately final Type idType = persister.getIdentifierType(); if (idType.isComponentType()) { final CompositeType cidType = (CompositeType) idType; if (cidType.isEmbedded()) { // we have an embedded composite identifier. Most likely we need to process the composite // properties separately, although there is an edge case where the identifier is really // a simple identifier (single value) wrapped in a JPA @IdClass or even in the case of a // a simple identifier (single value) wrapped in a Hibernate composite type. // // We really do not have a built-in method to determine that. However, generally the // persister would report that there is single, physical identifier property which is // explicitly at odds with the notion of "embedded composite". So we use that for now if (persister.getEntityMetamodel().getIdentifierProperty().isEmbedded()) { walkComponentTree(cidType, -1, 0, persister, alias, path.append(""), currentDepth); } } } }
private CriteriaInfoProvider getPathInfo(String path) { StringTokenizer tokens = new StringTokenizer(path, "."); String componentPath = ""; // start with the 'rootProvider' CriteriaInfoProvider provider = nameCriteriaInfoMap.get(rootEntityName); while (tokens.hasMoreTokens()) { componentPath += tokens.nextToken(); Type type = provider.getType(componentPath); if (type.isAssociationType()) { // CollectionTypes are always also AssociationTypes - but there's not always an associated // entity... AssociationType atype = (AssociationType) type; CollectionType ctype = type.isCollectionType() ? (CollectionType) type : null; Type elementType = (ctype != null) ? ctype.getElementType(sessionFactory) : null; // is the association a collection of components or value-types? (i.e a colloction of valued // types?) if (ctype != null && elementType.isComponentType()) { provider = new ComponentCollectionCriteriaInfoProvider( helper.getCollectionPersister(ctype.getRole())); } else if (ctype != null && !elementType.isEntityType()) { provider = new ScalarCollectionCriteriaInfoProvider(helper, ctype.getRole()); } else { provider = new EntityCriteriaInfoProvider( (Queryable) sessionFactory.getEntityPersister( atype.getAssociatedEntityName(sessionFactory))); } componentPath = ""; } else if (type.isComponentType()) { if (!tokens.hasMoreTokens()) { throw new QueryException( "Criteria objects cannot be created directly on components. Create a criteria on owning entity and use a dotted property to access component property: " + path); } else { componentPath += '.'; } } else { throw new QueryException("not an association: " + componentPath); } } return provider; }
/** * Walk the association tree for an entity, adding associations which should be join fetched to * the {@link #associations} inst var. This form is the entry point into the walking for a given * entity, starting the recursive calls into {@link * #walkEntityTree(org.hibernate.persister.entity.OuterJoinLoadable, String, PropertyPath ,int)}. * * @param persister The persister representing the entity to be walked. * @param alias The (root) alias to use for this entity/persister. * @param path The property path to the entity being walked * @param currentDepth The current join depth * @throws org.hibernate.MappingException ??? */ private void walkEntityTree( final OuterJoinLoadable persister, final String alias, final PropertyPath path, final int currentDepth) throws MappingException { int n = persister.countSubclassProperties(); for (int i = 0; i < n; i++) { Type type = persister.getSubclassPropertyType(i); if (type.isAssociationType()) { walkEntityAssociationTree( (AssociationType) type, persister, i, alias, path, persister.isSubclassPropertyNullable(i), currentDepth); } else if (type.isComponentType()) { walkComponentTree( (CompositeType) type, i, 0, persister, alias, path.append(persister.getSubclassPropertyName(i)), currentDepth); } } }
FromElement createCollection( QueryableCollection queryableCollection, String role, int joinType, boolean fetchFlag, boolean indexed) throws SemanticException { if (!collection) { throw new IllegalStateException("FromElementFactory not initialized for collections!"); } this.inElementsFunction = indexed; FromElement elem; this.queryableCollection = queryableCollection; collectionType = queryableCollection.getCollectionType(); String roleAlias = fromClause.getAliasGenerator().createName(role); // Correlated subqueries create 'special' implied from nodes // because correlated subselects can't use an ANSI-style join boolean explicitSubqueryFromElement = fromClause.isSubQuery() && !implied; if (explicitSubqueryFromElement) { String pathRoot = StringHelper.root(path); FromElement origin = fromClause.getFromElement(pathRoot); if (origin == null || origin.getFromClause() != fromClause) { implied = true; } } // super-duper-classic-parser-regression-testing-mojo-magic... if (explicitSubqueryFromElement && DotNode.useThetaStyleImplicitJoins) { implied = true; } Type elementType = queryableCollection.getElementType(); if (elementType.isEntityType()) { // A collection of entities... elem = createEntityAssociation(role, roleAlias, joinType); } else if (elementType.isComponentType()) { // A collection of components... JoinSequence joinSequence = createJoinSequence(roleAlias, joinType); elem = createCollectionJoin(joinSequence, roleAlias); } else { // A collection of scalar elements... JoinSequence joinSequence = createJoinSequence(roleAlias, joinType); elem = createCollectionJoin(joinSequence, roleAlias); } elem.setRole(role); elem.setQueryableCollection(queryableCollection); // Don't include sub-classes for implied collection joins or subquery joins. if (implied) { elem.setIncludeSubclasses(false); } if (explicitSubqueryFromElement) { elem.setInProjectionList(true); // Treat explict from elements in sub-queries properly. } if (fetchFlag) { elem.setFetch(true); } return elem; }
private static NonIdentifierAttributeNature decode(Type type) { if (type.isAssociationType()) { AssociationType associationType = (AssociationType) type; if (type.isComponentType()) { // an any type is both an association and a composite... return NonIdentifierAttributeNature.ANY; } return type.isCollectionType() ? NonIdentifierAttributeNature.COLLECTION : NonIdentifierAttributeNature.ENTITY; } else { if (type.isComponentType()) { return NonIdentifierAttributeNature.COMPOSITE; } return NonIdentifierAttributeNature.BASIC; } }
private boolean indicatesCollection(Type type) { if (type.isCollectionType()) { return true; } else if (type.isComponentType()) { Type[] subtypes = ((CompositeType) type).getSubtypes(); for (int i = 0; i < subtypes.length; i++) { if (indicatesCollection(subtypes[i])) { return true; } } } return false; }
protected String generateTableAlias(int n, PropertyPath path, Joinable joinable) { // TODO: deal with side-effects (changes to includeInResultRowList, userAliasList, // resultTypeList)!!! // for collection-of-entity, we are called twice for given "path" // once for the collection Joinable, once for the entity Joinable. // the second call will/must "consume" the alias + perform side effects according to // consumesEntityAlias() // for collection-of-other, however, there is only one call // it must "consume" the alias + perform side effects, despite what consumeEntityAlias() return // says // // note: the logic for adding to the userAliasList is still strictly based on // consumesEntityAlias return value boolean checkForSqlAlias = joinable.consumesEntityAlias(); if (!checkForSqlAlias && joinable.isCollection()) { // is it a collection-of-other (component or value) ? CollectionPersister collectionPersister = (CollectionPersister) joinable; Type elementType = collectionPersister.getElementType(); if (elementType.isComponentType() || !elementType.isEntityType()) { checkForSqlAlias = true; } } String sqlAlias = null; if (checkForSqlAlias) { final Criteria subcriteria = translator.getCriteria(path.getFullPath()); sqlAlias = subcriteria == null ? null : translator.getSQLAlias(subcriteria); if (joinable.consumesEntityAlias() && !translator.hasProjection()) { includeInResultRowList.add(subcriteria != null && subcriteria.getAlias() != null); if (sqlAlias != null) { if (subcriteria.getAlias() != null) { userAliasList.add(subcriteria.getAlias()); resultTypeList.add(translator.getResultType(subcriteria)); } } } } if (sqlAlias == null) { sqlAlias = super.generateTableAlias(n + translator.getSQLAliasCount(), path, joinable); } return sqlAlias; }
/** For a collection role, return a list of associations to be fetched by outerjoin */ private void walkCollectionTree( final QueryableCollection persister, final String alias, final PropertyPath path, final int currentDepth) throws MappingException { if (persister.isOneToMany()) { walkEntityTree( (OuterJoinLoadable) persister.getElementPersister(), alias, path, currentDepth); } else { Type type = persister.getElementType(); if (type.isAssociationType()) { // a many-to-many; // decrement currentDepth here to allow join across the association table // without exceeding MAX_FETCH_DEPTH (i.e. the "currentDepth - 1" bit) AssociationType associationType = (AssociationType) type; String[] aliasedLhsColumns = persister.getElementColumnNames(alias); String[] lhsColumns = persister.getElementColumnNames(); // if the current depth is 0, the root thing being loaded is the // many-to-many collection itself. Here, it is alright to use // an inner join... boolean useInnerJoin = currentDepth == 0; final JoinType joinType = getJoinType( associationType, persister.getFetchMode(), path, persister.getTableName(), lhsColumns, !useInnerJoin, currentDepth - 1, null // operations which cascade as far as the collection also cascade to collection // elements ); addAssociationToJoinTreeIfNecessary( associationType, aliasedLhsColumns, alias, path, currentDepth - 1, joinType); } else if (type.isComponentType()) { walkCompositeElementTree( (CompositeType) type, persister.getElementColumnNames(), persister, alias, path, currentDepth); } } }
protected void initPropertyPaths( final String path, final Type type, String[] columns, final String[] formulaTemplates, final Mapping factory) throws MappingException { if (columns.length != type.getColumnSpan(factory)) { throw new MappingException("broken column mapping for: " + path + " of: " + getEntityName()); } if (type.isAssociationType()) { AssociationType actype = (AssociationType) type; if (actype.useLHSPrimaryKey()) { columns = getIdentifierColumnNames(); } else { String foreignKeyProperty = actype.getLHSPropertyName(); if (foreignKeyProperty != null && !path.equals(foreignKeyProperty)) { // TODO: this requires that the collection is defined after the // referenced property in the mapping file (ok?) columns = (String[]) columnsByPropertyPath.get(foreignKeyProperty); if (columns == null) return; // get em on the second pass! } } } if (path != null) addPropertyPath(path, type, columns, formulaTemplates); if (type.isComponentType()) { AbstractComponentType actype = (AbstractComponentType) type; initComponentPropertyPaths(path, actype, columns, formulaTemplates, factory); if (actype.isEmbedded()) { initComponentPropertyPaths( path == null ? null : StringHelper.qualifier(path), actype, columns, formulaTemplates, factory); } } else if (type.isEntityType()) { initIdentifierPropertyPaths(path, (EntityType) type, columns, factory); } }
public CascadeStyle getCascadeStyle() throws MappingException { Type type = value.getType(); if (type.isComponentType() && !type.isAnyType()) { AbstractComponentType actype = (AbstractComponentType) type; int length = actype.getSubtypes().length; for (int i = 0; i < length; i++) { if (actype.getCascadeStyle(i) != CascadeStyle.NONE) return CascadeStyle.ALL; } return CascadeStyle.NONE; } else if (cascade == null || cascade.equals("none")) { return CascadeStyle.NONE; } else { StringTokenizer tokens = new StringTokenizer(cascade, ", "); CascadeStyle[] styles = new CascadeStyle[tokens.countTokens()]; int i = 0; while (tokens.hasMoreTokens()) { styles[i++] = CascadeStyle.getCascadeStyle(tokens.nextToken()); } return new CascadeStyle.MultipleCascadeStyle(styles); } }
private String getPathEntityName(String path) { Queryable persister = (Queryable) sessionFactory.getEntityPersister(rootEntityName); StringTokenizer tokens = new StringTokenizer(path, "."); String componentPath = ""; while (tokens.hasMoreTokens()) { componentPath += tokens.nextToken(); Type type = persister.toType(componentPath); if (type.isAssociationType()) { AssociationType atype = (AssociationType) type; persister = (Queryable) sessionFactory.getEntityPersister(atype.getAssociatedEntityName(sessionFactory)); componentPath = ""; } else if (type.isComponentType()) { componentPath += '.'; } else { throw new QueryException("not an association: " + componentPath); } } return persister.getEntityName(); }
public void token(String token, QueryTranslatorImpl q) throws QueryException { if (token != null) path.append(token); String alias = q.getPathAlias(path.toString()); if (alias != null) { reset(q); // reset the dotcount (but not the path) currentName = alias; // after reset! currentPropertyMapping = q.getPropertyMapping(currentName); if (!ignoreInitialJoin) { JoinSequence ojf = q.getPathJoin(path.toString()); try { joinSequence.addCondition( ojf.toJoinFragment(q.getEnabledFilters(), true) .toWhereFragmentString()); // after reset! } catch (MappingException me) { throw new QueryException(me); } // we don't need to worry about any condition in the ON clause // here (toFromFragmentString), since anything in the ON condition // is already applied to the whole query } } else if (".".equals(token)) { dotcount++; } else { if (dotcount == 0) { if (!continuation) { if (!q.isName(token)) throw new QueryException("undefined alias: " + token); currentName = token; currentPropertyMapping = q.getPropertyMapping(currentName); } } else if (dotcount == 1) { if (currentName != null) { currentProperty = token; } else if (collectionName != null) { // processCollectionProperty(token, q.getCollectionPersister(collectionRole), // collectionName); continuation = false; } else { throw new QueryException("unexpected"); } } else { // dotcount>=2 // Do the corresponding RHS Type propertyType = getPropertyType(); if (propertyType == null) { throw new QueryException("unresolved property: " + path); } if (propertyType.isComponentType()) { dereferenceComponent(token); } else if (propertyType.isEntityType()) { if (!isCollectionValued()) dereferenceEntity(token, (EntityType) propertyType, q); } else if (propertyType.isCollectionType()) { dereferenceCollection(token, ((CollectionType) propertyType).getRole(), q); } else { if (token != null) throw new QueryException("dereferenced: " + path); } } } }