/* * 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.hql; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.junit.Before; import org.junit.Test; import org.jboss.logging.Logger; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Vlad Mihalcea */ public class SelectDistinctTest extends BaseEntityManagerFunctionalTestCase { private static final Logger log = Logger.getLogger( SelectDistinctTest.class ); @Override protected Class<?>[] getAnnotatedClasses() { return new Class<?>[] { Person.class, Book.class }; } @Before public void init() { doInJPA( this::entityManagerFactory, entityManager -> { Person gavinKing = new Person("Gavin", "King" ); Person stephanKing = new Person("Stephen", "King" ); Person vladMihalcea = new Person("Vlad", "Mihalcea" ); gavinKing.addBook( new Book( "Hibernate in Action" ) ); gavinKing.addBook( new Book( "Java Persistence with Hibernate" ) ); stephanKing.addBook( new Book( "The Green Mile" ) ); vladMihalcea.addBook( new Book( "High-Performance Java Persistence" ) ); entityManager.persist( gavinKing ); entityManager.persist( stephanKing ); entityManager.persist( vladMihalcea ); }); } @Test public void testDistinctProjection() { doInJPA( this::entityManagerFactory, entityManager -> { //tag::hql-distinct-projection-query-example[] List<String> lastNames = entityManager.createQuery( "select distinct p.lastName " + "from Person p", String.class) .getResultList(); //end::hql-distinct-projection-query-example[] assertTrue( lastNames.size() == 2 && lastNames.contains( "King" ) && lastNames.contains( "Mihalcea" ) ); }); } @Test public void testAllAuthors() { doInJPA( this::entityManagerFactory, entityManager -> { List<Person> authors = entityManager.createQuery( "select p " + "from Person p " + "left join fetch p.books", Person.class) .getResultList(); authors.forEach( author -> { log.infof( "Author %s wrote %d books", author.getFirstName() + " " + author.getLastName(), author.getBooks().size() ); } ); }); } @Test public void testDistinctAuthors() { doInJPA( this::entityManagerFactory, entityManager -> { //tag::hql-distinct-entity-query-example[] List<Person> authors = entityManager.createQuery( "select distinct p " + "from Person p " + "left join fetch p.books", Person.class) .getResultList(); //end::hql-distinct-entity-query-example[] authors.forEach( author -> { log.infof( "Author %s wrote %d books", author.getFirstName() + " " + author.getLastName(), author.getBooks().size() ); } ); }); } @Test public void testDistinctAuthorsWithoutPassThrough() { doInJPA( this::entityManagerFactory, entityManager -> { //tag::hql-distinct-entity-query-hint-example[] List<Person> authors = entityManager.createQuery( "select distinct p " + "from Person p " + "left join fetch p.books", Person.class) .setHint( QueryHints.HINT_PASS_DISTINCT_THROUGH, false ) .getResultList(); //end::hql-distinct-entity-query-hint-example[] authors.forEach( author -> { log.infof( "Author %s wrote %d books", author.getFirstName() + " " + author.getLastName(), author.getBooks().size() ); } ); }); } @Entity(name = "Person") @Table( name = "person") public static class Person { @Id @GeneratedValue private Long id; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) private List<Book> books = new ArrayList<>( ); public Person() { } public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public List<Book> getBooks() { return books; } public void addBook(Book book) { books.add( book ); book.setAuthor( this ); } } @Entity(name = "Book") @Table( name = "book") public static class Book { @Id @GeneratedValue private Long id; private String title; @ManyToOne private Person author; public Book() { } public Book(String title) { this.title = title; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Person getAuthor() { return author; } public void setAuthor(Person author) { this.author = author; } } }