/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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 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
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.criteria;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.hibernate.sql.JoinFragment;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
/**
* @author Mattias Jiderhamn
* @author Gail Badner
*/
public class OuterJoinCriteriaTest extends BaseCoreFunctionalTestCase {
private Order order1;
private Order order2;
private Order order3;
@Override
public String[] getMappings() {
return new String[] { "criteria/Order.hbm.xml" };
}
@Test
public void testSubcriteriaWithNonNullRestrictions() {
Session s = openSession();
s.getTransaction().begin();
Criteria rootCriteria = s.createCriteria( Order.class );
Criteria subCriteria = rootCriteria.createCriteria( "orderLines", JoinFragment.LEFT_OUTER_JOIN );
assertNotSame( rootCriteria, subCriteria );
// add restrictions to subCriteria, ensuring we stay on subCriteria
assertSame( subCriteria, subCriteria.add( Restrictions.eq( "articleId", "3000" ) ) );
List orders = rootCriteria.list();
// order1 and order3 should be returned because each has articleId == "3000"
// both should have their full collection
assertEquals( 2, orders.size() );
for ( Iterator it = orders.iterator(); it.hasNext(); ) {
Order o = (Order) it.next();
if ( order1.getOrderId() == o.getOrderId() ) {
assertEquals( order1.getLines().size(), o.getLines().size() );
}
else if ( order3.getOrderId() == o.getOrderId() ) {
assertEquals( order3.getLines().size(), o.getLines().size() );
}
else {
fail( "unknown order" );
}
}
s.getTransaction().commit();
s.close();
}
@Test
public void testSubcriteriaWithNonNullRestrictionsAliasToEntityMap() {
Session s = openSession();
s.getTransaction().begin();
Criteria rootCriteria = s.createCriteria( Order.class, "o" );
Criteria subCriteria = rootCriteria.createCriteria( "orderLines", "ol", JoinFragment.LEFT_OUTER_JOIN );
assertNotSame( rootCriteria, subCriteria );
// add restriction to subCriteria, ensuring we stay on subCriteria
assertSame( subCriteria, subCriteria.add( Restrictions.eq( "articleId", "3000" ) ) );
List orders = rootCriteria.setResultTransformer( Criteria.ALIAS_TO_ENTITY_MAP ).list();
// order1 and order3 should be returned because each has articleId == "3000";
// the orders should both should have their full collection;
assertEquals( 2, orders.size() );
for ( Iterator it = orders.iterator(); it.hasNext(); ) {
Map map = (Map) it.next();
Order o = ( Order ) map.get( "o" );
// the orderLine returned from the map should have articleId = "3000"
OrderLine ol = ( OrderLine ) map.get( "ol" );
if ( order1.getOrderId() == o.getOrderId() ) {
assertEquals( order1.getLines().size(), o.getLines().size() );
assertEquals( "3000", ol.getArticleId() );
}
else if ( order3.getOrderId() == o.getOrderId() ) {
assertEquals( order3.getLines().size(), o.getLines().size() );
assertEquals( "3000", ol.getArticleId() );
}
else {
fail( "unknown order" );
}
}
s.getTransaction().commit();
s.close();
}
@Test
public void testSubcriteriaWithNullOrNonNullRestrictions() {
Session s = openSession();
s.getTransaction().begin();
Criteria rootCriteria = s.createCriteria( Order.class );
Criteria subCriteria = rootCriteria.createCriteria( "orderLines", JoinFragment.LEFT_OUTER_JOIN );
assertNotSame( rootCriteria, subCriteria );
// add restrictions to subCriteria, ensuring we stay on subCriteria
// add restriction to subCriteria, ensuring we stay on subCriteria
assertSame(
subCriteria,
subCriteria.add(
Restrictions.or(
Restrictions.isNull( "articleId" ), // Allow null
Restrictions.eq( "articleId", "1000" )
)
)
);
List orders = rootCriteria.list();
// order1 should be returned because it has an orderline with articleId == "1000";
// order2 should be returned because it has no orderlines
assertEquals( 2, orders.size() );
for ( Iterator it = orders.iterator(); it.hasNext(); ) {
Order o = ( Order ) it.next();
if ( order1.getOrderId() == o.getOrderId() ) {
// o.getLines() should contain all of its orderLines
assertEquals( order1.getLines().size(), o.getLines().size() );
}
else if ( order2.getOrderId() == o.getOrderId() ) {
assertEquals( order2.getLines() , o.getLines() );
assertTrue( o.getLines().isEmpty() );
}
else {
fail( "unknown order" );
}
}
s.getTransaction().commit();
s.close();
}
@Test
public void testSubcriteriaWithNullOrNonNullRestrictionsAliasToEntityMap() {
Session s = openSession();
s.getTransaction().begin();
Criteria rootCriteria = s.createCriteria( Order.class, "o" );
Criteria subCriteria = rootCriteria.createCriteria( "orderLines", "ol", JoinFragment.LEFT_OUTER_JOIN );
assertNotSame( rootCriteria, subCriteria );
// add restriction to subCriteria, ensuring we stay on subCriteria
assertSame(
subCriteria,
subCriteria.add(
Restrictions.or(
Restrictions.isNull( "ol.articleId" ), // Allow null
Restrictions.eq( "ol.articleId", "1000" )
)
)
);
List orders = rootCriteria.setResultTransformer( Criteria.ALIAS_TO_ENTITY_MAP ).list();
// order1 should be returned because it has an orderline with articleId == "1000";
// order2 should be returned because it has no orderlines
assertEquals( 2, orders.size() );
for ( Iterator it = orders.iterator(); it.hasNext(); ) {
Map map = (Map) it.next();
Order o = ( Order ) map.get( "o" );
// the orderLine returned from the map should either be null or have articleId = "1000"
OrderLine ol = ( OrderLine ) map.get( "ol" );
if ( order1.getOrderId() == o.getOrderId() ) {
// o.getLines() should contain all of its orderLines
assertEquals( order1.getLines().size(), o.getLines().size() );
assertNotNull( ol );
assertEquals( "1000", ol.getArticleId() );
}
else if ( order2.getOrderId() == o.getOrderId() ) {
assertEquals( order2.getLines() , o.getLines() );
assertTrue( o.getLines().isEmpty() );
assertNull( ol );
}
else {
fail( "unknown order" );
}
}
s.getTransaction().commit();
s.close();
}
@Test
public void testSubcriteriaWithClauseAliasToEntityMap() {
Session s = openSession();
s.getTransaction().begin();
Criteria rootCriteria = s.createCriteria( Order.class, "o" );
Criteria subCriteria = rootCriteria.createCriteria(
"orderLines",
"ol", JoinFragment.LEFT_OUTER_JOIN,
Restrictions.or(
Restrictions.isNull( "ol.articleId" ), // Allow null
Restrictions.eq( "ol.articleId", "1000" )
)
);
assertNotSame( rootCriteria, subCriteria );
List orders = rootCriteria.setResultTransformer( Criteria.ALIAS_TO_ENTITY_MAP ).list();
// all orders should be returned (via map.get( "o" )) with their full collections;
assertEquals( 3, orders.size() );
for ( Iterator it = orders.iterator(); it.hasNext(); ) {
Map map = ( Map ) it.next();
Order o = ( Order ) map.get( "o" );
// the orderLine returned from the map should either be null or have articleId = "1000"
OrderLine ol = ( OrderLine ) map.get( "ol" );
if ( order1.getOrderId() == o.getOrderId() ) {
// o.getLines() should contain all of its orderLines
assertEquals( order1.getLines().size(), o.getLines().size() );
assertNotNull( ol );
assertEquals( "1000", ol.getArticleId() );
}
else if ( order2.getOrderId() == o.getOrderId() ) {
assertTrue( o.getLines().isEmpty() );
assertNull( ol );
}
else if ( order3.getOrderId() == o.getOrderId() ) {
assertEquals( order3.getLines().size(), o.getLines().size() );
assertNull( ol);
}
else {
fail( "unknown order" );
}
}
s.getTransaction().commit();
s.close();
}
@Test
public void testAliasWithNonNullRestrictions() {
Session s = openSession();
s.getTransaction().begin();
Criteria rootCriteria = s.createCriteria( Order.class );
// create alias, ensuring we stay on the root criteria
assertSame( rootCriteria, rootCriteria.createAlias( "orderLines", "ol", JoinFragment.LEFT_OUTER_JOIN ) );
// add restrictions to rootCriteria
assertSame( rootCriteria, rootCriteria.add( Restrictions.eq( "ol.articleId", "3000" ) ) );
List orders = rootCriteria.list();
// order1 and order3 should be returned because each has articleId == "3000"
// the contained collections should only have the orderLine with articleId == "3000"
assertEquals( 2, orders.size() );
for ( Iterator it = orders.iterator(); it.hasNext(); ) {
Order o = (Order) it.next();
if ( order1.getOrderId() == o.getOrderId() ) {
assertEquals( 1, o.getLines().size() );
assertEquals( "3000", ( ( OrderLine ) o.getLines().iterator().next() ).getArticleId() );
}
else if ( order3.getOrderId() == o.getOrderId() ) {
assertEquals( 1, o.getLines().size() );
assertEquals( "3000", ( ( OrderLine ) o.getLines().iterator().next() ).getArticleId() );
}
else {
fail( "unknown order" );
}
}
s.getTransaction().commit();
s.close();
}
@Test
public void testAliasWithNullOrNonNullRestrictions() {
Session s = openSession();
s.getTransaction().begin();
Criteria rootCriteria = s.createCriteria( Order.class );
// create alias, ensuring we stay on the root criteria
assertSame( rootCriteria, rootCriteria.createAlias( "orderLines", "ol", JoinFragment.LEFT_OUTER_JOIN ) );
// add restrictions to rootCriteria
assertSame(
rootCriteria,
rootCriteria.add(
Restrictions.or(
Restrictions.isNull( "ol.articleId" ), // Allow null
Restrictions.eq( "ol.articleId", "1000" )
)
)
);
List orders = rootCriteria.list();
// order1 should be returned because it has an orderline with articleId == "1000";
// the contained collection for order1 should only have the orderLine with articleId == "1000";
// order2 should be returned because it has no orderlines
assertEquals( 2, orders.size() );
for ( Object order : orders ) {
Order o = (Order) order;
if ( order1.getOrderId() == o.getOrderId() ) {
assertEquals( "1000", ( ( OrderLine ) o.getLines().iterator().next() ).getArticleId() );
}
else if ( order2.getOrderId() == o.getOrderId() ) {
assertEquals( 0, o.getLines().size() );
}
else {
fail( "unknown order" );
}
}
s.getTransaction().commit();
s.close();
}
@Test
public void testNonNullSubcriteriaRestrictionsOnRootCriteria() {
Session s = openSession();
s.getTransaction().begin();
Criteria rootCriteria = s.createCriteria( Order.class );
Criteria subCriteria = rootCriteria.createCriteria( "orderLines", "ol", JoinFragment.LEFT_OUTER_JOIN );
assertNotSame( rootCriteria, subCriteria );
// add restriction to rootCriteria (NOT subcriteria)
assertSame( rootCriteria, rootCriteria.add( Restrictions.eq( "ol.articleId", "3000" ) ) );
List orders = rootCriteria.list();
// results should be the same as testAliasWithNonNullRestrictions() (using Criteria.createAlias())
// order1 and order3 should be returned because each has articleId == "3000"
// the contained collections should only have the orderLine with articleId == "3000"
assertEquals( 2, orders.size() );
for ( Iterator it = orders.iterator(); it.hasNext(); ) {
Order o = (Order) it.next();
if ( order1.getOrderId() == o.getOrderId() ) {
assertEquals( 1, o.getLines().size() );
assertEquals( "3000", ( ( OrderLine ) o.getLines().iterator().next() ).getArticleId() );
}
else if ( order3.getOrderId() == o.getOrderId() ) {
assertEquals( 1, o.getLines().size() );
assertEquals( "3000", ( ( OrderLine ) o.getLines().iterator().next() ).getArticleId() );
}
else {
fail( "unknown order" );
}
}
s.getTransaction().commit();
s.close();
}
protected void prepareTest() {
Session s = openSession();
s.getTransaction().begin();
// Order with one mathing line
order1 = new Order();
OrderLine line = new OrderLine();
line.setArticleId( "1000" );
order1.addLine( line );
line = new OrderLine();
line.setArticleId( "3000" );
order1.addLine( line );
s.persist( order1 );
// Order with no lines
order2 = new Order();
s.persist( order2 );
// Order with non-matching line
order3 = new Order();
line = new OrderLine();
line.setArticleId( "3000" );
order3.addLine( line );
s.persist( order3 );
s.getTransaction().commit();
s.close();
}
protected void cleanupTest() {
Session s = openSession();
s.getTransaction().begin();
s.createQuery( "delete from OrderLine" ).executeUpdate();
s.createQuery( "delete from Order" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
private static boolean isBlank(String s) {
return s == null || s.trim().length() == 0;
}
}