📄 pathexpressionparser.java
字号:
//$Id: PathExpressionParser.java 10830 2006-11-16 20:22:07Z steve.ebersole@jboss.com $package org.hibernate.hql.classic;import java.util.LinkedList;import java.util.Map;import org.hibernate.MappingException;import org.hibernate.QueryException;import org.hibernate.engine.JoinSequence;import org.hibernate.hql.CollectionSubqueryFactory;import org.hibernate.persister.collection.CollectionPropertyMapping;import org.hibernate.persister.collection.QueryableCollection;import org.hibernate.persister.entity.EntityPersister;import org.hibernate.persister.entity.PropertyMapping;import org.hibernate.persister.entity.Queryable;import org.hibernate.sql.JoinFragment;import org.hibernate.type.AssociationType;import org.hibernate.type.CollectionType;import org.hibernate.type.EntityType;import org.hibernate.type.Type;import org.hibernate.type.TypeFactory;/** * Parses an expression of the form foo.bar.baz and builds up an expression * involving two less table joins than there are path components. */public class PathExpressionParser implements Parser { //TODO: this class does too many things! we need a different //kind of path expression parser for each of the diffferent //ways in which path expressions can occur //We should actually rework this class to not implement Parser //and just process path expressions in the most convenient way. //The class is now way to complex! private int dotcount; private String currentName; private String currentProperty; private String oneToOneOwnerName; private AssociationType ownerAssociationType; private String[] columns; private String collectionName; private String collectionOwnerName; private String collectionRole; private final StringBuffer componentPath = new StringBuffer(); private Type type; private final StringBuffer path = new StringBuffer(); private boolean ignoreInitialJoin; private boolean continuation; private int joinType = JoinFragment.INNER_JOIN; //default mode private boolean useThetaStyleJoin = true; private PropertyMapping currentPropertyMapping; private JoinSequence joinSequence; private boolean expectingCollectionIndex; private LinkedList collectionElements = new LinkedList(); void setJoinType(int joinType) { this.joinType = joinType; } void setUseThetaStyleJoin(boolean useThetaStyleJoin) { this.useThetaStyleJoin = useThetaStyleJoin; } private void addJoin(String name, AssociationType joinableType) throws QueryException { try { joinSequence.addJoin( joinableType, name, joinType, currentColumns() ); } catch ( MappingException me ) { throw new QueryException( me ); } } private void addJoin(String name, AssociationType joinableType, String[] foreignKeyColumns) throws QueryException { try { joinSequence.addJoin( joinableType, name, joinType, foreignKeyColumns ); } catch ( MappingException me ) { throw new QueryException( me ); } } String continueFromManyToMany(String entityName, String[] joinColumns, QueryTranslatorImpl q) throws QueryException { start( q ); continuation = true; currentName = q.createNameFor( entityName ); q.addType( currentName, entityName ); Queryable classPersister = q.getEntityPersister( entityName ); //QueryJoinFragment join = q.createJoinFragment(useThetaStyleJoin); addJoin( currentName, TypeFactory.manyToOne( entityName ), joinColumns ); currentPropertyMapping = classPersister; return currentName; } public void ignoreInitialJoin() { ignoreInitialJoin = true; } 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 ); } } } } private void dereferenceEntity(String propertyName, EntityType propertyType, QueryTranslatorImpl q) throws QueryException { //NOTE: we avoid joining to the next table if the named property is just the foreign key value //if its "id" boolean isIdShortcut = EntityPersister.ENTITY_ID.equals( propertyName ) && propertyType.isReferenceToPrimaryKey(); //or its the id property name final String idPropertyName; try { idPropertyName = propertyType.getIdentifierOrUniqueKeyPropertyName( q.getFactory() ); } catch ( MappingException me ) { throw new QueryException( me ); } boolean isNamedIdPropertyShortcut = idPropertyName != null && idPropertyName.equals( propertyName ) && propertyType.isReferenceToPrimaryKey(); if ( isIdShortcut || isNamedIdPropertyShortcut ) { // special shortcut for id properties, skip the join! // this must only occur at the _end_ of a path expression if ( componentPath.length() > 0 ) componentPath.append( '.' ); componentPath.append( propertyName ); } else { String entityClass = propertyType.getAssociatedEntityName(); String name = q.createNameFor( entityClass ); q.addType( name, entityClass ); addJoin( name, propertyType ); if ( propertyType.isOneToOne() ) oneToOneOwnerName = currentName; ownerAssociationType = propertyType; currentName = name; currentProperty = propertyName; q.addPathAliasAndJoin( path.substring( 0, path.toString().lastIndexOf( '.' ) ), name, joinSequence.copy() ); componentPath.setLength( 0 ); currentPropertyMapping = q.getEntityPersister( entityClass ); } } private void dereferenceComponent(String propertyName) { if ( propertyName != null ) { if ( componentPath.length() > 0 ) componentPath.append( '.' ); componentPath.append( propertyName ); } } private void dereferenceCollection(String propertyName, String role, QueryTranslatorImpl q) throws QueryException { collectionRole = role; QueryableCollection collPersister = q.getCollectionPersister( role ); String name = q.createNameForCollection( role ); addJoin( name, collPersister.getCollectionType() ); //if ( collPersister.hasWhere() ) join.addCondition( collPersister.getSQLWhereString(name) ); collectionName = name; collectionOwnerName = currentName; currentName = name; currentProperty = propertyName; componentPath.setLength( 0 ); currentPropertyMapping = new CollectionPropertyMapping( collPersister ); } private String getPropertyPath() { if ( currentProperty == null ) { return EntityPersister.ENTITY_ID; } else { if ( componentPath.length() > 0 ) { return new StringBuffer() .append( currentProperty ) .append( '.' ) .append( componentPath.toString() ) .toString(); } else { return currentProperty; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -