mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-28 14:59:12 +00:00
HHH-5645 - Criteria.createAlias with specified criterion results in wrong parameters passed into SQL statement
This commit is contained in:
parent
eaeda2f41d
commit
dbd5f81f79
@ -6,6 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.loader;
|
package org.hibernate.loader;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
@ -24,6 +26,7 @@
|
|||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public abstract class OuterJoinLoader extends BasicLoader {
|
public abstract class OuterJoinLoader extends BasicLoader {
|
||||||
|
|
||||||
protected Loadable[] persisters;
|
protected Loadable[] persisters;
|
||||||
protected CollectionPersister[] collectionPersisters;
|
protected CollectionPersister[] collectionPersisters;
|
||||||
protected int[] collectionOwners;
|
protected int[] collectionOwners;
|
||||||
@ -35,6 +38,7 @@ public abstract class OuterJoinLoader extends BasicLoader {
|
|||||||
protected String sql;
|
protected String sql;
|
||||||
protected String[] suffixes;
|
protected String[] suffixes;
|
||||||
protected String[] collectionSuffixes;
|
protected String[] collectionSuffixes;
|
||||||
|
protected List associations;
|
||||||
|
|
||||||
private LoadQueryInfluencers loadQueryInfluencers;
|
private LoadQueryInfluencers loadQueryInfluencers;
|
||||||
|
|
||||||
@ -110,6 +114,7 @@ protected void initFromWalker(JoinWalker walker) {
|
|||||||
collectionOwners = walker.getCollectionOwners();
|
collectionOwners = walker.getCollectionOwners();
|
||||||
sql = walker.getSQLString();
|
sql = walker.getSQLString();
|
||||||
aliases = walker.getAliases();
|
aliases = walker.getAliases();
|
||||||
|
associations = walker.getAssociations();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -28,6 +29,7 @@
|
|||||||
import org.hibernate.internal.CriteriaImpl;
|
import org.hibernate.internal.CriteriaImpl;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.loader.OuterJoinLoader;
|
import org.hibernate.loader.OuterJoinLoader;
|
||||||
|
import org.hibernate.loader.OuterJoinableAssociation;
|
||||||
import org.hibernate.loader.spi.AfterLoadAction;
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.persister.entity.Loadable;
|
import org.hibernate.persister.entity.Loadable;
|
||||||
import org.hibernate.persister.entity.Lockable;
|
import org.hibernate.persister.entity.Lockable;
|
||||||
@ -86,8 +88,9 @@ public CriteriaLoader(
|
|||||||
loadQueryInfluencers
|
loadQueryInfluencers
|
||||||
);
|
);
|
||||||
|
|
||||||
initFromWalker( walker );
|
initFromWalker(walker);
|
||||||
|
|
||||||
|
translator.setAssociations(getAssociationPaths());
|
||||||
userAliases = walker.getUserAliases();
|
userAliases = walker.getUserAliases();
|
||||||
resultTypes = walker.getResultTypes();
|
resultTypes = walker.getResultTypes();
|
||||||
includeInResultRow = walker.includeInResultRow();
|
includeInResultRow = walker.includeInResultRow();
|
||||||
@ -97,11 +100,24 @@ public CriteriaLoader(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<String> getAssociationPaths() {
|
||||||
|
Set<String> associationPaths = new HashSet<>();
|
||||||
|
for ( Object association : this.associations ) {
|
||||||
|
if ( association instanceof OuterJoinableAssociation ) {
|
||||||
|
OuterJoinableAssociation outerJoinableAssociation = (OuterJoinableAssociation) association;
|
||||||
|
if ( outerJoinableAssociation.getPropertyPath() != null ) {
|
||||||
|
associationPaths.add( outerJoinableAssociation.getPropertyPath().getFullPath() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return associationPaths;
|
||||||
|
}
|
||||||
|
|
||||||
public ScrollableResultsImplementor scroll(SharedSessionContractImplementor session, ScrollMode scrollMode)
|
public ScrollableResultsImplementor scroll(SharedSessionContractImplementor session, ScrollMode scrollMode)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
QueryParameters qp = translator.getQueryParameters();
|
QueryParameters qp = translator.getQueryParameters();
|
||||||
qp.setScrollMode( scrollMode );
|
qp.setScrollMode(scrollMode);
|
||||||
return scroll( qp, resultTypes, null, session );
|
return scroll(qp, resultTypes, null, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List list(SharedSessionContractImplementor session)
|
public List list(SharedSessionContractImplementor session)
|
||||||
@ -138,7 +154,7 @@ protected Object getResultColumnOrRow(
|
|||||||
SharedSessionContractImplementor session)
|
SharedSessionContractImplementor session)
|
||||||
throws SQLException, HibernateException {
|
throws SQLException, HibernateException {
|
||||||
return resolveResultTransformer( transformer ).transformTuple(
|
return resolveResultTransformer( transformer ).transformTuple(
|
||||||
getResultRow( row, rs, session ),
|
getResultRow( row, rs, session),
|
||||||
getResultRowAliases()
|
getResultRowAliases()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -151,14 +167,14 @@ protected Object[] getResultRow(Object[] row, ResultSet rs, SharedSessionContrac
|
|||||||
Type[] types = translator.getProjectedTypes();
|
Type[] types = translator.getProjectedTypes();
|
||||||
result = new Object[types.length];
|
result = new Object[types.length];
|
||||||
String[] columnAliases = translator.getProjectedColumnAliases();
|
String[] columnAliases = translator.getProjectedColumnAliases();
|
||||||
for ( int i = 0, pos = 0; i < result.length; i++ ) {
|
for ( int i=0, pos=0; i<result.length; i++ ) {
|
||||||
int numColumns = types[i].getColumnSpan( session.getFactory() );
|
int numColumns = types[i].getColumnSpan( session.getFactory() );
|
||||||
if ( numColumns > 1 ) {
|
if ( numColumns > 1 ) {
|
||||||
String[] typeColumnAliases = ArrayHelper.slice( columnAliases, pos, numColumns );
|
String[] typeColumnAliases = ArrayHelper.slice( columnAliases, pos, numColumns );
|
||||||
result[i] = types[i].nullSafeGet( rs, typeColumnAliases, session, null );
|
result[i] = types[i].nullSafeGet(rs, typeColumnAliases, session, null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result[i] = types[i].nullSafeGet( rs, columnAliases[pos], session, null );
|
result[i] = types[i].nullSafeGet(rs, columnAliases[pos], session, null);
|
||||||
}
|
}
|
||||||
pos += numColumns;
|
pos += numColumns;
|
||||||
}
|
}
|
||||||
@ -174,7 +190,7 @@ private Object[] toResultRow(Object[] row) {
|
|||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Object[] result = new Object[resultRowLength];
|
Object[] result = new Object[ resultRowLength ];
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for ( int i = 0; i < row.length; i++ ) {
|
for ( int i = 0; i < row.length; i++ ) {
|
||||||
if ( includeInResultRow[i] ) {
|
if ( includeInResultRow[i] ) {
|
||||||
@ -208,7 +224,7 @@ protected String applyLocks(
|
|||||||
if ( ( parameters.getLockOptions().getFollowOnLocking() == null && dialect.useFollowOnLocking( parameters ) ) ||
|
if ( ( parameters.getLockOptions().getFollowOnLocking() == null && dialect.useFollowOnLocking( parameters ) ) ||
|
||||||
( parameters.getLockOptions().getFollowOnLocking() != null && parameters.getLockOptions().getFollowOnLocking() ) ) {
|
( parameters.getLockOptions().getFollowOnLocking() != null && parameters.getLockOptions().getFollowOnLocking() ) ) {
|
||||||
final LockMode lockMode = determineFollowOnLockMode( lockOptions );
|
final LockMode lockMode = determineFollowOnLockMode( lockOptions );
|
||||||
if ( lockMode != LockMode.UPGRADE_SKIPLOCKED ) {
|
if( lockMode != LockMode.UPGRADE_SKIPLOCKED ) {
|
||||||
// Dialect prefers to perform locking in a separate step
|
// Dialect prefers to perform locking in a separate step
|
||||||
LOG.usingFollowOnLocking();
|
LOG.usingFollowOnLocking();
|
||||||
|
|
||||||
@ -229,16 +245,16 @@ public void afterLoad(SharedSessionContractImplementor session, Object entity, L
|
|||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final LockOptions locks = new LockOptions( lockOptions.getLockMode() );
|
final LockOptions locks = new LockOptions(lockOptions.getLockMode());
|
||||||
locks.setScope( lockOptions.getScope() );
|
locks.setScope( lockOptions.getScope());
|
||||||
locks.setTimeOut( lockOptions.getTimeOut() );
|
locks.setTimeOut( lockOptions.getTimeOut());
|
||||||
|
|
||||||
final Map<String,String[]> keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
|
final Map<String,String[]> keyColumnNames = dialect.forUpdateOfColumns() ? new HashMap() : null;
|
||||||
final String[] drivingSqlAliases = getAliases();
|
final String[] drivingSqlAliases = getAliases();
|
||||||
for ( int i = 0; i < drivingSqlAliases.length; i++ ) {
|
for ( int i = 0; i < drivingSqlAliases.length; i++ ) {
|
||||||
final LockMode lockMode = lockOptions.getAliasSpecificLockMode( drivingSqlAliases[i] );
|
final LockMode lockMode = lockOptions.getAliasSpecificLockMode( drivingSqlAliases[i] );
|
||||||
if ( lockMode != null ) {
|
if ( lockMode != null ) {
|
||||||
final Lockable drivingPersister = (Lockable) getEntityPersisters()[i];
|
final Lockable drivingPersister = ( Lockable ) getEntityPersisters()[i];
|
||||||
final String rootSqlAlias = drivingPersister.getRootTableAlias( drivingSqlAliases[i] );
|
final String rootSqlAlias = drivingPersister.getRootTableAlias( drivingSqlAliases[i] );
|
||||||
locks.setAliasSpecificLockMode( rootSqlAlias, lockMode );
|
locks.setAliasSpecificLockMode( rootSqlAlias, lockMode );
|
||||||
if ( keyColumnNames != null ) {
|
if ( keyColumnNames != null ) {
|
||||||
@ -270,9 +286,9 @@ protected LockMode[] getLockModes(LockOptions lockOptions) {
|
|||||||
}
|
}
|
||||||
final int size = entityAliases.length;
|
final int size = entityAliases.length;
|
||||||
LockMode[] lockModesArray = new LockMode[size];
|
LockMode[] lockModesArray = new LockMode[size];
|
||||||
for ( int i = 0; i < size; i++ ) {
|
for ( int i=0; i<size; i++ ) {
|
||||||
LockMode lockMode = lockOptions.getAliasSpecificLockMode( entityAliases[i] );
|
LockMode lockMode = lockOptions.getAliasSpecificLockMode( entityAliases[i] );
|
||||||
lockModesArray[i] = lockMode == null ? lockOptions.getLockMode() : lockMode;
|
lockModesArray[i] = lockMode==null ? lockOptions.getLockMode() : lockMode;
|
||||||
}
|
}
|
||||||
return lockModesArray;
|
return lockModesArray;
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,12 @@
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -63,8 +65,9 @@ public class CriteriaQueryTranslator implements CriteriaQuery {
|
|||||||
private final Map<Criteria, String> criteriaSQLAliasMap = new HashMap<Criteria, String>();
|
private final Map<Criteria, String> criteriaSQLAliasMap = new HashMap<Criteria, String>();
|
||||||
private final Map<String, Criteria> aliasCriteriaMap = new HashMap<String, Criteria>();
|
private final Map<String, Criteria> aliasCriteriaMap = new HashMap<String, Criteria>();
|
||||||
private final Map<String, Criteria> associationPathCriteriaMap = new LinkedHashMap<String, Criteria>();
|
private final Map<String, Criteria> associationPathCriteriaMap = new LinkedHashMap<String, Criteria>();
|
||||||
private final Map<String, JoinType> associationPathJoinTypesMap = new LinkedHashMap<String, JoinType>();
|
private final Map<String, JoinType> associationPathJoinTypesMap = new LinkedHashMap<String,JoinType>();
|
||||||
private final Map<String, Criterion> withClauseMap = new HashMap<String, Criterion>();
|
private final Map<String, Criterion> withClauseMap = new HashMap<String, Criterion>();
|
||||||
|
private Set<String> associations;
|
||||||
|
|
||||||
private final SessionFactoryImplementor sessionFactory;
|
private final SessionFactoryImplementor sessionFactory;
|
||||||
private final SessionFactoryHelper helper;
|
private final SessionFactoryHelper helper;
|
||||||
@ -88,13 +91,17 @@ public CriteriaQueryTranslator(
|
|||||||
this.rootEntityName = rootEntityName;
|
this.rootEntityName = rootEntityName;
|
||||||
this.sessionFactory = factory;
|
this.sessionFactory = factory;
|
||||||
this.rootSQLAlias = rootSQLAlias;
|
this.rootSQLAlias = rootSQLAlias;
|
||||||
this.helper = new SessionFactoryHelper( factory );
|
this.helper = new SessionFactoryHelper(factory);
|
||||||
createAliasCriteriaMap();
|
createAliasCriteriaMap();
|
||||||
createAssociationPathCriteriaMap();
|
createAssociationPathCriteriaMap();
|
||||||
createCriteriaEntityNameMap();
|
createCriteriaEntityNameMap();
|
||||||
createCriteriaSQLAliasMap();
|
createCriteriaSQLAliasMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAssociations(Set<String> associations) {
|
||||||
|
this.associations = associations;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String generateSQLAlias() {
|
public String generateSQLAlias() {
|
||||||
int aliasCount = 0;
|
int aliasCount = 0;
|
||||||
@ -195,7 +202,7 @@ private String getWholeAssociationPath(CriteriaImpl.Subcriteria subcriteria) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// otherwise, recurse
|
// otherwise, recurse
|
||||||
return getWholeAssociationPath( (CriteriaImpl.Subcriteria) parent ) + '.' + path;
|
return getWholeAssociationPath( ( CriteriaImpl.Subcriteria ) parent ) + '.' + path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +211,7 @@ private void createCriteriaEntityNameMap() {
|
|||||||
final CriteriaInfoProvider rootProvider = new EntityCriteriaInfoProvider(
|
final CriteriaInfoProvider rootProvider = new EntityCriteriaInfoProvider(
|
||||||
(Queryable) sessionFactory.getEntityPersister( rootEntityName )
|
(Queryable) sessionFactory.getEntityPersister( rootEntityName )
|
||||||
);
|
);
|
||||||
criteriaInfoMap.put( rootCriteria, rootProvider );
|
criteriaInfoMap.put( rootCriteria, rootProvider);
|
||||||
nameCriteriaInfoMap.put( rootProvider.getName(), rootProvider );
|
nameCriteriaInfoMap.put( rootProvider.getName(), rootProvider );
|
||||||
|
|
||||||
for ( final String key : associationPathCriteriaMap.keySet() ) {
|
for ( final String key : associationPathCriteriaMap.keySet() ) {
|
||||||
@ -229,11 +236,11 @@ private CriteriaInfoProvider getPathInfo(String path) {
|
|||||||
if ( type.isAssociationType() ) {
|
if ( type.isAssociationType() ) {
|
||||||
// CollectionTypes are always also AssociationTypes - but there's not always an associated entity...
|
// CollectionTypes are always also AssociationTypes - but there's not always an associated entity...
|
||||||
final AssociationType atype = (AssociationType) type;
|
final AssociationType atype = (AssociationType) type;
|
||||||
final CollectionType ctype = type.isCollectionType() ? (CollectionType) type : null;
|
final CollectionType ctype = type.isCollectionType() ? (CollectionType)type : null;
|
||||||
final Type elementType = ( ctype != null ) ? ctype.getElementType( sessionFactory ) : null;
|
final 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?)
|
// is the association a collection of components or value-types? (i.e a colloction of valued types?)
|
||||||
if ( ctype != null && elementType.isComponentType() ) {
|
if ( ctype != null && elementType.isComponentType() ) {
|
||||||
provider = new ComponentCollectionCriteriaInfoProvider( helper.getCollectionPersister( ctype.getRole() ) );
|
provider = new ComponentCollectionCriteriaInfoProvider( helper.getCollectionPersister(ctype.getRole()) );
|
||||||
}
|
}
|
||||||
else if ( ctype != null && !elementType.isEntityType() ) {
|
else if ( ctype != null && !elementType.isEntityType() ) {
|
||||||
provider = new ScalarCollectionCriteriaInfoProvider( helper, ctype.getRole() );
|
provider = new ScalarCollectionCriteriaInfoProvider( helper, ctype.getRole() );
|
||||||
@ -247,7 +254,7 @@ else if ( ctype != null && !elementType.isEntityType() ) {
|
|||||||
componentPath = "";
|
componentPath = "";
|
||||||
}
|
}
|
||||||
else if ( type.isComponentType() ) {
|
else if ( type.isComponentType() ) {
|
||||||
if ( !tokens.hasMoreTokens() ) {
|
if (!tokens.hasMoreTokens()) {
|
||||||
throw new QueryException(
|
throw new QueryException(
|
||||||
"Criteria objects cannot be created directly on components. Create a criteria on " +
|
"Criteria objects cannot be created directly on components. Create a criteria on " +
|
||||||
"owning entity and use a dotted property to access component property: " + path
|
"owning entity and use a dotted property to access component property: " + path
|
||||||
@ -271,7 +278,7 @@ public int getSQLAliasCount() {
|
|||||||
|
|
||||||
private void createCriteriaSQLAliasMap() {
|
private void createCriteriaSQLAliasMap() {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for ( final Criteria crit : criteriaInfoMap.keySet() ) {
|
for(final Criteria crit : criteriaInfoMap.keySet()){
|
||||||
final CriteriaInfoProvider value = criteriaInfoMap.get( crit );
|
final CriteriaInfoProvider value = criteriaInfoMap.get( crit );
|
||||||
String alias = crit.getAlias();
|
String alias = crit.getAlias();
|
||||||
if ( alias == null ) {
|
if ( alias == null ) {
|
||||||
@ -304,6 +311,9 @@ public QueryParameters getQueryParameters() {
|
|||||||
|
|
||||||
final List<Object> values = new ArrayList<Object>();
|
final List<Object> values = new ArrayList<Object>();
|
||||||
final List<Type> types = new ArrayList<Type>();
|
final List<Type> types = new ArrayList<Type>();
|
||||||
|
final Map<String, String> aliasMap = new HashMap<String, String>();
|
||||||
|
final Map<String, Collection<Object>> valueMap = new HashMap<String, Collection<Object>>();
|
||||||
|
final Map<String, Collection<Type>> typeMap = new HashMap<String, Collection<Type>>();
|
||||||
final Iterator<CriteriaImpl.Subcriteria> subcriteriaIterator = rootCriteria.iterateSubcriteria();
|
final Iterator<CriteriaImpl.Subcriteria> subcriteriaIterator = rootCriteria.iterateSubcriteria();
|
||||||
while ( subcriteriaIterator.hasNext() ) {
|
while ( subcriteriaIterator.hasNext() ) {
|
||||||
final CriteriaImpl.Subcriteria subcriteria = subcriteriaIterator.next();
|
final CriteriaImpl.Subcriteria subcriteria = subcriteriaIterator.next();
|
||||||
@ -311,11 +321,65 @@ public QueryParameters getQueryParameters() {
|
|||||||
if ( lm != null ) {
|
if ( lm != null ) {
|
||||||
lockOptions.setAliasSpecificLockMode( getSQLAlias( subcriteria ), lm );
|
lockOptions.setAliasSpecificLockMode( getSQLAlias( subcriteria ), lm );
|
||||||
}
|
}
|
||||||
|
aliasMap.put(subcriteria.getPath(), subcriteria.getAlias());
|
||||||
if ( subcriteria.getWithClause() != null ) {
|
if ( subcriteria.getWithClause() != null ) {
|
||||||
final TypedValue[] tv = subcriteria.getWithClause().getTypedValues( subcriteria, this );
|
final TypedValue[] tv = subcriteria.getWithClause().getTypedValues( subcriteria, this );
|
||||||
for ( TypedValue aTv : tv ) {
|
for ( TypedValue aTv : tv ) {
|
||||||
values.add( aTv.getValue() );
|
Collection<Object> valueCollection = valueMap.get( subcriteria.getPath() );
|
||||||
types.add( aTv.getType() );
|
Collection<Type> typeCollection = typeMap.get( subcriteria.getPath() );
|
||||||
|
if ( valueCollection == null ) {
|
||||||
|
valueCollection = new LinkedList<>();
|
||||||
|
valueMap.put( subcriteria.getPath(), valueCollection );
|
||||||
|
}
|
||||||
|
if ( typeCollection == null ) {
|
||||||
|
typeCollection = new LinkedList<>();
|
||||||
|
typeMap.put( subcriteria.getPath(), typeCollection );
|
||||||
|
}
|
||||||
|
valueCollection.add( aTv.getValue() );
|
||||||
|
typeCollection.add( aTv.getType() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( associations != null ) {
|
||||||
|
for ( String association : this.associations ) {
|
||||||
|
if ( association.contains( "." ) ) {
|
||||||
|
String alias = null;
|
||||||
|
String[] pathArray = association.split( "\\." );
|
||||||
|
for ( int i = 0; i < pathArray.length; i++ ) {
|
||||||
|
String element = pathArray[i];
|
||||||
|
if ( i == ( pathArray.length - 1 ) ) {
|
||||||
|
Collection<Object> valueList = valueMap.get( alias + "." + element );
|
||||||
|
Collection<Type> typeList = typeMap.get( alias + "." + element );
|
||||||
|
if ( typeList != null ) {
|
||||||
|
values.addAll( valueList );
|
||||||
|
types.addAll( typeList );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( alias == null ) {
|
||||||
|
alias = aliasMap.get( element );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alias = aliasMap.get( alias + "." + element );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
String matchingAssociation = null;
|
||||||
|
for ( Map.Entry<String, Collection<Type>> typeEntry : typeMap.entrySet() ) {
|
||||||
|
String path = typeEntry.getKey();
|
||||||
|
if ( path.equals( association ) || path.endsWith( "." + association ) ) {
|
||||||
|
matchingAssociation = path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( matchingAssociation != null ) {
|
||||||
|
Collection<Object> valueList = valueMap.get( matchingAssociation );
|
||||||
|
Collection<Type> typeList = typeMap.get( matchingAssociation );
|
||||||
|
if ( typeList != null ) {
|
||||||
|
values.addAll( valueList );
|
||||||
|
types.addAll( typeList );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -384,7 +448,7 @@ public Type[] getProjectedTypes() {
|
|||||||
|
|
||||||
public String[] getProjectedColumnAliases() {
|
public String[] getProjectedColumnAliases() {
|
||||||
return rootCriteria.getProjection() instanceof EnhancedProjection ?
|
return rootCriteria.getProjection() instanceof EnhancedProjection ?
|
||||||
( (EnhancedProjection) rootCriteria.getProjection() ).getColumnAliases( 0, rootCriteria, this ) :
|
( ( EnhancedProjection ) rootCriteria.getProjection() ).getColumnAliases( 0, rootCriteria, this ) :
|
||||||
rootCriteria.getProjection().getColumnAliases( 0 );
|
rootCriteria.getProjection().getColumnAliases( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +522,7 @@ public String[] getColumnsUsingProjection(
|
|||||||
String[] projectionColumns = null;
|
String[] projectionColumns = null;
|
||||||
if ( projection != null ) {
|
if ( projection != null ) {
|
||||||
projectionColumns = ( projection instanceof EnhancedProjection ?
|
projectionColumns = ( projection instanceof EnhancedProjection ?
|
||||||
( (EnhancedProjection) projection ).getColumnAliases( propertyName, 0, rootCriteria, this ) :
|
( ( EnhancedProjection ) projection ).getColumnAliases( propertyName, 0, rootCriteria, this ) :
|
||||||
projection.getColumnAliases( propertyName, 0 )
|
projection.getColumnAliases( propertyName, 0 )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -468,7 +532,7 @@ public String[] getColumnsUsingProjection(
|
|||||||
try {
|
try {
|
||||||
return getColumns( propertyName, subcriteria );
|
return getColumns( propertyName, subcriteria );
|
||||||
}
|
}
|
||||||
catch (HibernateException he) {
|
catch ( HibernateException he ) {
|
||||||
//not found in inner query , try the outer query
|
//not found in inner query , try the outer query
|
||||||
if ( outerQueryTranslator != null ) {
|
if ( outerQueryTranslator != null ) {
|
||||||
return outerQueryTranslator.getColumnsUsingProjection( subcriteria, propertyName );
|
return outerQueryTranslator.getColumnsUsingProjection( subcriteria, propertyName );
|
||||||
@ -487,18 +551,18 @@ public String[] getColumnsUsingProjection(
|
|||||||
@Override
|
@Override
|
||||||
public String[] getIdentifierColumns(Criteria criteria) {
|
public String[] getIdentifierColumns(Criteria criteria) {
|
||||||
String[] idcols =
|
String[] idcols =
|
||||||
( (Loadable) getPropertyMapping( getEntityName( criteria ) ) ).getIdentifierColumnNames();
|
( ( Loadable ) getPropertyMapping( getEntityName( criteria ) ) ).getIdentifierColumnNames();
|
||||||
return StringHelper.qualify( getSQLAlias( criteria ), idcols );
|
return StringHelper.qualify( getSQLAlias( criteria ), idcols );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getIdentifierType(Criteria criteria) {
|
public Type getIdentifierType(Criteria criteria) {
|
||||||
return ( (Loadable) getPropertyMapping( getEntityName( criteria ) ) ).getIdentifierType();
|
return ( ( Loadable ) getPropertyMapping( getEntityName( criteria ) ) ).getIdentifierType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TypedValue getTypedIdentifierValue(Criteria criteria, Object value) {
|
public TypedValue getTypedIdentifierValue(Criteria criteria, Object value) {
|
||||||
final Loadable loadable = (Loadable) getPropertyMapping( getEntityName( criteria ) );
|
final Loadable loadable = ( Loadable ) getPropertyMapping( getEntityName( criteria ) );
|
||||||
return new TypedValue( loadable.getIdentifierType(), value );
|
return new TypedValue( loadable.getIdentifierType(), value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -519,12 +583,12 @@ public String[] getColumns(
|
|||||||
* Projection aliases are ignored.
|
* Projection aliases are ignored.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String[] findColumns(String propertyName, Criteria subcriteria)
|
public String[] findColumns(String propertyName, Criteria subcriteria )
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
try {
|
try {
|
||||||
return getColumns( propertyName, subcriteria );
|
return getColumns( propertyName, subcriteria );
|
||||||
}
|
}
|
||||||
catch (HibernateException he) {
|
catch ( HibernateException he ) {
|
||||||
//not found in inner query, try the outer query
|
//not found in inner query, try the outer query
|
||||||
if ( outerQueryTranslator != null ) {
|
if ( outerQueryTranslator != null ) {
|
||||||
return outerQueryTranslator.findColumns( propertyName, subcriteria );
|
return outerQueryTranslator.findColumns( propertyName, subcriteria );
|
||||||
@ -551,7 +615,7 @@ public Type getTypeUsingProjection(Criteria subcriteria, String propertyName)
|
|||||||
//look for a property
|
//look for a property
|
||||||
return getType( subcriteria, propertyName );
|
return getType( subcriteria, propertyName );
|
||||||
}
|
}
|
||||||
catch (HibernateException he) {
|
catch ( HibernateException he ) {
|
||||||
//not found in inner query , try the outer query
|
//not found in inner query , try the outer query
|
||||||
if ( outerQueryTranslator != null ) {
|
if ( outerQueryTranslator != null ) {
|
||||||
return outerQueryTranslator.getType( subcriteria, propertyName );
|
return outerQueryTranslator.getType( subcriteria, propertyName );
|
||||||
@ -666,5 +730,4 @@ public boolean hasRestriction(String path) {
|
|||||||
final CriteriaImpl.Subcriteria subcriteria = (CriteriaImpl.Subcriteria) getCriteria( path );
|
final CriteriaImpl.Subcriteria subcriteria = (CriteriaImpl.Subcriteria) getCriteria( path );
|
||||||
return subcriteria != null && subcriteria.hasRestriction();
|
return subcriteria != null && subcriteria.hasRestriction();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.query.criteria.internal;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
import org.hibernate.Criteria;
|
||||||
|
import org.hibernate.criterion.CriteriaSpecification;
|
||||||
|
import org.hibernate.criterion.Criterion;
|
||||||
|
import org.hibernate.criterion.ProjectionList;
|
||||||
|
import org.hibernate.criterion.Projections;
|
||||||
|
import org.hibernate.criterion.Restrictions;
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
import org.hibernate.sql.JoinType;
|
||||||
|
|
||||||
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class AliasWithCriterionTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCaseClause() {
|
||||||
|
doInHibernate( this::sessionFactory, session -> {
|
||||||
|
Criteria criteria = session.createCriteria( TableA.class );
|
||||||
|
|
||||||
|
final String TABLE_B_ALIAS = "tableBAlias";
|
||||||
|
final String TABLE_C_ALIAS = "tableCAlias";
|
||||||
|
|
||||||
|
Criterion tableCRestriction = Restrictions.eq( TABLE_C_ALIAS + ".tableCBoolean", false );
|
||||||
|
criteria.createAlias(
|
||||||
|
TABLE_B_ALIAS + ".tableCs",
|
||||||
|
TABLE_C_ALIAS,
|
||||||
|
JoinType.LEFT_OUTER_JOIN,
|
||||||
|
tableCRestriction
|
||||||
|
);
|
||||||
|
|
||||||
|
Criterion tableBRestriction = Restrictions.eq( TABLE_B_ALIAS + ".tableBDate", new Date() );
|
||||||
|
criteria.createAlias( "tableBs", TABLE_B_ALIAS, JoinType.LEFT_OUTER_JOIN, tableBRestriction );
|
||||||
|
|
||||||
|
criteria.add( Restrictions.eq( "tableACharacter", "c" ) );
|
||||||
|
|
||||||
|
ProjectionList projectionList = Projections.projectionList();
|
||||||
|
projectionList.add( Projections.property( "tableACharacter" ) );
|
||||||
|
criteria.setProjection( projectionList );
|
||||||
|
|
||||||
|
criteria.list();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
TableA.class,
|
||||||
|
TableB.class,
|
||||||
|
TableC.class,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "TableA")
|
||||||
|
public static class TableA {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "table_a_id")
|
||||||
|
private Long tableAId;
|
||||||
|
|
||||||
|
@Column(name = "table_a_character")
|
||||||
|
private String tableACharacter;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "tableA")
|
||||||
|
private Set<TableB> tableBs;
|
||||||
|
|
||||||
|
public TableA() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTableAId() {
|
||||||
|
return this.tableAId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableAId_(Long _tableAId_) {
|
||||||
|
this.tableAId = _tableAId_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTableACharacter() {
|
||||||
|
return this.tableACharacter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableACharacter(String _tableACharacter_) {
|
||||||
|
this.tableACharacter = _tableACharacter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<TableB> getTableBs() {
|
||||||
|
return this.tableBs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableBs(Set<TableB> tableBs) {
|
||||||
|
this.tableBs = tableBs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "TableB")
|
||||||
|
public static class TableB {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "table_b_id")
|
||||||
|
private Long tableBId;
|
||||||
|
|
||||||
|
@Column(name = "table_a_id", insertable = false, updatable = false)
|
||||||
|
private Long tableAId;
|
||||||
|
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
@Column(name = "table_b_date")
|
||||||
|
private Date tableBDate;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "table_a_id")
|
||||||
|
private TableA tableA;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "tableB")
|
||||||
|
private Set<TableC> tableCs;
|
||||||
|
|
||||||
|
|
||||||
|
public TableB() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTableBId() {
|
||||||
|
return this.tableBId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableBId(Long _tableBId_) {
|
||||||
|
this.tableBId = _tableBId_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTableAId() {
|
||||||
|
return this.tableAId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableAId(Long _tableAId_) {
|
||||||
|
this.tableAId = _tableAId_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getTableBDate() {
|
||||||
|
return this.tableBDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableBDate(Date _tableBDate_) {
|
||||||
|
this.tableBDate = _tableBDate_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableA getTableA() {
|
||||||
|
return tableA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableA(TableA tableA) {
|
||||||
|
this.tableA = tableA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<TableC> getTableCs() {
|
||||||
|
return tableCs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableCs(Set<TableC> tableCs) {
|
||||||
|
this.tableCs = tableCs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "TableC")
|
||||||
|
public static class TableC {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "table_c_id")
|
||||||
|
private Long tableCId;
|
||||||
|
|
||||||
|
@Column(name = "table_b_id", insertable = false, updatable = false)
|
||||||
|
private Long tableBId;
|
||||||
|
|
||||||
|
@Column(name = "table_c_boolean")
|
||||||
|
private Boolean tableCBoolean;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "table_b_id")
|
||||||
|
private TableB tableB;
|
||||||
|
|
||||||
|
public TableC() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTableCId() {
|
||||||
|
return this.tableCId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableCId(Long tableCId) {
|
||||||
|
this.tableCId = tableCId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTableBId() {
|
||||||
|
return this.tableBId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableBId(Long tableBId) {
|
||||||
|
this.tableBId = tableBId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getTableCBoolean() {
|
||||||
|
return this.tableCBoolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableCBoolean(Boolean tableCBoolean) {
|
||||||
|
this.tableCBoolean = tableCBoolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableB getTableB() {
|
||||||
|
return tableB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableB(TableB tableB) {
|
||||||
|
this.tableB = tableB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user