📄 pathexpressionparser.java
字号:
//$Id: PathExpressionParser.java 6585 2005-04-28 06:50:06Z oneovthafew $
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 );
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 + -