HHH-2308 - Adding predicates to the join condition using Criteria Query
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18012 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
a3d1a3c59f
commit
a8e34f0066
|
@ -135,7 +135,10 @@ public interface Criteria extends CriteriaSpecification {
|
|||
*
|
||||
* @param associationPath a dot seperated property path
|
||||
* @param mode The fetch mode for the referenced association
|
||||
*
|
||||
* @return this (for method chaining)
|
||||
*
|
||||
* @throws HibernateException Indicates a problem applying the given fetch mode
|
||||
*/
|
||||
public Criteria setFetchMode(String associationPath, FetchMode mode) throws HibernateException;
|
||||
|
||||
|
@ -143,6 +146,7 @@ public interface Criteria extends CriteriaSpecification {
|
|||
* Set the lock mode of the current entity
|
||||
*
|
||||
* @param lockMode The lock mode to be applied
|
||||
*
|
||||
* @return this (for method chaining)
|
||||
*/
|
||||
public Criteria setLockMode(LockMode lockMode);
|
||||
|
@ -153,6 +157,7 @@ public interface Criteria extends CriteriaSpecification {
|
|||
* @param alias The previously assigned alias representing the entity to
|
||||
* which the given lock mode should apply.
|
||||
* @param lockMode The lock mode to be applied
|
||||
*
|
||||
* @return this (for method chaining)
|
||||
*/
|
||||
public Criteria setLockMode(String alias, LockMode lockMode);
|
||||
|
@ -165,7 +170,10 @@ public interface Criteria extends CriteriaSpecification {
|
|||
*
|
||||
* @param associationPath A dot-seperated property path
|
||||
* @param alias The alias to assign to the joined association (for later reference).
|
||||
*
|
||||
* @return this (for method chaining)
|
||||
*
|
||||
* @throws HibernateException Indicates a problem creating the sub criteria
|
||||
*/
|
||||
public Criteria createAlias(String associationPath, String alias) throws HibernateException;
|
||||
|
||||
|
@ -179,10 +187,31 @@ public interface Criteria extends CriteriaSpecification {
|
|||
* @param associationPath A dot-seperated property path
|
||||
* @param alias The alias to assign to the joined association (for later reference).
|
||||
* @param joinType The type of join to use.
|
||||
*
|
||||
* @return this (for method chaining)
|
||||
*
|
||||
* @throws HibernateException Indicates a problem creating the sub criteria
|
||||
*/
|
||||
public Criteria createAlias(String associationPath, String alias, int joinType) throws HibernateException;
|
||||
|
||||
/**
|
||||
* Join an association using the specified join-type, assigning an alias
|
||||
* to the joined association.
|
||||
* <p/>
|
||||
* The joinType is expected to be one of {@link #INNER_JOIN} (the default),
|
||||
* {@link #FULL_JOIN}, or {@link #LEFT_JOIN}.
|
||||
*
|
||||
* @param associationPath A dot-seperated property path
|
||||
* @param alias The alias to assign to the joined association (for later reference).
|
||||
* @param joinType The type of join to use.
|
||||
* @param withClause The criteria to be added to the join condition (<tt>ON</tt> clause)
|
||||
*
|
||||
* @return this (for method chaining)
|
||||
*
|
||||
* @throws HibernateException Indicates a problem creating the sub criteria
|
||||
*/
|
||||
public Criteria createAlias(String associationPath, String alias, int joinType, Criterion withClause) throws HibernateException;
|
||||
|
||||
/**
|
||||
* Create a new <tt>Criteria</tt>, "rooted" at the associated entity.
|
||||
* <p/>
|
||||
|
@ -190,7 +219,10 @@ public interface Criteria extends CriteriaSpecification {
|
|||
* {@link #INNER_JOIN} for the joinType.
|
||||
*
|
||||
* @param associationPath A dot-seperated property path
|
||||
*
|
||||
* @return the created "sub criteria"
|
||||
*
|
||||
* @throws HibernateException Indicates a problem creating the sub criteria
|
||||
*/
|
||||
public Criteria createCriteria(String associationPath) throws HibernateException;
|
||||
|
||||
|
@ -200,7 +232,10 @@ public interface Criteria extends CriteriaSpecification {
|
|||
*
|
||||
* @param associationPath A dot-seperated property path
|
||||
* @param joinType The type of join to use.
|
||||
*
|
||||
* @return the created "sub criteria"
|
||||
*
|
||||
* @throws HibernateException Indicates a problem creating the sub criteria
|
||||
*/
|
||||
public Criteria createCriteria(String associationPath, int joinType) throws HibernateException;
|
||||
|
||||
|
@ -213,7 +248,10 @@ public interface Criteria extends CriteriaSpecification {
|
|||
*
|
||||
* @param associationPath A dot-seperated property path
|
||||
* @param alias The alias to assign to the joined association (for later reference).
|
||||
*
|
||||
* @return the created "sub criteria"
|
||||
*
|
||||
* @throws HibernateException Indicates a problem creating the sub criteria
|
||||
*/
|
||||
public Criteria createCriteria(String associationPath, String alias) throws HibernateException;
|
||||
|
||||
|
@ -224,10 +262,28 @@ public interface Criteria extends CriteriaSpecification {
|
|||
* @param associationPath A dot-seperated property path
|
||||
* @param alias The alias to assign to the joined association (for later reference).
|
||||
* @param joinType The type of join to use.
|
||||
*
|
||||
* @return the created "sub criteria"
|
||||
*
|
||||
* @throws HibernateException Indicates a problem creating the sub criteria
|
||||
*/
|
||||
public Criteria createCriteria(String associationPath, String alias, int joinType) throws HibernateException;
|
||||
|
||||
/**
|
||||
* Create a new <tt>Criteria</tt>, "rooted" at the associated entity,
|
||||
* assigning the given alias and using the specified join type.
|
||||
*
|
||||
* @param associationPath A dot-seperated property path
|
||||
* @param alias The alias to assign to the joined association (for later reference).
|
||||
* @param joinType The type of join to use.
|
||||
* @param withClause The criteria to be added to the join condition (<tt>ON</tt> clause)
|
||||
*
|
||||
* @return the created "sub criteria"
|
||||
*
|
||||
* @throws HibernateException Indicates a problem creating the sub criteria
|
||||
*/
|
||||
public Criteria createCriteria(String associationPath, String alias, int joinType, Criterion withClause) throws HibernateException;
|
||||
|
||||
/**
|
||||
* Set a strategy for handling the query results. This determines the
|
||||
* "shape" of the query result.
|
||||
|
@ -327,6 +383,9 @@ public interface Criteria extends CriteriaSpecification {
|
|||
* Get the results.
|
||||
*
|
||||
* @return The list of matched query results.
|
||||
*
|
||||
* @throws HibernateException Indicates a problem either translating the criteria to SQL,
|
||||
* exeucting the SQL or processing the SQL results.
|
||||
*/
|
||||
public List list() throws HibernateException;
|
||||
|
||||
|
@ -335,6 +394,9 @@ public interface Criteria extends CriteriaSpecification {
|
|||
*
|
||||
* @return The {@link ScrollableResults} representing the matched
|
||||
* query results.
|
||||
*
|
||||
* @throws HibernateException Indicates a problem either translating the criteria to SQL,
|
||||
* exeucting the SQL or processing the SQL results.
|
||||
*/
|
||||
public ScrollableResults scroll() throws HibernateException;
|
||||
|
||||
|
@ -344,8 +406,12 @@ public interface Criteria extends CriteriaSpecification {
|
|||
*
|
||||
* @param scrollMode Indicates the type of underlying database cursor to
|
||||
* request.
|
||||
*
|
||||
* @return The {@link ScrollableResults} representing the matched
|
||||
* query results.
|
||||
*
|
||||
* @throws HibernateException Indicates a problem either translating the criteria to SQL,
|
||||
* exeucting the SQL or processing the SQL results.
|
||||
*/
|
||||
public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException;
|
||||
|
||||
|
|
|
@ -202,6 +202,11 @@ public class CriteriaImpl implements Criteria, Serializable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Criteria createAlias(String associationPath, String alias, int joinType, Criterion withClause) {
|
||||
new Subcriteria( this, associationPath, alias, joinType, withClause );
|
||||
return this;
|
||||
}
|
||||
|
||||
public Criteria createCriteria(String associationPath) {
|
||||
return createCriteria( associationPath, INNER_JOIN );
|
||||
}
|
||||
|
@ -218,6 +223,10 @@ public class CriteriaImpl implements Criteria, Serializable {
|
|||
return new Subcriteria( this, associationPath, alias, joinType );
|
||||
}
|
||||
|
||||
public Criteria createCriteria(String associationPath, String alias, int joinType, Criterion withClause) {
|
||||
return new Subcriteria( this, associationPath, alias, joinType, withClause );
|
||||
}
|
||||
|
||||
public ResultTransformer getResultTransformer() {
|
||||
return resultTransformer;
|
||||
}
|
||||
|
@ -374,16 +383,21 @@ public class CriteriaImpl implements Criteria, Serializable {
|
|||
private Criteria parent;
|
||||
private LockMode lockMode;
|
||||
private int joinType;
|
||||
|
||||
private Criterion withClause;
|
||||
|
||||
// Constructors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private Subcriteria(Criteria parent, String path, String alias, int joinType) {
|
||||
private Subcriteria(Criteria parent, String path, String alias, int joinType, Criterion withClause) {
|
||||
this.alias = alias;
|
||||
this.path = path;
|
||||
this.parent = parent;
|
||||
this.joinType = joinType;
|
||||
CriteriaImpl.this.subcriteriaList.add(this);
|
||||
this.withClause = withClause;
|
||||
CriteriaImpl.this.subcriteriaList.add( this );
|
||||
}
|
||||
|
||||
private Subcriteria(Criteria parent, String path, String alias, int joinType) {
|
||||
this( parent, path, alias, joinType, null );
|
||||
}
|
||||
|
||||
private Subcriteria(Criteria parent, String path, int joinType) {
|
||||
|
@ -391,10 +405,10 @@ public class CriteriaImpl implements Criteria, Serializable {
|
|||
}
|
||||
|
||||
public String toString() {
|
||||
return "Subcriteria(" +
|
||||
path + ":" +
|
||||
(alias==null ? "" : alias) +
|
||||
')';
|
||||
return "Subcriteria("
|
||||
+ path + ":"
|
||||
+ (alias==null ? "" : alias)
|
||||
+ ')';
|
||||
}
|
||||
|
||||
|
||||
|
@ -429,6 +443,10 @@ public class CriteriaImpl implements Criteria, Serializable {
|
|||
return joinType;
|
||||
}
|
||||
|
||||
public Criterion getWithClause() {
|
||||
return this.withClause;
|
||||
}
|
||||
|
||||
|
||||
// Criteria impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -451,6 +469,11 @@ public class CriteriaImpl implements Criteria, Serializable {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Criteria createAlias(String associationPath, String alias, int joinType, Criterion withClause) throws HibernateException {
|
||||
new Subcriteria( this, associationPath, alias, joinType, withClause );
|
||||
return this;
|
||||
}
|
||||
|
||||
public Criteria createCriteria(String associationPath) {
|
||||
return createCriteria( associationPath, INNER_JOIN );
|
||||
}
|
||||
|
@ -467,6 +490,10 @@ public class CriteriaImpl implements Criteria, Serializable {
|
|||
return new Subcriteria( Subcriteria.this, associationPath, alias, joinType );
|
||||
}
|
||||
|
||||
public Criteria createCriteria(String associationPath, String alias, int joinType, Criterion withClause) throws HibernateException {
|
||||
return new Subcriteria( this, associationPath, alias, joinType, withClause );
|
||||
}
|
||||
|
||||
public Criteria setCacheable(boolean cacheable) {
|
||||
CriteriaImpl.this.setCacheable(cacheable);
|
||||
return this;
|
||||
|
@ -493,8 +520,7 @@ public class CriteriaImpl implements Criteria, Serializable {
|
|||
return CriteriaImpl.this.uniqueResult();
|
||||
}
|
||||
|
||||
public Criteria setFetchMode(String associationPath, FetchMode mode)
|
||||
throws HibernateException {
|
||||
public Criteria setFetchMode(String associationPath, FetchMode mode) {
|
||||
CriteriaImpl.this.setFetchMode( StringHelper.qualify(path, associationPath), mode);
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ public abstract class AbstractEntityJoinWalker extends JoinWalker {
|
|||
null,
|
||||
alias,
|
||||
JoinFragment.LEFT_OUTER_JOIN,
|
||||
null,
|
||||
getFactory(),
|
||||
CollectionHelper.EMPTY_MAP
|
||||
)
|
||||
|
|
|
@ -207,6 +207,10 @@ public class JoinWalker {
|
|||
}
|
||||
}
|
||||
|
||||
protected String getWithClause(String path) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Add on association (one-to-one, many-to-one, or a collection) to a list
|
||||
* of associations to be fetched by outerjoin
|
||||
|
@ -235,6 +239,7 @@ public class JoinWalker {
|
|||
aliasedLhsColumns,
|
||||
subalias,
|
||||
joinType,
|
||||
getWithClause(path),
|
||||
getFactory(),
|
||||
loadQueryInfluencers.getEnabledFilters()
|
||||
);
|
||||
|
|
|
@ -59,6 +59,7 @@ public final class OuterJoinableAssociation {
|
|||
String[] lhsColumns,
|
||||
String rhsAlias,
|
||||
int joinType,
|
||||
String withClause,
|
||||
SessionFactoryImplementor factory,
|
||||
Map enabledFilters) throws MappingException {
|
||||
this.joinableType = joinableType;
|
||||
|
@ -68,7 +69,8 @@ public final class OuterJoinableAssociation {
|
|||
this.joinType = joinType;
|
||||
this.joinable = joinableType.getAssociatedJoinable(factory);
|
||||
this.rhsColumns = JoinHelper.getRHSColumnNames(joinableType, factory);
|
||||
this.on = joinableType.getOnCondition(rhsAlias, factory, enabledFilters);
|
||||
this.on = joinableType.getOnCondition(rhsAlias, factory, enabledFilters)
|
||||
+ ( withClause == null || withClause.trim().length() == 0 ? "" : " and ( " + withClause + " )" );
|
||||
this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ public class BasicCollectionJoinWalker extends CollectionJoinWalker {
|
|||
null,
|
||||
alias,
|
||||
JoinFragment.LEFT_OUTER_JOIN,
|
||||
null,
|
||||
getFactory(),
|
||||
CollectionHelper.EMPTY_MAP
|
||||
)
|
||||
|
|
|
@ -85,6 +85,7 @@ public class OneToManyJoinWalker extends CollectionJoinWalker {
|
|||
null,
|
||||
alias,
|
||||
JoinFragment.LEFT_OUTER_JOIN,
|
||||
null,
|
||||
getFactory(),
|
||||
CollectionHelper.EMPTY_MAP
|
||||
) );
|
||||
|
|
|
@ -210,4 +210,8 @@ public class CriteriaJoinWalker extends AbstractEntityJoinWalker {
|
|||
return "criteria query";
|
||||
}
|
||||
|
||||
protected String getWithClause(String path) {
|
||||
return translator.getWithClause(path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.hibernate.MappingException;
|
|||
import org.hibernate.QueryException;
|
||||
import org.hibernate.hql.ast.util.SessionFactoryHelper;
|
||||
import org.hibernate.criterion.CriteriaQuery;
|
||||
import org.hibernate.criterion.Criterion;
|
||||
import org.hibernate.criterion.Projection;
|
||||
import org.hibernate.engine.QueryParameters;
|
||||
import org.hibernate.engine.RowSelection;
|
||||
|
@ -77,6 +78,7 @@ public class CriteriaQueryTranslator implements CriteriaQuery {
|
|||
private final Map aliasCriteriaMap = new HashMap();
|
||||
private final Map associationPathCriteriaMap = new LinkedHashMap();
|
||||
private final Map associationPathJoinTypesMap = new LinkedHashMap();
|
||||
private final Map withClauseMap = new HashMap();
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
|
@ -169,6 +171,10 @@ public class CriteriaQueryTranslator implements CriteriaQuery {
|
|||
// TODO : not so sure this is needed...
|
||||
throw new QueryException( "duplicate association path: " + wholeAssociationPath );
|
||||
}
|
||||
if ( crit.getWithClause() != null )
|
||||
{
|
||||
this.withClauseMap.put(wholeAssociationPath, crit.getWithClause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,9 +272,42 @@ public class CriteriaQueryTranslator implements CriteriaQuery {
|
|||
}
|
||||
|
||||
public QueryParameters getQueryParameters() {
|
||||
RowSelection selection = new RowSelection();
|
||||
selection.setFirstRow( rootCriteria.getFirstResult() );
|
||||
selection.setMaxRows( rootCriteria.getMaxResults() );
|
||||
selection.setTimeout( rootCriteria.getTimeout() );
|
||||
selection.setFetchSize( rootCriteria.getFetchSize() );
|
||||
|
||||
Map lockModes = new HashMap();
|
||||
Iterator iter = rootCriteria.getLockModes().entrySet().iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Map.Entry me = ( Map.Entry ) iter.next();
|
||||
final Criteria subcriteria = getAliasedCriteria( ( String ) me.getKey() );
|
||||
lockModes.put( getSQLAlias( subcriteria ), me.getValue() );
|
||||
}
|
||||
List values = new ArrayList();
|
||||
List types = new ArrayList();
|
||||
Iterator iter = rootCriteria.iterateExpressionEntries();
|
||||
iter = rootCriteria.iterateSubcriteria();
|
||||
while ( iter.hasNext() ) {
|
||||
CriteriaImpl.Subcriteria subcriteria = ( CriteriaImpl.Subcriteria ) iter.next();
|
||||
LockMode lm = subcriteria.getLockMode();
|
||||
if ( lm != null ) {
|
||||
lockModes.put( getSQLAlias( subcriteria ), lm );
|
||||
}
|
||||
if ( subcriteria.getWithClause() != null )
|
||||
{
|
||||
TypedValue[] tv = subcriteria.getWithClause().getTypedValues( subcriteria, this );
|
||||
for ( int i = 0; i < tv.length; i++ ) {
|
||||
values.add( tv[i].getValue() );
|
||||
types.add( tv[i].getType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Type and value gathering for the WHERE clause needs to come AFTER lock mode gathering,
|
||||
// because the lock mode gathering loop now contains join clauses which can contain
|
||||
// parameter bindings (as in the HQL WITH clause).
|
||||
iter = rootCriteria.iterateExpressionEntries();
|
||||
while ( iter.hasNext() ) {
|
||||
CriteriaImpl.CriterionEntry ce = ( CriteriaImpl.CriterionEntry ) iter.next();
|
||||
TypedValue[] tv = ce.getCriterion().getTypedValues( ce.getCriteria(), this );
|
||||
|
@ -277,31 +316,9 @@ public class CriteriaQueryTranslator implements CriteriaQuery {
|
|||
types.add( tv[i].getType() );
|
||||
}
|
||||
}
|
||||
|
||||
Object[] valueArray = values.toArray();
|
||||
Type[] typeArray = ArrayHelper.toTypeArray( types );
|
||||
|
||||
RowSelection selection = new RowSelection();
|
||||
selection.setFirstRow( rootCriteria.getFirstResult() );
|
||||
selection.setMaxRows( rootCriteria.getMaxResults() );
|
||||
selection.setTimeout( rootCriteria.getTimeout() );
|
||||
selection.setFetchSize( rootCriteria.getFetchSize() );
|
||||
|
||||
Map lockModes = new HashMap();
|
||||
iter = rootCriteria.getLockModes().entrySet().iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Map.Entry me = ( Map.Entry ) iter.next();
|
||||
final Criteria subcriteria = getAliasedCriteria( ( String ) me.getKey() );
|
||||
lockModes.put( getSQLAlias( subcriteria ), me.getValue() );
|
||||
}
|
||||
iter = rootCriteria.iterateSubcriteria();
|
||||
while ( iter.hasNext() ) {
|
||||
CriteriaImpl.Subcriteria subcriteria = ( CriteriaImpl.Subcriteria ) iter.next();
|
||||
LockMode lm = subcriteria.getLockMode();
|
||||
if ( lm != null ) {
|
||||
lockModes.put( getSQLAlias( subcriteria ), lm );
|
||||
}
|
||||
}
|
||||
|
||||
return new QueryParameters(
|
||||
typeArray,
|
||||
valueArray,
|
||||
|
@ -576,4 +593,10 @@ public class CriteriaQueryTranslator implements CriteriaQuery {
|
|||
return propertyName;
|
||||
}
|
||||
|
||||
public String getWithClause(String path)
|
||||
{
|
||||
final Criterion crit = (Criterion)this.withClauseMap.get(path);
|
||||
return crit == null ? null : crit.toSqlString(getCriteria(path), this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -196,6 +196,34 @@ while ( iter.hasNext() ) {
|
|||
Cat kitten = (Cat) map.get("kt");
|
||||
}]]></programlisting>
|
||||
|
||||
<para>
|
||||
Additionally you may manipulate the result set using a left outer join:
|
||||
</para>
|
||||
<programlisting><![CDATA[
|
||||
List cats = session.createCriteria( Cat.class )
|
||||
.createAlias("mate", "mt", Criteria.LEFT_JOIN, Restrictions.like("mt.name", "good%") )
|
||||
.addOrder(Order.asc("mt.age"))
|
||||
.list();
|
||||
|
||||
]]></programlisting>
|
||||
|
||||
<para>
|
||||
This will return all of the <literal>Cat</literal>s with a mate whose name starts with "good"
|
||||
ordered by their mate's age, and all cats who do not have a mate.
|
||||
This is useful when there is a need to order or limit in the database
|
||||
prior to returning complex/large result sets, and removes many instances where
|
||||
multiple queries would have to be performed and the results unioned
|
||||
by java in memory.
|
||||
</para>
|
||||
<para>
|
||||
Without this feature, first all of the cats without a mate would need to be loaded in one query.
|
||||
</para>
|
||||
<para>
|
||||
A second query would need to retreive the cats with mates who's name started with "good" sorted by the mates age.
|
||||
</para>
|
||||
<para>
|
||||
Thirdly, in memory; the lists would need to be joined manually.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="querycriteria-dynamicfetching" revision="1">
|
||||
|
|
|
@ -794,5 +794,99 @@ public class CriteriaQueryTest extends FunctionalTestCase {
|
|||
t.commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
public void testAliasJoinCriterion() {
|
||||
Session session = openSession();
|
||||
Transaction t = session.beginTransaction();
|
||||
|
||||
Course courseA = new Course();
|
||||
courseA.setCourseCode("HIB-A");
|
||||
courseA.setDescription("Hibernate Training A");
|
||||
session.persist(courseA);
|
||||
|
||||
Course courseB = new Course();
|
||||
courseB.setCourseCode("HIB-B");
|
||||
courseB.setDescription("Hibernate Training B");
|
||||
session.persist(courseB);
|
||||
|
||||
Student gavin = new Student();
|
||||
gavin.setName("Gavin King");
|
||||
gavin.setStudentNumber(232);
|
||||
gavin.setPreferredCourse(courseA);
|
||||
session.persist(gavin);
|
||||
|
||||
Student leonardo = new Student();
|
||||
leonardo.setName("Leonardo Quijano");
|
||||
leonardo.setStudentNumber(233);
|
||||
leonardo.setPreferredCourse(courseB);
|
||||
session.persist(leonardo);
|
||||
|
||||
Student johnDoe = new Student();
|
||||
johnDoe.setName("John Doe");
|
||||
johnDoe.setStudentNumber(235);
|
||||
johnDoe.setPreferredCourse(null);
|
||||
session.persist(johnDoe);
|
||||
|
||||
// test == on one value exists
|
||||
List result = session.createCriteria( Student.class )
|
||||
.createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN, Restrictions.eq("pc.courseCode", "HIB-A") )
|
||||
.setProjection( Property.forName("pc.courseCode") )
|
||||
.addOrder(Order.asc("pc.courseCode"))
|
||||
.list();
|
||||
|
||||
assertEquals( 3, result.size() );
|
||||
|
||||
// can't be sure of NULL comparison ordering aside from they should
|
||||
// either come first or last
|
||||
if ( result.get( 0 ) == null ) {
|
||||
assertNull(result.get(1));
|
||||
assertEquals( "HIB-A", result.get(2) );
|
||||
}
|
||||
else {
|
||||
assertNull( result.get(2) );
|
||||
assertNull( result.get(1) );
|
||||
assertEquals( "HIB-A", result.get(0) );
|
||||
}
|
||||
|
||||
// test == on non existent value
|
||||
result = session.createCriteria( Student.class )
|
||||
.createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN, Restrictions.eq("pc.courseCode", "HIB-R") )
|
||||
.setProjection( Property.forName("pc.courseCode") )
|
||||
.addOrder(Order.asc("pc.courseCode"))
|
||||
.list();
|
||||
|
||||
assertEquals( 3, result.size() );
|
||||
assertNull( result.get(2) );
|
||||
assertNull( result.get(1) );
|
||||
assertNull(result.get(0) );
|
||||
|
||||
// test != on one existing value
|
||||
result = session.createCriteria( Student.class )
|
||||
.createAlias( "preferredCourse", "pc", Criteria.LEFT_JOIN, Restrictions.ne("pc.courseCode", "HIB-A") )
|
||||
.setProjection( Property.forName("pc.courseCode") )
|
||||
.addOrder(Order.asc("pc.courseCode"))
|
||||
.list();
|
||||
|
||||
assertEquals( 3, result.size() );
|
||||
// can't be sure of NULL comparison ordering aside from they should
|
||||
// either come first or last
|
||||
if ( result.get( 0 ) == null ) {
|
||||
assertNull( result.get(1) );
|
||||
assertEquals( "HIB-B", result.get(2) );
|
||||
}
|
||||
else {
|
||||
assertEquals( "HIB-B", result.get(0) );
|
||||
assertNull( result.get(1) );
|
||||
assertNull( result.get(2) );
|
||||
}
|
||||
|
||||
session.delete(gavin);
|
||||
session.delete(leonardo);
|
||||
session.delete(johnDoe);
|
||||
session.delete(courseA);
|
||||
session.delete(courseB);
|
||||
t.commit();
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue