@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())); } }
public OuterJoinableAssociation( PropertyPath propertyPath, AssociationType joinableType, String lhsAlias, String[] lhsColumns, String rhsAlias, JoinType joinType, String withClause, boolean hasRestriction, SessionFactoryImplementor factory, Map enabledFilters) throws MappingException { this.propertyPath = propertyPath; this.joinableType = joinableType; this.lhsAlias = lhsAlias; this.lhsColumns = lhsColumns; this.rhsAlias = rhsAlias; this.joinType = joinType; this.joinable = joinableType.getAssociatedJoinable(factory); this.rhsColumns = JoinHelper.getRHSColumnNames(joinableType, factory); this.on = joinableType.getOnCondition(rhsAlias, factory, enabledFilters) + (withClause == null || withClause.trim().length() == 0 ? "" : " and ( " + withClause + " )"); this.hasRestriction = hasRestriction; this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application }
/** Used to detect circularities in the joined graph, note that this method is side-effecty */ protected boolean isDuplicateAssociation( final String lhsTable, final String[] lhsColumnNames, final AssociationType type) { final String foreignKeyTable; final String[] foreignKeyColumns; if (type.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT) { foreignKeyTable = lhsTable; foreignKeyColumns = lhsColumnNames; } else { foreignKeyTable = type.getAssociatedJoinable(getFactory()).getTableName(); foreignKeyColumns = JoinHelper.getRHSColumnNames(type, getFactory()); } return isDuplicateAssociation(foreignKeyTable, foreignKeyColumns); }
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; }
private boolean isOneToOne() { if (joinableType.isEntityType()) { EntityType etype = (EntityType) joinableType; return etype.isOneToOne() /*&& etype.isReferenceToPrimaryKey()*/; } else { return false; } }
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) : ""; }
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); } }
/** * Does the mapping, and Hibernate default semantics, specify that this association should be * fetched by outer joining */ protected boolean isJoinedFetchEnabledInMapping(FetchMode config, AssociationType type) throws MappingException { if (!type.isEntityType() && !type.isCollectionType()) { return false; } else { if (config == FetchMode.JOIN) return true; if (config == FetchMode.SELECT) return false; if (type.isEntityType()) { // TODO: look at the owning property and check that it // isn't lazy (by instrumentation) EntityType entityType = (EntityType) type; EntityPersister persister = getFactory().getEntityPersister(entityType.getAssociatedEntityName()); return !persister.hasProxy(); } else { return false; } } }
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(); }
protected void setRelatedClassType( GrailsHibernateDomainClassProperty prop, AssociationType assType, Type hibernateType) { try { String associatedEntity = assType.getAssociatedEntityName((SessionFactoryImplementor) getSessionFactory()); ClassMetadata associatedMetaData = getSessionFactory().getClassMetadata(associatedEntity); prop.setRelatedClassType(associatedMetaData.getMappedClass(EntityMode.POJO)); } catch (MappingException me) { // other side must be a value object if (hibernateType.isCollectionType()) { prop.setRelatedClassType(Collection.class); } } }
/** * 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); } } }
/** * Determine the appropriate associationType of join (if any) to use to fetch the given * association. * * @param associationType The association associationType. * @param config The metadata-defined fetch mode. * @param path The path to the association * @param lhsTable The owner table * @param lhsColumns The owner join columns * @param nullable Is the association nullable. * @param currentDepth Current join depth * @param cascadeStyle The metadata-defined cascade style. * @return type of join to use ({@link org.hibernate.sql.JoinType#INNER_JOIN}, {@link * org.hibernate.sql.JoinType#LEFT_OUTER_JOIN}, or -1 to indicate no joining. * @throws MappingException ?? */ protected JoinType getJoinType( AssociationType associationType, FetchMode config, PropertyPath path, String lhsTable, String[] lhsColumns, boolean nullable, int currentDepth, CascadeStyle cascadeStyle) throws MappingException { if (!isJoinedFetchEnabled(associationType, config, cascadeStyle)) { return JoinType.NONE; } if (isTooDeep(currentDepth) || (associationType.isCollectionType() && isTooManyCollections())) { return JoinType.NONE; } if (isDuplicateAssociation(lhsTable, lhsColumns, associationType)) { return JoinType.NONE; } return getJoinType(nullable, currentDepth); }
// $Id: CascadeEntityJoinWalker.java,v 1.1 2005/07/26 05:51:47 oneovthafew Exp $
public boolean isCollection() { return joinableType.isCollectionType(); }
public String getRHSUniqueKeyName() { return joinableType.getRHSUniqueKeyPropertyName(); }
/** Override on subclasses to enable or suppress joining of certain association types */ protected boolean isJoinedFetchEnabled( AssociationType type, FetchMode config, CascadeStyle cascadeStyle) { return type.isEntityType() && isJoinedFetchEnabledInMapping(config, type); }
protected JoinType getJoinType( OuterJoinLoadable persister, final PropertyPath path, int propertyNumber, AssociationType associationType, FetchMode metadataFetchMode, CascadeStyle metadataCascadeStyle, String lhsTable, String[] lhsColumns, final boolean nullable, final int currentDepth) throws MappingException { final JoinType resolvedJoinType; if (translator.isJoin(path.getFullPath())) { resolvedJoinType = translator.getJoinType(path.getFullPath()); } else { if (translator.hasProjection()) { resolvedJoinType = JoinType.NONE; } else { FetchMode fetchMode = translator.getRootCriteria().getFetchMode(path.getFullPath()); if (isDefaultFetchMode(fetchMode)) { if (persister != null) { if (isJoinFetchEnabledByProfile(persister, path, propertyNumber)) { if (isDuplicateAssociation(lhsTable, lhsColumns, associationType)) { resolvedJoinType = JoinType.NONE; } else if (isTooDeep(currentDepth) || (associationType.isCollectionType() && isTooManyCollections())) { resolvedJoinType = JoinType.NONE; } else { resolvedJoinType = getJoinType(nullable, currentDepth); } } else { resolvedJoinType = super.getJoinType( persister, path, propertyNumber, associationType, metadataFetchMode, metadataCascadeStyle, lhsTable, lhsColumns, nullable, currentDepth); } } else { resolvedJoinType = super.getJoinType( associationType, metadataFetchMode, path, lhsTable, lhsColumns, nullable, currentDepth, metadataCascadeStyle); } } else { if (fetchMode == FetchMode.JOIN) { isDuplicateAssociation( lhsTable, lhsColumns, associationType); // deliberately ignore return value! resolvedJoinType = getJoinType(nullable, currentDepth); } else { resolvedJoinType = JoinType.NONE; } } } } return resolvedJoinType; }
@Override protected Class getClassForAssociationType(AssociationType type) { String otherSideEntityName = type.getAssociatedEntityName((SessionFactoryImplementor) sessionFactory); return sessionFactory.getClassMetadata(otherSideEntityName).getMappedClass(EntityMode.POJO); }