HHH-6974 - Add caching to new "load access" api for natural id loading

This commit is contained in:
Steve Ebersole 2012-02-08 09:08:11 -06:00
parent 368c4cc2bc
commit 199d08210d
6 changed files with 165 additions and 136 deletions

View File

@ -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 );
}
}

View File

@ -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 );
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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) ) {