HHH-6974 - Add caching to new "load access" api for natural id loading
This commit is contained in:
parent
368c4cc2bc
commit
199d08210d
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008-2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,18 +20,14 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.criterion;
|
||||
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Conjunction extends Junction {
|
||||
|
||||
public Conjunction() {
|
||||
super("and");
|
||||
super( Nature.AND );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008-2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,18 +20,14 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.criterion;
|
||||
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Disjunction extends Junction {
|
||||
|
||||
protected Disjunction() {
|
||||
super("or");
|
||||
super( Nature.OR );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
package org.hibernate.criterion;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -39,56 +40,65 @@ import org.hibernate.internal.util.StringHelper;
|
|||
* @author Gavin King
|
||||
*/
|
||||
public class Junction implements Criterion {
|
||||
private final Nature nature;
|
||||
private final List<Criterion> conditions = new ArrayList<Criterion>();
|
||||
|
||||
private final List criteria = new ArrayList();
|
||||
private final String op;
|
||||
|
||||
protected Junction(String op) {
|
||||
this.op = op;
|
||||
protected Junction(Nature nature) {
|
||||
this.nature = nature;
|
||||
}
|
||||
|
||||
public Junction add(Criterion criterion) {
|
||||
criteria.add(criterion);
|
||||
conditions.add( criterion );
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getOp() {
|
||||
return op;
|
||||
public Nature getNature() {
|
||||
return nature;
|
||||
}
|
||||
|
||||
public TypedValue[] getTypedValues(Criteria crit, CriteriaQuery criteriaQuery)
|
||||
throws HibernateException {
|
||||
ArrayList typedValues = new ArrayList();
|
||||
Iterator iter = criteria.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
TypedValue[] subvalues = ( (Criterion) iter.next() ).getTypedValues(crit, criteriaQuery);
|
||||
for ( int i=0; i<subvalues.length; i++ ) {
|
||||
typedValues.add( subvalues[i] );
|
||||
}
|
||||
public Iterable<Criterion> conditions() {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue[] getTypedValues(Criteria crit, CriteriaQuery criteriaQuery) throws HibernateException {
|
||||
ArrayList<TypedValue> typedValues = new ArrayList<TypedValue>();
|
||||
for ( Criterion condition : conditions ) {
|
||||
TypedValue[] subValues = condition.getTypedValues( crit, criteriaQuery );
|
||||
Collections.addAll( typedValues, subValues );
|
||||
}
|
||||
return (TypedValue[]) typedValues.toArray( new TypedValue[ typedValues.size() ] );
|
||||
return typedValues.toArray( new TypedValue[ typedValues.size() ] );
|
||||
}
|
||||
|
||||
public String toSqlString(Criteria crit, CriteriaQuery criteriaQuery)
|
||||
throws HibernateException {
|
||||
@Override
|
||||
public String toSqlString(Criteria crit, CriteriaQuery criteriaQuery) throws HibernateException {
|
||||
if ( conditions.size()==0 ) {
|
||||
return "1=1";
|
||||
}
|
||||
|
||||
if ( criteria.size()==0 ) return "1=1";
|
||||
|
||||
StringBuffer buffer = new StringBuffer()
|
||||
.append('(');
|
||||
Iterator iter = criteria.iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
buffer.append( ( (Criterion) iter.next() ).toSqlString(crit, criteriaQuery) );
|
||||
if ( iter.hasNext() ) buffer.append(' ').append(op).append(' ');
|
||||
StringBuilder buffer = new StringBuilder().append( '(' );
|
||||
Iterator itr = conditions.iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
buffer.append( ( (Criterion) itr.next() ).toSqlString( crit, criteriaQuery ) );
|
||||
if ( itr.hasNext() ) {
|
||||
buffer.append(' ').append( nature.getOperator() ).append(' ');
|
||||
}
|
||||
}
|
||||
return buffer.append(')').toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return '(' + StringHelper.join( ' ' + op + ' ', criteria.iterator() ) + ')';
|
||||
return '(' + StringHelper.join( ' ' + nature.getOperator() + ' ', conditions.iterator() ) + ')';
|
||||
}
|
||||
|
||||
public static enum Nature {
|
||||
AND,
|
||||
OR
|
||||
;
|
||||
|
||||
public String getOperator() {
|
||||
return name().toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,11 +20,11 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.criterion;
|
||||
import java.util.HashMap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -39,25 +39,34 @@ import org.hibernate.engine.spi.TypedValue;
|
|||
* @see Session#bySimpleNaturalId(String)
|
||||
*/
|
||||
public class NaturalIdentifier implements Criterion {
|
||||
|
||||
private final Junction conjunction = new Conjunction();
|
||||
private final Map<String, Object> naturalIdValues = new HashMap<String, Object>();
|
||||
private final Conjunction conjunction = new Conjunction();
|
||||
|
||||
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
|
||||
return conjunction.getTypedValues(criteria, criteriaQuery);
|
||||
return conjunction.getTypedValues( criteria, criteriaQuery );
|
||||
}
|
||||
|
||||
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
|
||||
return conjunction.toSqlString(criteria, criteriaQuery);
|
||||
return conjunction.toSqlString( criteria, criteriaQuery );
|
||||
}
|
||||
|
||||
|
||||
public Map<String, Object> getNaturalIdValues() {
|
||||
return naturalIdValues;
|
||||
final Map<String, Object> naturalIdValueMap = new ConcurrentHashMap<String, Object>();
|
||||
for ( Criterion condition : conjunction.conditions() ) {
|
||||
if ( !SimpleExpression.class.isInstance( condition ) ) {
|
||||
continue;
|
||||
}
|
||||
final SimpleExpression equalsCondition = SimpleExpression.class.cast( condition );
|
||||
if ( !"=".equals( equalsCondition.getOp() ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
naturalIdValueMap.put( equalsCondition.getPropertyName(), equalsCondition.getValue() );
|
||||
}
|
||||
return naturalIdValueMap;
|
||||
}
|
||||
|
||||
public NaturalIdentifier set(String property, Object value) {
|
||||
conjunction.add( Restrictions.eq(property, value) );
|
||||
naturalIdValues.put( property, value );
|
||||
conjunction.add( Restrictions.eq( property, value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008-2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
|
@ -20,9 +20,9 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.criterion;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
|
@ -33,10 +33,10 @@ import org.hibernate.type.Type;
|
|||
|
||||
/**
|
||||
* superclass for "simple" comparisons (with SQL binary operators)
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class SimpleExpression implements Criterion {
|
||||
|
||||
private final String propertyName;
|
||||
private final Object value;
|
||||
private boolean ignoreCase;
|
||||
|
@ -61,35 +61,43 @@ public class SimpleExpression implements Criterion {
|
|||
}
|
||||
|
||||
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
|
||||
throws HibernateException {
|
||||
throws HibernateException {
|
||||
|
||||
String[] columns = criteriaQuery.findColumns(propertyName, criteria);
|
||||
Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName);
|
||||
String[] columns = criteriaQuery.findColumns( propertyName, criteria );
|
||||
Type type = criteriaQuery.getTypeUsingProjection( criteria, propertyName );
|
||||
StringBuffer fragment = new StringBuffer();
|
||||
if (columns.length>1) fragment.append('(');
|
||||
if ( columns.length > 1 ) {
|
||||
fragment.append( '(' );
|
||||
}
|
||||
SessionFactoryImplementor factory = criteriaQuery.getFactory();
|
||||
int[] sqlTypes = type.sqlTypes( factory );
|
||||
for ( int i=0; i<columns.length; i++ ) {
|
||||
boolean lower = ignoreCase &&
|
||||
( sqlTypes[i]==Types.VARCHAR || sqlTypes[i]==Types.CHAR );
|
||||
if (lower) {
|
||||
for ( int i = 0; i < columns.length; i++ ) {
|
||||
boolean lower = ignoreCase &&
|
||||
(sqlTypes[i] == Types.VARCHAR || sqlTypes[i] == Types.CHAR);
|
||||
if ( lower ) {
|
||||
fragment.append( factory.getDialect().getLowercaseFunction() )
|
||||
.append('(');
|
||||
.append( '(' );
|
||||
}
|
||||
fragment.append( columns[i] );
|
||||
if (lower) fragment.append(')');
|
||||
fragment.append( getOp() ).append("?");
|
||||
if ( i<columns.length-1 ) fragment.append(" and ");
|
||||
if ( lower ) {
|
||||
fragment.append( ')' );
|
||||
}
|
||||
fragment.append( getOp() ).append( "?" );
|
||||
if ( i < columns.length - 1 ) {
|
||||
fragment.append( " and " );
|
||||
}
|
||||
}
|
||||
if ( columns.length > 1 ) {
|
||||
fragment.append( ')' );
|
||||
}
|
||||
if (columns.length>1) fragment.append(')');
|
||||
return fragment.toString();
|
||||
|
||||
}
|
||||
|
||||
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
|
||||
throws HibernateException {
|
||||
throws HibernateException {
|
||||
Object icvalue = ignoreCase ? value.toString().toLowerCase() : value;
|
||||
return new TypedValue[] { criteriaQuery.getTypedValue(criteria, propertyName, icvalue) };
|
||||
return new TypedValue[] {criteriaQuery.getTypedValue( criteria, propertyName, icvalue )};
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
@ -100,4 +108,11 @@ public class SimpleExpression implements Criterion {
|
|||
return op;
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1496,68 +1496,11 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
dontFlushFromFind--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the CriteriaImpl is a naturalId lookup that can be done via
|
||||
* NaturalIdLoadAccess
|
||||
*
|
||||
* @return A fully configured NaturalIdLoadAccess or null, if null is returned the standard CriteriaImpl execution
|
||||
* should be performed
|
||||
*/
|
||||
private NaturalIdLoadAccess tryNaturalIdLoadAccess(CriteriaImpl criteria) {
|
||||
// See if the criteria lookup is by naturalId
|
||||
if ( !criteria.isLookupByNaturalKey() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String entityName = criteria.getEntityOrClassName();
|
||||
final EntityPersister entityPersister = factory.getEntityPersister( entityName );
|
||||
|
||||
// Verify the entity actually has a natural id, needed for legacy support as NaturalIdentifier criteria
|
||||
// queries did no natural id validation
|
||||
if ( !entityPersister.hasNaturalIdentifier() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Since isLookupByNaturalKey is true there can be only one CriterionEntry and getCriterion() will
|
||||
// return an instanceof NaturalIdentifier
|
||||
final CriterionEntry criterionEntry = (CriterionEntry) criteria.iterateExpressionEntries().next();
|
||||
final NaturalIdentifier naturalIdentifier = (NaturalIdentifier) criterionEntry.getCriterion();
|
||||
|
||||
final Map<String, Object> naturalIdValues = naturalIdentifier.getNaturalIdValues();
|
||||
final int[] naturalIdentifierProperties = entityPersister.getNaturalIdentifierProperties();
|
||||
|
||||
// Verify the NaturalIdentifier criterion includes all naturalId properties, first check that the property counts match
|
||||
if ( naturalIdentifierProperties.length != naturalIdValues.size() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String[] propertyNames = entityPersister.getPropertyNames();
|
||||
final NaturalIdLoadAccess naturalIdLoader = this.byNaturalId( entityName );
|
||||
|
||||
// Build NaturalIdLoadAccess and in the process verify all naturalId properties were specified
|
||||
for ( int i = 0; i < naturalIdentifierProperties.length; i++ ) {
|
||||
final String naturalIdProperty = propertyNames[naturalIdentifierProperties[i]];
|
||||
final Object naturalIdValue = naturalIdValues.get( naturalIdProperty );
|
||||
|
||||
if ( naturalIdValue == null ) {
|
||||
// A NaturalId property is missing from the critera query, can't use NaturalIdLoadAccess
|
||||
return null;
|
||||
}
|
||||
|
||||
naturalIdLoader.using( naturalIdProperty, naturalIdValue );
|
||||
}
|
||||
|
||||
// Critera query contains a valid naturalId, use the new API
|
||||
LOG.warn( "Session.byNaturalId(" + entityName
|
||||
+ ") should be used for naturalId queries instead of Restrictions.naturalId() from a Criteria" );
|
||||
|
||||
return naturalIdLoader;
|
||||
}
|
||||
|
||||
public List list(CriteriaImpl criteria) throws HibernateException {
|
||||
final NaturalIdLoadAccess naturalIdLoadAccess = this.tryNaturalIdLoadAccess( criteria );
|
||||
if ( naturalIdLoadAccess != null ) {
|
||||
// EARLY EXIT!
|
||||
return Arrays.asList( naturalIdLoadAccess.load() );
|
||||
}
|
||||
|
||||
|
@ -1603,6 +1546,66 @@ public final class SessionImpl extends AbstractSessionImpl implements EventSourc
|
|||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the CriteriaImpl is a naturalId lookup that can be done via
|
||||
* NaturalIdLoadAccess
|
||||
*
|
||||
* @param criteria The criteria to check as a complete natural identifier lookup.
|
||||
*
|
||||
* @return A fully configured NaturalIdLoadAccess or null, if null is returned the standard CriteriaImpl execution
|
||||
* should be performed
|
||||
*/
|
||||
private NaturalIdLoadAccess tryNaturalIdLoadAccess(CriteriaImpl criteria) {
|
||||
// See if the criteria lookup is by naturalId
|
||||
if ( !criteria.isLookupByNaturalKey() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String entityName = criteria.getEntityOrClassName();
|
||||
final EntityPersister entityPersister = factory.getEntityPersister( entityName );
|
||||
|
||||
// Verify the entity actually has a natural id, needed for legacy support as NaturalIdentifier criteria
|
||||
// queries did no natural id validation
|
||||
if ( !entityPersister.hasNaturalIdentifier() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Since isLookupByNaturalKey is true there can be only one CriterionEntry and getCriterion() will
|
||||
// return an instanceof NaturalIdentifier
|
||||
final CriterionEntry criterionEntry = (CriterionEntry) criteria.iterateExpressionEntries().next();
|
||||
final NaturalIdentifier naturalIdentifier = (NaturalIdentifier) criterionEntry.getCriterion();
|
||||
|
||||
final Map<String, Object> naturalIdValues = naturalIdentifier.getNaturalIdValues();
|
||||
final int[] naturalIdentifierProperties = entityPersister.getNaturalIdentifierProperties();
|
||||
|
||||
// Verify the NaturalIdentifier criterion includes all naturalId properties, first check that the property counts match
|
||||
if ( naturalIdentifierProperties.length != naturalIdValues.size() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final String[] propertyNames = entityPersister.getPropertyNames();
|
||||
final NaturalIdLoadAccess naturalIdLoader = this.byNaturalId( entityName );
|
||||
|
||||
// Build NaturalIdLoadAccess and in the process verify all naturalId properties were specified
|
||||
for ( int i = 0; i < naturalIdentifierProperties.length; i++ ) {
|
||||
final String naturalIdProperty = propertyNames[naturalIdentifierProperties[i]];
|
||||
final Object naturalIdValue = naturalIdValues.get( naturalIdProperty );
|
||||
|
||||
if ( naturalIdValue == null ) {
|
||||
// A NaturalId property is missing from the critera query, can't use NaturalIdLoadAccess
|
||||
return null;
|
||||
}
|
||||
|
||||
naturalIdLoader.using( naturalIdProperty, naturalIdValue );
|
||||
}
|
||||
|
||||
// Critera query contains a valid naturalId, use the new API
|
||||
LOG.warn( "Session.byNaturalId(" + entityName
|
||||
+ ") should be used for naturalId queries instead of Restrictions.naturalId() from a Criteria" );
|
||||
|
||||
return naturalIdLoader;
|
||||
}
|
||||
|
||||
private OuterJoinLoadable getOuterJoinLoadable(String entityName) throws MappingException {
|
||||
EntityPersister persister = factory.getEntityPersister(entityName);
|
||||
if ( !(persister instanceof OuterJoinLoadable) ) {
|
||||
|
|
Loading…
Reference in New Issue