HHH-1570 - criteria-api: filtering by key-many-to-one causes invalid sql

This commit is contained in:
Steve Ebersole 2012-10-30 12:25:55 -05:00
parent 4516dd45d6
commit 3e3b439e02
3 changed files with 84 additions and 25 deletions

View File

@ -71,31 +71,46 @@ public final class JoinHelper {
* be used in the join
*/
public static String[] getAliasedLHSColumnNames(
AssociationType type,
String alias,
int property,
AssociationType associationType,
String columnQualifier,
int propertyIndex,
int begin,
OuterJoinLoadable lhsPersister,
Mapping mapping
) {
if ( type.useLHSPrimaryKey() ) {
return StringHelper.qualify( alias, lhsPersister.getIdentifierColumnNames() );
Mapping mapping) {
if ( associationType.useLHSPrimaryKey() ) {
return StringHelper.qualify( columnQualifier, lhsPersister.getIdentifierColumnNames() );
}
else {
String propertyName = type.getLHSPropertyName();
if (propertyName==null) {
return ArrayHelper.slice(
lhsPersister.toColumns(alias, property),
begin,
type.getColumnSpan(mapping)
);
String propertyName = associationType.getLHSPropertyName();
if ( propertyName == null ) {
return ArrayHelper.slice(
toColumns( lhsPersister, columnQualifier, propertyIndex ),
begin,
associationType.getColumnSpan( mapping )
);
}
else {
return ( (PropertyMapping) lhsPersister ).toColumns(alias, propertyName); //bad cast
return ( (PropertyMapping) lhsPersister ).toColumns(columnQualifier, propertyName); //bad cast
}
}
}
private static String[] toColumns(OuterJoinLoadable persister, String columnQualifier, int propertyIndex) {
if ( propertyIndex >= 0 ) {
return persister.toColumns( columnQualifier, propertyIndex );
}
else {
final String[] cols = persister.getIdentifierColumnNames();
final String[] result = new String[cols.length];
for ( int j = 0; j < cols.length; j++ ) {
result[j] = StringHelper.qualify( columnQualifier, cols[j] );
}
return result;
}
}
/**
* Get the columns of the owning entity which are to
* be used in the join
@ -116,8 +131,10 @@ public final class JoinHelper {
if (propertyName==null) {
//slice, to get the columns for this component
//property
return ArrayHelper.slice(
lhsPersister.getSubclassPropertyColumnNames(property),
return ArrayHelper.slice(
property < 0
? lhsPersister.getIdentifierColumnNames()
: lhsPersister.getSubclassPropertyColumnNames(property),
begin,
type.getColumnSpan(mapping)
);
@ -131,11 +148,10 @@ public final class JoinHelper {
}
public static String getLHSTableName(
AssociationType type,
int property,
OuterJoinLoadable lhsPersister
) {
if ( type.useLHSPrimaryKey() ) {
AssociationType type,
int propertyIndex,
OuterJoinLoadable lhsPersister) {
if ( type.useLHSPrimaryKey() || propertyIndex < 0 ) {
return lhsPersister.getTableName();
}
else {
@ -144,7 +160,7 @@ public final class JoinHelper {
//if there is no property-ref, assume the join
//is to the subclass table (ie. the table of the
//subclass that the association belongs to)
return lhsPersister.getSubclassPropertyTableName(property);
return lhsPersister.getSubclassPropertyTableName(propertyIndex);
}
else {
//handle a property-ref
@ -157,7 +173,7 @@ public final class JoinHelper {
//assumes that the property-ref refers to a property of the subclass
//table that the association belongs to (a reasonable guess)
//TODO: fix this, add: OuterJoinLoadable.getSubclassPropertyTableName(String propertyName)
propertyRefTable = lhsPersister.getSubclassPropertyTableName(property);
propertyRefTable = lhsPersister.getSubclassPropertyTableName(propertyIndex);
}
return propertyRefTable;
}

View File

@ -539,6 +539,34 @@ public class JoinWalker {
);
}
}
// if the entity has a composite identifier, see if we need to handle
// its sub-properties separately
final Type idType = persister.getIdentifierType();
if ( idType.isComponentType() ) {
final CompositeType cidType = (CompositeType) idType;
if ( cidType.isEmbedded() ) {
// we have an embedded composite identifier. Most likely we need to process the composite
// properties separately, although there is an edge case where the identifier is really
// a simple identifier (single value) wrapped in a JPA @IdClass or even in the case of a
// a simple identifier (single value) wrapped in a Hibernate composite type.
//
// We really do not have a built-in method to determine that. However, generally the
// persister would report that there is single, physical identifier property which is
// explicitly at odds with the notion of "embedded composite". So we use that for now
if ( persister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
walkComponentTree(
cidType,
-1,
0,
persister,
alias,
path.append( "" ),
currentDepth
);
}
}
}
}
/**

View File

@ -26,9 +26,12 @@ import java.util.List;
import org.junit.Test;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.criterion.Restrictions;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
@ -48,6 +51,18 @@ public class KeyManyToOneTest extends BaseCoreFunctionalTestCase {
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
}
@Test
public void testCriteriaRestrictionOnKeyManyToOne() {
Session s = openSession();
s.beginTransaction();
s.createQuery( "from Order o where o.customer.name = 'Acme'" ).list();
Criteria criteria = s.createCriteria( Order.class );
criteria.createCriteria( "customer" ).add( Restrictions.eq( "name", "Acme" ) );
criteria.list();
s.getTransaction().commit();
s.close();
}
@Test
public void testSaveCascadedToKeyManyToOne() {
// test cascading a save to an association with a key-many-to-one which refers to a