/*
* 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.userguide.criteria;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Fetch;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.Session;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.userguide.model.AddressType;
import org.hibernate.userguide.model.Call;
import org.hibernate.userguide.model.CreditCardPayment;
import org.hibernate.userguide.model.Partner;
import org.hibernate.userguide.model.Partner_;
import org.hibernate.userguide.model.Person;
import org.hibernate.userguide.model.Person_;
import org.hibernate.userguide.model.Phone;
import org.hibernate.userguide.model.PhoneType;
import org.hibernate.userguide.model.Phone_;
import org.hibernate.userguide.model.WireTransferPayment;
import org.junit.Before;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
public class CriteriaTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class,
Partner.class,
Phone.class,
Call.class,
CreditCardPayment.class,
WireTransferPayment.class,
Event.class
};
}
@Before
public void init() {
doInJPA( this::entityManagerFactory, entityManager -> {
Person person1 = new Person("John Doe" );
person1.setNickName( "JD" );
person1.setAddress( "Earth" );
person1.setCreatedOn( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 0, 0, 0 ).toInstant( ZoneOffset.UTC ) )) ;
person1.getAddresses().put( AddressType.HOME, "Home address" );
person1.getAddresses().put( AddressType.OFFICE, "Office address" );
entityManager.persist(person1);
Person person2 = new Person("Mrs. John Doe" );
person2.setAddress( "Earth" );
person2.setCreatedOn( Timestamp.from( LocalDateTime.of( 2000, 1, 2, 12, 0, 0 ).toInstant( ZoneOffset.UTC ) )) ;
entityManager.persist(person2);
Person person3 = new Person("Dr_ John Doe" );
entityManager.persist(person3);
Phone phone1 = new Phone( "123-456-7890" );
phone1.setId( 1L );
phone1.setType( PhoneType.MOBILE );
person1.addPhone( phone1 );
phone1.getRepairTimestamps().add( Timestamp.from( LocalDateTime.of( 2005, 1, 1, 12, 0, 0 ).toInstant( ZoneOffset.UTC ) ) );
phone1.getRepairTimestamps().add( Timestamp.from( LocalDateTime.of( 2006, 1, 1, 12, 0, 0 ).toInstant( ZoneOffset.UTC ) ) );
Call call11 = new Call();
call11.setDuration( 12 );
call11.setTimestamp( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 0, 0, 0 ).toInstant( ZoneOffset.UTC ) ) );
Call call12 = new Call();
call12.setDuration( 33 );
call12.setTimestamp( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 1, 0, 0 ).toInstant( ZoneOffset.UTC ) ) );
phone1.addCall(call11);
phone1.addCall(call12);
Phone phone2 = new Phone( "098_765-4321" );
phone2.setId( 2L );
phone2.setType( PhoneType.LAND_LINE );
Phone phone3 = new Phone( "098-765-4320" );
phone3.setId( 3L );
phone3.setType( PhoneType.LAND_LINE );
person2.addPhone( phone2 );
person2.addPhone( phone3 );
CreditCardPayment creditCardPayment = new CreditCardPayment();
creditCardPayment.setCompleted( true );
creditCardPayment.setAmount( BigDecimal.ZERO );
creditCardPayment.setPerson( person1 );
WireTransferPayment wireTransferPayment = new WireTransferPayment();
wireTransferPayment.setCompleted( true );
wireTransferPayment.setAmount( BigDecimal.valueOf( 100 ) );
wireTransferPayment.setPerson( person2 );
entityManager.persist( creditCardPayment );
entityManager.persist( wireTransferPayment );
Partner partner = new Partner( "John Doe" );
entityManager.persist( partner );
});
}
@Test
public void test_criteria_typedquery_entity_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-typedquery-entity-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
Root<Person> root = criteria.from( Person.class );
criteria.select( root );
criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
List<Person> persons = entityManager.createQuery( criteria ).getResultList();
//end::criteria-typedquery-entity-example[]
assertEquals(1, persons.size());
});
}
@Test
public void test_criteria_typedquery_expression_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-typedquery-expression-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<String> criteria = builder.createQuery( String.class );
Root<Person> root = criteria.from( Person.class );
criteria.select( root.get( Person_.nickName ) );
criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
List<String> nickNames = entityManager.createQuery( criteria ).getResultList();
//end::criteria-typedquery-expression-example[]
assertEquals(1, nickNames.size());
});
}
@Test
public void test_criteria_typedquery_multiselect_explicit_array_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-typedquery-multiselect-array-explicit-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
Root<Person> root = criteria.from( Person.class );
Path<Long> idPath = root.get( Person_.id );
Path<String> nickNamePath = root.get( Person_.nickName);
criteria.select( builder.array( idPath, nickNamePath ) );
criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
List<Object[]> idAndNickNames = entityManager.createQuery( criteria ).getResultList();
//end::criteria-typedquery-multiselect-array-explicit-example[]
assertEquals(1, idAndNickNames.size());
});
}
@Test
public void test_criteria_typedquery_multiselect_implicit_array_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-typedquery-multiselect-array-implicit-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
Root<Person> root = criteria.from( Person.class );
Path<Long> idPath = root.get( Person_.id );
Path<String> nickNamePath = root.get( Person_.nickName);
criteria.multiselect( idPath, nickNamePath );
criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
List<Object[]> idAndNickNames = entityManager.createQuery( criteria ).getResultList();
//end::criteria-typedquery-multiselect-array-implicit-example[]
assertEquals(1, idAndNickNames.size());
});
}
@Test
public void test_criteria_typedquery_wrapper_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-typedquery-wrapper-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<PersonWrapper> criteria = builder.createQuery( PersonWrapper.class );
Root<Person> root = criteria.from( Person.class );
Path<Long> idPath = root.get( Person_.id );
Path<String> nickNamePath = root.get( Person_.nickName);
criteria.select( builder.construct( PersonWrapper.class, idPath, nickNamePath ) );
criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
List<PersonWrapper> wrappers = entityManager.createQuery( criteria ).getResultList();
//end::criteria-typedquery-wrapper-example[]
assertEquals(1, wrappers.size());
});
}
@Test
public void test_criteria_tuple_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-tuple-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createQuery( Tuple.class );
Root<Person> root = criteria.from( Person.class );
Path<Long> idPath = root.get( Person_.id );
Path<String> nickNamePath = root.get( Person_.nickName);
criteria.multiselect( idPath, nickNamePath );
criteria.where( builder.equal( root.get( Person_.name ), "John Doe" ) );
List<Tuple> tuples = entityManager.createQuery( criteria ).getResultList();
for ( Tuple tuple : tuples ) {
Long id = tuple.get( idPath );
String nickName = tuple.get( nickNamePath );
}
//or using indices
for ( Tuple tuple : tuples ) {
Long id = (Long) tuple.get( 0 );
String nickName = (String) tuple.get( 1 );
}
//end::criteria-tuple-example[]
assertEquals(1, tuples.size());
});
}
@Test
public void test_criteria_from_root_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-from-root-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
Root<Person> root = criteria.from( Person.class );
//end::criteria-from-root-example[]
});
}
@Test
public void test_criteria_from_multiple_root_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
String address = "Earth";
String prefix = "J%";
//tag::criteria-from-multiple-root-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createQuery( Tuple.class );
Root<Person> personRoot = criteria.from( Person.class );
Root<Partner> partnerRoot = criteria.from( Partner.class );
criteria.multiselect( personRoot, partnerRoot );
Predicate personRestriction = builder.and(
builder.equal( personRoot.get( Person_.address ), address ),
builder.isNotEmpty( personRoot.get( Person_.phones ) )
);
Predicate partnerRestriction = builder.and(
builder.like( partnerRoot.get( Partner_.name ), prefix ),
builder.equal( partnerRoot.get( Partner_.version ), 0 )
);
criteria.where( builder.and( personRestriction, partnerRestriction ) );
List<Tuple> tuples = entityManager.createQuery( criteria ).getResultList();
//end::criteria-from-multiple-root-example[]
assertEquals(2, tuples.size());
});
}
@Test
public void test_criteria_from_join_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-from-join-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Phone> criteria = builder.createQuery( Phone.class );
Root<Phone> root = criteria.from( Phone.class );
// Phone.person is a @ManyToOne
Join<Phone, Person> personJoin = root.join( Phone_.person );
// Person.addresses is an @ElementCollection
Join<Person, String> addressesJoin = personJoin.join( Person_.addresses );
criteria.where( builder.isNotEmpty( root.get( Phone_.calls ) ) );
List<Phone> phones = entityManager.createQuery( criteria ).getResultList();
//end::criteria-from-join-example[]
assertEquals(2, phones.size());
});
}
@Test
public void test_criteria_from_fetch_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-from-fetch-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Phone> criteria = builder.createQuery( Phone.class );
Root<Phone> root = criteria.from( Phone.class );
// Phone.person is a @ManyToOne
Fetch<Phone, Person> personFetch = root.fetch( Phone_.person );
// Person.addresses is an @ElementCollection
Fetch<Person, String> addressesJoin = personFetch.fetch( Person_.addresses );
criteria.where( builder.isNotEmpty( root.get( Phone_.calls ) ) );
List<Phone> phones = entityManager.createQuery( criteria ).getResultList();
//end::criteria-from-fetch-example[]
assertEquals(2, phones.size());
});
}
@Test
public void test_criteria_param_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-param-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
Root<Person> root = criteria.from( Person.class );
ParameterExpression<String> nickNameParameter = builder.parameter( String.class );
criteria.where( builder.equal( root.get( Person_.nickName ), nickNameParameter ) );
TypedQuery<Person> query = entityManager.createQuery( criteria );
query.setParameter( nickNameParameter, "JD" );
List<Person> persons = query.getResultList();
//end::criteria-param-example[]
assertEquals(1, persons.size());
});
}
@Test
public void test_criteria_group_by_example() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::criteria-group-by-example[]
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> criteria = builder.createQuery( Tuple.class );
Root<Person> root = criteria.from( Person.class );
criteria.groupBy(root.get("address"));
criteria.multiselect(root.get("address"), builder.count(root));
List<Tuple> tuples = entityManager.createQuery( criteria ).getResultList();
for ( Tuple tuple : tuples ) {
String name = (String) tuple.get( 0 );
Long count = (Long) tuple.get( 1 );
}
//end::criteria-group-by-example[]
assertEquals(2, tuples.size());
});
}
@Test
public void testLegacyCriteriaJpavsHibernateEntityName() {
doInJPA( this::entityManagerFactory, entityManager -> {
Event event1 = new Event();
event1.id = 1L;
event1.name = "E1";
entityManager.persist( event1 );
Event event2 = new Event();
event2.id = 2L;
event2.name = "E2";
entityManager.persist( event2 );
List<String> eventNames = entityManager.unwrap( Session.class )
.createQuery( "select ae.name from ApplicationEvent ae" )
.list();
try {
List<Event> events = entityManager.unwrap( Session.class )
.createCriteria( "ApplicationEvent" )
.list();
}
catch ( MappingException expected ) {
assertEquals( "Unknown entity: ApplicationEvent", expected.getMessage() );
}
List<Event> events = entityManager.unwrap( Session.class )
.createCriteria( Event.class.getName() )
.list();
});
}
@Entity(name = "ApplicationEvent")
public static class Event {
@Id
private Long id;
private String name;
}
}