/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.hql;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.QueryException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Implementation of WithClauseTest.
*
* @author Steve Ebersole
*/
public class WithClauseTest extends BaseCoreFunctionalTestCase {
public String[] getMappings() {
return new String[] { "hql/Animal.hbm.xml", "hql/SimpleEntityWithAssociation.hbm.xml" };
}
@Test
public void testWithClauseFailsWithFetch() {
TestData data = new TestData();
data.prepare();
Session s = openSession();
Transaction txn = s.beginTransaction();
try {
s.createQuery( "from Animal a inner join fetch a.offspring as o with o.bodyWeight = :someLimit" )
.setDouble( "someLimit", 1 )
.list();
fail( "ad-hoc on clause allowed with fetched association" );
}
catch (IllegalArgumentException e) {
assertTyping( QueryException.class, e.getCause() );
}
catch ( HibernateException e ) {
// the expected response...
}
txn.commit();
s.close();
data.cleanup();
}
@Test
public void testWithClause() {
TestData data = new TestData();
data.prepare();
Session s = openSession();
Transaction txn = s.beginTransaction();
// one-to-many
List list = s.createQuery( "from Human h inner join h.offspring as o with o.bodyWeight < :someLimit" )
.setDouble( "someLimit", 1 )
.list();
assertTrue( "ad-hoc on did not take effect", list.isEmpty() );
// many-to-one
list = s.createQuery( "from Animal a inner join a.mother as m with m.bodyWeight < :someLimit" )
.setDouble( "someLimit", 1 )
.list();
assertTrue( "ad-hoc on did not take effect", list.isEmpty() );
list = s.createQuery( "from Human h inner join h.friends f with f.bodyWeight < :someLimit" )
.setDouble( "someLimit", 25 )
.list();
assertTrue( "ad-hoc on did take effect", !list.isEmpty() );
// many-to-many
list = s.createQuery( "from Human h inner join h.friends as f with f.nickName like 'bubba'" )
.list();
assertTrue( "ad-hoc on did not take effect", list.isEmpty() );
// http://opensource.atlassian.com/projects/hibernate/browse/HHH-1930
list = s.createQuery( "from Human h inner join h.nickNames as nicknames with nicknames = 'abc'" )
.list();
assertTrue( "ad-hoc on did not take effect", list.isEmpty() );
list = s.createQuery( "from Human h inner join h.offspring o with o.mother.father = :cousin" )
.setEntity( "cousin", s.load( Human.class, Long.valueOf( "123" ) ) )
.list();
assertTrue( "ad-hoc did take effect", list.isEmpty() );
txn.commit();
s.close();
data.cleanup();
}
@Test
@TestForIssue(jiraKey = "HHH-2772")
public void testWithJoinRHS() {
Session s = openSession();
s.beginTransaction();
SimpleEntityWithAssociation entity1 = new SimpleEntityWithAssociation();
entity1.setName( "entity1" );
SimpleEntityWithAssociation entity2 = new SimpleEntityWithAssociation();
entity2.setName( "entity2" );
SimpleAssociatedEntity associatedEntity1 = new SimpleAssociatedEntity();
associatedEntity1.setName( "associatedEntity1" );
SimpleAssociatedEntity associatedEntity2 = new SimpleAssociatedEntity();
associatedEntity2.setName( "associatedEntity2" );
entity1.addAssociation( associatedEntity1 );
entity2.addAssociation( associatedEntity2 );
s.persist( entity1 );
s.persist( entity2 );
s.getTransaction().commit();
s.clear();
s.beginTransaction();
Query query = s.createQuery( "select a from SimpleEntityWithAssociation as e INNER JOIN e.associatedEntities as a WITH e.name=?" );
query.setParameter( 0, "entity1" );
List list = query.list();
assertEquals( list.size(), 1 );
SimpleAssociatedEntity associatedEntity = (SimpleAssociatedEntity) query.list().get( 0 );
assertNotNull( associatedEntity );
assertEquals( associatedEntity.getName(), "associatedEntity1" );
assertEquals( associatedEntity.getOwner().getName(), "entity1" );
s.getTransaction().commit();
s.close();
}
@Test
@TestForIssue(jiraKey = "HHH-9329")
public void testWithClauseAsSubquery() {
TestData data = new TestData();
data.prepare();
Session s = openSession();
Transaction txn = s.beginTransaction();
// Since friends has a join table, we will first left join all friends and then do the WITH clause on the target entity table join
// Normally this produces 2 results which is wrong and can only be circumvented by converting the join table and target entity table join to a subquery
List list = s.createQuery( "from Human h left join h.friends as f with f.nickName like 'bubba' where h.description = 'father'" )
.list();
assertEquals( "subquery rewriting of join table did not take effect", 1, list.size() );
txn.commit();
s.close();
data.cleanup();
}
@Test
@TestForIssue(jiraKey = "HHH-11230")
public void testWithClauseAsSubqueryWithEqualOperator() {
TestData data = new TestData();
data.prepare();
Session s = openSession();
Transaction txn = s.beginTransaction();
// Like testWithClauseAsSubquery but uses equal operator since it render differently in SQL
List list = s.createQuery( "from Human h left join h.friends as f with f.nickName = 'bubba' where h.description = 'father'" )
.list();
assertEquals( "subquery rewriting of join table did not take effect", 1, list.size() );
txn.commit();
s.close();
data.cleanup();
}
@Test
@TestForIssue(jiraKey = "HHH-9329")
public void testWithClauseAsSubqueryWithKey() {
TestData data = new TestData();
data.prepare();
Session s = openSession();
Transaction txn = s.beginTransaction();
// Since family has a join table, we will first left join all family members and then do the WITH clause on the target entity table join
// Normally this produces 2 results which is wrong and can only be circumvented by converting the join table and target entity table join to a subquery
List list = s.createQuery( "from Human h left join h.family as f with key(f) like 'son1' where h.description = 'father'" )
.list();
assertEquals( "subquery rewriting of join table did not take effect", 1, list.size() );
txn.commit();
s.close();
data.cleanup();
}
@Test
@TestForIssue(jiraKey = "HHH-11157")
public void testWithClauseAsNonSubqueryWithKey() {
rebuildSessionFactory( c -> c.setProperty( AvailableSettings.COLLECTION_JOIN_SUBQUERY, "false" ) );
try {
TestData data = new TestData();
data.prepare();
Session s = openSession();
Transaction txn = s.beginTransaction();
// Since family has a join table, we will first left join all family members and then do the WITH clause on the target entity table join
// Normally this produces 2 results which is wrong and can only be circumvented by converting the join table and target entity table join to a subquery
List list = s.createQuery( "from Human h left join h.family as f with key(f) like 'son1' where h.description = 'father'" )
.list();
assertEquals( "subquery rewriting of join table was not disabled", 2, list.size() );
txn.commit();
s.close();
data.cleanup();
} finally {
// Rebuild to reset the properties
rebuildSessionFactory();
}
}
@Test
@TestForIssue(jiraKey = "HHH-11401")
public void testWithClauseAsSubqueryWithKeyAndOtherJoinReference() {
TestData data = new TestData();
data.prepare();
Session s = openSession();
Transaction txn = s.beginTransaction();
// Just a stupid example that makes use of a column that isn't from the collection table or the target entity table
List list = s.createQuery( "from Human h join h.friends as friend left join h.family as f with key(f) = concat('son', cast(friend.intValue as string)) where h.description = 'father'" )
.list();
assertEquals( "subquery rewriting of join table did not take effect", 2, list.size() );
txn.commit();
s.close();
data.cleanup();
}
private class TestData {
public void prepare() {
Session session = openSession();
Transaction txn = session.beginTransaction();
Human mother = new Human();
mother.setBodyWeight( 10 );
mother.setDescription( "mother" );
Human father = new Human();
father.setBodyWeight( 15 );
father.setDescription( "father" );
Human child1 = new Human();
child1.setBodyWeight( 5 );
child1.setDescription( "child1" );
Human child2 = new Human();
child2.setBodyWeight( 6 );
child2.setDescription( "child2" );
Human friend = new Human();
friend.setBodyWeight( 20 );
friend.setDescription( "friend" );
friend.setIntValue( 1 );
Human friend2 = new Human();
friend2.setBodyWeight( 20 );
friend2.setDescription( "friend2" );
friend.setIntValue( 2 );
child1.setMother( mother );
child1.setFather( father );
mother.addOffspring( child1 );
father.addOffspring( child1 );
child2.setMother( mother );
child2.setFather( father );
mother.addOffspring( child2 );
father.addOffspring( child2 );
father.setFriends( new ArrayList() );
father.getFriends().add( friend );
father.getFriends().add( friend2 );
session.save( mother );
session.save( father );
session.save( child1 );
session.save( child2 );
session.save( friend );
session.save( friend2 );
father.setFamily( new HashMap() );
father.getFamily().put( "son1", child1 );
father.getFamily().put( "son2", child2 );
txn.commit();
session.close();
}
public void cleanup() {
Session session = openSession();
Transaction txn = session.beginTransaction();
Human father = (Human) session.createQuery( "from Human where description = 'father'" ).uniqueResult();
father.getFriends().clear();
father.getFamily().clear();
session.flush();
session.delete( session.createQuery( "from Human where description = 'friend2'" ).uniqueResult() );
session.delete( session.createQuery( "from Human where description = 'friend'" ).uniqueResult() );
session.delete( session.createQuery( "from Human where description = 'child1'" ).uniqueResult() );
session.delete( session.createQuery( "from Human where description = 'child2'" ).uniqueResult() );
session.delete( session.createQuery( "from Human where description = 'mother'" ).uniqueResult() );
session.delete( father );
session.createQuery( "delete Animal" ).executeUpdate();
txn.commit();
session.close();
}
}
}