mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-27 14:30:16 +00:00
HHH-6766 - Criteria API multicolumn subqueries
This commit is contained in:
parent
c26030a27e
commit
fed759f8e5
@ -0,0 +1,28 @@
|
|||||||
|
package org.hibernate.criterion;
|
||||||
|
|
||||||
|
import org.hibernate.Criteria;
|
||||||
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A comparison between several properties value in the outer query and the result of a multicolumn subquery.
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class PropertiesSubqueryExpression extends SubqueryExpression {
|
||||||
|
private final String[] propertyNames;
|
||||||
|
|
||||||
|
protected PropertiesSubqueryExpression(String[] propertyNames, String op, DetachedCriteria dc) {
|
||||||
|
super( op, null, dc );
|
||||||
|
this.propertyNames = propertyNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String toLeftSqlString(Criteria criteria, CriteriaQuery outerQuery) {
|
||||||
|
StringBuilder left = new StringBuilder( "(" );
|
||||||
|
final String[] sqlColumnNames = new String[propertyNames.length];
|
||||||
|
for ( int i = 0; i < sqlColumnNames.length; ++i ) {
|
||||||
|
sqlColumnNames[i] = outerQuery.getColumn( criteria, propertyNames[i] );
|
||||||
|
}
|
||||||
|
left.append( StringHelper.join( ", ", sqlColumnNames ) );
|
||||||
|
return left.append( ")" ).toString();
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,7 @@
|
|||||||
* @see Projection
|
* @see Projection
|
||||||
* @see org.hibernate.Criteria
|
* @see org.hibernate.Criteria
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public class Subqueries {
|
public class Subqueries {
|
||||||
|
|
||||||
@ -60,6 +61,22 @@ public static Criterion propertyEq(String propertyName, DetachedCriteria dc) {
|
|||||||
return new PropertySubqueryExpression(propertyName, "=", null, dc);
|
return new PropertySubqueryExpression(propertyName, "=", null, dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Criterion propertiesEq(String[] propertyNames, DetachedCriteria dc) {
|
||||||
|
return new PropertiesSubqueryExpression(propertyNames, "=", dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Criterion propertiesNotEq(String[] propertyNames, DetachedCriteria dc) {
|
||||||
|
return new PropertiesSubqueryExpression(propertyNames, "<>", dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Criterion propertiesIn(String[] propertyNames, DetachedCriteria dc) {
|
||||||
|
return new PropertiesSubqueryExpression(propertyNames, "in", dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Criterion propertiesNotIn(String[] propertyNames, DetachedCriteria dc) {
|
||||||
|
return new PropertiesSubqueryExpression(propertyNames, "not in", dc);
|
||||||
|
}
|
||||||
|
|
||||||
public static Criterion propertyNe(String propertyName, DetachedCriteria dc) {
|
public static Criterion propertyNe(String propertyName, DetachedCriteria dc) {
|
||||||
return new PropertySubqueryExpression(propertyName, "<>", null, dc);
|
return new PropertySubqueryExpression(propertyName, "<>", null, dc);
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,9 @@
|
|||||||
import org.hibernate.test.hql.Reptile;
|
import org.hibernate.test.hql.Reptile;
|
||||||
import org.hibernate.testing.SkipForDialect;
|
import org.hibernate.testing.SkipForDialect;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.hibernate.testing.DialectChecks;
|
||||||
|
import org.hibernate.testing.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.transform.Transformers;
|
import org.hibernate.transform.Transformers;
|
||||||
import org.hibernate.type.StandardBasicTypes;
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
@ -72,11 +75,14 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
*/
|
*/
|
||||||
public class CriteriaQueryTest extends BaseCoreFunctionalTestCase {
|
public class CriteriaQueryTest extends BaseCoreFunctionalTestCase {
|
||||||
@Override
|
@Override
|
||||||
public String[] getMappings() {
|
public String[] getMappings() {
|
||||||
return new String[] { "criteria/Enrolment.hbm.xml","criteria/Foo.hbm.xml", "hql/Animal.hbm.xml" };
|
return new String[] {
|
||||||
|
"criteria/Enrolment.hbm.xml", "criteria/Foo.hbm.xml", "hql/Animal.hbm.xml", "criteria/Person.hbm.xml"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1720,6 +1726,85 @@ public void testCriteriaCollectionOfValue() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-6766" )
|
||||||
|
public void testMultiplePropertiesSubquery() {
|
||||||
|
Session session = openSession();
|
||||||
|
Transaction tx = session.beginTransaction();
|
||||||
|
|
||||||
|
Man lukasz = new Man();
|
||||||
|
lukasz.setName( "Lukasz" );
|
||||||
|
lukasz.setHeight( 170 );
|
||||||
|
lukasz.setWeight( 60 );
|
||||||
|
session.persist( lukasz );
|
||||||
|
|
||||||
|
Man robert = new Man();
|
||||||
|
robert.setName( "Robert" );
|
||||||
|
robert.setHeight( 170 );
|
||||||
|
robert.setWeight( 78 );
|
||||||
|
session.persist( robert );
|
||||||
|
|
||||||
|
Woman kinga = new Woman();
|
||||||
|
kinga.setName( "Kinga" );
|
||||||
|
kinga.setHeight( 170 );
|
||||||
|
kinga.setWeight( 60 );
|
||||||
|
session.persist( kinga );
|
||||||
|
|
||||||
|
tx.commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
session = openSession();
|
||||||
|
tx = session.beginTransaction();
|
||||||
|
|
||||||
|
DetachedCriteria sizeQuery = DetachedCriteria.forClass( Man.class ).setProjection(
|
||||||
|
Projections.projectionList().add( Projections.property( "weight" ) )
|
||||||
|
.add( Projections.property( "height" ) ) )
|
||||||
|
.add( Restrictions.eq( "name", "Lukasz" )
|
||||||
|
);
|
||||||
|
|
||||||
|
List result = session.createCriteria( Woman.class )
|
||||||
|
.add( Subqueries.propertiesEq( new String[] { "weight", "height" }, sizeQuery ) )
|
||||||
|
.list();
|
||||||
|
assertEquals( 1, result.size() );
|
||||||
|
assertEquals( kinga, result.get( 0 ) );
|
||||||
|
|
||||||
|
if (getDialect().supportsRowValueConstructorSyntaxInInList()) {
|
||||||
|
result = session.createCriteria( Woman.class )
|
||||||
|
.add( Subqueries.propertiesIn( new String[] { "weight", "height" }, sizeQuery ) )
|
||||||
|
.list();
|
||||||
|
assertEquals( 1, result.size() );
|
||||||
|
assertEquals( kinga, result.get( 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
session = openSession();
|
||||||
|
tx = session.beginTransaction();
|
||||||
|
|
||||||
|
sizeQuery = DetachedCriteria.forClass( Man.class ).setProjection(
|
||||||
|
Projections.projectionList().add( Projections.property( "weight" ) )
|
||||||
|
.add( Projections.property( "height" ) ) )
|
||||||
|
.add( Restrictions.ne( "name", "Lukasz" )
|
||||||
|
);
|
||||||
|
result = session.createCriteria( Woman.class )
|
||||||
|
.add( Subqueries.propertiesNotEq( new String[] { "weight", "height" }, sizeQuery ) )
|
||||||
|
.list();
|
||||||
|
assertEquals( 1, result.size() );
|
||||||
|
assertEquals( kinga, result.get( 0 ) );
|
||||||
|
|
||||||
|
if (getDialect().supportsRowValueConstructorSyntaxInInList()) {
|
||||||
|
result = session.createCriteria( Woman.class )
|
||||||
|
.add( Subqueries.propertiesNotIn( new String[] { "weight", "height" }, sizeQuery ) )
|
||||||
|
.list();
|
||||||
|
assertEquals( 1, result.size() );
|
||||||
|
assertEquals( kinga, result.get( 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCriteriaCollectionOfComponent() {
|
public void testCriteriaCollectionOfComponent() {
|
||||||
Session session = openSession();
|
Session session = openSession();
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.hibernate.test.criteria;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class Man extends Person {
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE hibernate-mapping PUBLIC
|
||||||
|
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||||
|
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||||
|
|
||||||
|
<hibernate-mapping package="org.hibernate.test.criteria">
|
||||||
|
|
||||||
|
<class name="Person">
|
||||||
|
<id name="id" type="long">
|
||||||
|
<generator class="sequence"/>
|
||||||
|
</id>
|
||||||
|
<property name="name" type="string"/>
|
||||||
|
<property name="weight" type="integer"/>
|
||||||
|
<property name="height" type="integer"/>
|
||||||
|
|
||||||
|
<union-subclass name="Man"/>
|
||||||
|
<union-subclass name="Woman"/>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
</hibernate-mapping>
|
@ -0,0 +1,70 @@
|
|||||||
|
package org.hibernate.test.criteria;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
public abstract class Person {
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Integer weight;
|
||||||
|
|
||||||
|
private Integer height;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if ( this == o ) return true;
|
||||||
|
if ( o == null || getClass() != o.getClass() ) return false;
|
||||||
|
|
||||||
|
Person person = (Person) o;
|
||||||
|
|
||||||
|
if ( height != null ? !height.equals( person.height ) : person.height != null ) return false;
|
||||||
|
if ( id != null ? !id.equals( person.id ) : person.id != null ) return false;
|
||||||
|
if ( name != null ? !name.equals( person.name ) : person.name != null ) return false;
|
||||||
|
if ( weight != null ? !weight.equals( person.weight ) : person.weight != null ) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = id != null ? id.hashCode() : 0;
|
||||||
|
result = 31 * result + ( name != null ? name.hashCode() : 0 );
|
||||||
|
result = 31 * result + ( weight != null ? weight.hashCode() : 0 );
|
||||||
|
result = 31 * result + ( height != null ? height.hashCode() : 0 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getWeight() {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWeight(Integer weight) {
|
||||||
|
this.weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(Integer height) {
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.hibernate.test.criteria;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||||
|
*/
|
||||||
|
public class Woman extends Person {
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user