HHH-3383 - QueryKey is storing references to entities instead of identifiers

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@16652 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2009-06-01 18:54:44 +00:00
parent f8e2670b6e
commit aa710c6668
4 changed files with 173 additions and 68 deletions

View File

@ -28,13 +28,17 @@ import java.io.Serializable;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import org.hibernate.EntityMode;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.RowSelection;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.TypedValue;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;
import org.hibernate.util.EqualsHelper;
import org.hibernate.util.CollectionHelper;
/**
* A key that identifies a particular query with bound parameter values
@ -59,12 +63,41 @@ public class QueryKey implements Serializable {
*/
private transient int hashCode;
public QueryKey(String queryString, QueryParameters queryParameters, Set filters, EntityMode entityMode) {
this.sqlQueryString = queryString;
this.types = queryParameters.getPositionalParameterTypes();
this.values = queryParameters.getPositionalParameterValues();
RowSelection selection = queryParameters.getRowSelection();
if (selection!=null) {
public static QueryKey generateQueryKey(
String queryString,
QueryParameters queryParameters,
Set filters,
SessionImplementor session) {
// disassemble positional parameters
final int positionalParameterCount = queryParameters.getPositionalParameterTypes().length;
final Type[] types = new Type[positionalParameterCount];
final Object[] values = new Object[positionalParameterCount];
for ( int i = 0; i < positionalParameterCount; i++ ) {
types[i] = queryParameters.getPositionalParameterTypes()[i];
values[i] = types[i].disassemble( queryParameters.getPositionalParameterValues()[i], session, null );
}
// disassemble named parameters
Map namedParameters = CollectionHelper.mapOfSize( queryParameters.getNamedParameters().size() );
Iterator itr = queryParameters.getNamedParameters().entrySet().iterator();
while ( itr.hasNext() ) {
final Map.Entry namedParameterEntry = ( Map.Entry ) itr.next();
final TypedValue original = ( TypedValue ) namedParameterEntry.getValue();
namedParameters.put(
namedParameterEntry.getKey(),
new TypedValue(
original.getType(),
original.getType().disassemble( original.getValue(), session, null ),
session.getEntityMode()
)
);
}
// decode row selection...
final RowSelection selection = queryParameters.getRowSelection();
final Integer firstRow;
final Integer maxRows;
if ( selection != null ) {
firstRow = selection.getFirstRow();
maxRows = selection.getMaxRows();
}
@ -72,13 +105,62 @@ public class QueryKey implements Serializable {
firstRow = null;
maxRows = null;
}
this.namedParameters = queryParameters.getNamedParameters();
return new QueryKey(
queryString,
types,
values,
namedParameters,
firstRow,
maxRows,
filters,
session.getEntityMode(),
queryParameters.getResultTransformer()
);
}
/*package*/ QueryKey(
String sqlQueryString,
Type[] types,
Object[] values,
Map namedParameters,
Integer firstRow,
Integer maxRows,
Set filters,
EntityMode entityMode,
ResultTransformer customTransformer) {
this.sqlQueryString = sqlQueryString;
this.types = types;
this.values = values;
this.namedParameters = namedParameters;
this.firstRow = firstRow;
this.maxRows = maxRows;
this.entityMode = entityMode;
this.filters = filters;
this.customTransformer = queryParameters.getResultTransformer();
this.customTransformer = customTransformer;
this.hashCode = generateHashCode();
}
// public QueryKey(String queryString, QueryParameters queryParameters, Set filters, EntityMode entityMode) {
// this.sqlQueryString = queryString;
// this.types = queryParameters.getPositionalParameterTypes();
// this.values = queryParameters.getPositionalParameterValues();
// RowSelection selection = queryParameters.getRowSelection();
// if (selection!=null) {
// firstRow = selection.getFirstRow();
// maxRows = selection.getMaxRows();
// }
// else {
// firstRow = null;
// maxRows = null;
// }
// this.namedParameters = queryParameters.getNamedParameters();
// this.entityMode = entityMode;
// this.filters = filters;
// this.customTransformer = queryParameters.getResultTransformer();
// this.hashCode = generateHashCode();
// }
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.hashCode = generateHashCode();
@ -99,25 +181,43 @@ public class QueryKey implements Serializable {
}
public boolean equals(Object other) {
if (!(other instanceof QueryKey)) return false;
QueryKey that = (QueryKey) other;
if ( !sqlQueryString.equals(that.sqlQueryString) ) return false;
if ( !EqualsHelper.equals(firstRow, that.firstRow) || !EqualsHelper.equals(maxRows, that.maxRows) ) return false;
if ( !EqualsHelper.equals(customTransformer, that.customTransformer) ) return false;
if (types==null) {
if (that.types!=null) return false;
if ( !( other instanceof QueryKey ) ) {
return false;
}
else {
if (that.types==null) return false;
if ( types.length!=that.types.length ) return false;
for ( int i=0; i<types.length; i++ ) {
if ( types[i].getReturnedClass() != that.types[i].getReturnedClass() ) return false;
if ( !types[i].isEqual( values[i], that.values[i], entityMode ) ) return false;
QueryKey that = ( QueryKey ) other;
if ( !sqlQueryString.equals( that.sqlQueryString ) ) {
return false;
}
if ( !EqualsHelper.equals( firstRow, that.firstRow ) || !EqualsHelper.equals( maxRows, that.maxRows ) ) {
return false;
}
if ( !EqualsHelper.equals( customTransformer, that.customTransformer ) ) {
return false;
}
if ( types == null ) {
if ( that.types != null ) {
return false;
}
}
if ( !EqualsHelper.equals(filters, that.filters) ) return false;
if ( !EqualsHelper.equals(namedParameters, that.namedParameters) ) return false;
return true;
else {
if ( that.types == null ) {
return false;
}
if ( types.length != that.types.length ) {
return false;
}
for ( int i = 0; i < types.length; i++ ) {
if ( types[i].getReturnedClass() != that.types[i].getReturnedClass() ) {
return false;
}
if ( !types[i].isEqual( values[i], that.values[i], entityMode ) ) {
return false;
}
}
}
return EqualsHelper.equals( filters, that.filters )
&& EqualsHelper.equals( namedParameters, that.namedParameters );
}
public int hashCode() {
@ -126,26 +226,32 @@ public class QueryKey implements Serializable {
public String toString() {
StringBuffer buf = new StringBuffer()
.append("sql: ")
.append(sqlQueryString);
if (values!=null) {
buf.append("; parameters: ");
for (int i=0; i<values.length; i++) {
.append( "sql: " )
.append( sqlQueryString );
if ( values != null ) {
buf.append( "; parameters: " );
for ( int i = 0; i < values.length; i++ ) {
buf.append( values[i] )
.append(", ");
.append( ", " );
}
}
if (namedParameters!=null) {
buf.append("; named parameters: ")
.append(namedParameters);
if ( namedParameters != null ) {
buf.append( "; named parameters: " )
.append( namedParameters );
}
if (filters!=null) {
buf.append("; filters: ")
.append(filters);
if ( filters != null ) {
buf.append( "; filters: " )
.append( filters );
}
if ( firstRow != null ) {
buf.append( "; first row: " ).append( firstRow );
}
if ( maxRows != null ) {
buf.append( "; max rows: " ).append( maxRows );
}
if ( customTransformer != null ) {
buf.append( "; transformer: " ).append( customTransformer );
}
if (firstRow!=null) buf.append("; first row: ").append(firstRow);
if (maxRows!=null) buf.append("; max rows: ").append(maxRows);
if (customTransformer!=null) buf.append("; transformer: ").append(customTransformer);
return buf.toString();
}

View File

@ -2138,15 +2138,15 @@ public abstract class Loader {
QueryCache queryCache = factory.getQueryCache( queryParameters.getCacheRegion() );
Set filterKeys = FilterKey.createFilterKeys(
session.getEnabledFilters(),
session.getLoadQueryInfluencers().getEnabledFilters(),
session.getEntityMode()
);
QueryKey key = new QueryKey(
);
QueryKey key = QueryKey.generateQueryKey(
getSQLString(),
queryParameters,
filterKeys,
session.getEntityMode()
);
session
);
List result = getResultFromQueryCache(
session,
@ -2155,7 +2155,7 @@ public abstract class Loader {
resultTypes,
queryCache,
key
);
);
if ( result == null ) {
result = doList( session, queryParameters );
@ -2167,7 +2167,7 @@ public abstract class Loader {
queryCache,
key,
result
);
);
}
return getResultList( result, queryParameters.getResultTransformer() );

View File

@ -42,4 +42,8 @@ public final class CollectionHelper {
private CollectionHelper() {}
public static Map mapOfSize(int size) {
final int currentSize = (int) (size / 0.75f);
return new HashMap( Math.max( currentSize+ 1, 16), 0.75f );
}
}

View File

@ -29,7 +29,6 @@ import java.util.HashMap;
import junit.framework.TestCase;
import org.hibernate.engine.QueryParameters;
import org.hibernate.EntityMode;
import org.hibernate.transform.RootEntityResultTransformer;
import org.hibernate.transform.ResultTransformer;
@ -49,35 +48,31 @@ public class QueryKeyTest extends TestCase {
private static final String QUERY_STRING = "the query string";
public void testSerializedEquality() {
doTest( buildBasicKey( new QueryParameters() ) );
doTest( buildBasicKey( null ) );
}
public void testSerializedEqualityWithResultTransformer() {
doTest( buildBasicKey( buildQueryParameters( RootEntityResultTransformer.INSTANCE ) ) );
doTest( buildBasicKey( buildQueryParameters( DistinctRootEntityResultTransformer.INSTANCE ) ) );
doTest( buildBasicKey( buildQueryParameters( DistinctResultTransformer.INSTANCE ) ) );
doTest( buildBasicKey( buildQueryParameters( AliasToEntityMapResultTransformer.INSTANCE ) ) );
doTest( buildBasicKey( buildQueryParameters( PassThroughResultTransformer.INSTANCE ) ) );
doTest( buildBasicKey( RootEntityResultTransformer.INSTANCE ) );
doTest( buildBasicKey( DistinctRootEntityResultTransformer.INSTANCE ) );
doTest( buildBasicKey( DistinctResultTransformer.INSTANCE ) );
doTest( buildBasicKey( AliasToEntityMapResultTransformer.INSTANCE ) );
doTest( buildBasicKey( PassThroughResultTransformer.INSTANCE ) );
}
private QueryParameters buildQueryParameters(ResultTransformer resultTransformer) {
return new QueryParameters(
ArrayHelper.EMPTY_TYPE_ARRAY, // param types
ArrayHelper.EMPTY_OBJECT_ARRAY, // param values
Collections.EMPTY_MAP, // lock modes
null, // row selection
false, // cacheable?
"", // cache region
"", // SQL comment
false, // is natural key lookup?
resultTransformer // the result transformer, duh! ;)
private QueryKey buildBasicKey(ResultTransformer resultTransformer) {
return new QueryKey(
QUERY_STRING,
ArrayHelper.EMPTY_TYPE_ARRAY, // positional param types
ArrayHelper.EMPTY_OBJECT_ARRAY, // positional param values
Collections.EMPTY_MAP, // named params
null, // firstRow selection
null, // maxRows selection
Collections.EMPTY_SET, // filter keys
EntityMode.POJO, // entity mode
resultTransformer // the result transformer
);
}
private QueryKey buildBasicKey(QueryParameters queryParameters) {
return new QueryKey( QUERY_STRING, queryParameters, Collections.EMPTY_SET, EntityMode.POJO );
}
private void doTest(QueryKey key) {
HashMap map = new HashMap();