JPA Queries and Tips

JPA: Creating a object from a query

The JPA allow us to create objects inside a query, just with the values that we need:

package com.model;

public class PersonDogAmountReport {
	private int dogAmount;
	private Person person;

	public PersonDogAmountReport(Person person, int dogAmount) {
		this.person = person;
		this.dogAmount = dogAmount;
	}

	public int getDogAmount() {
		return dogAmount;
	}

	public void setDogAmount(int dogAmount) {
		this.dogAmount = dogAmount;
	}

	public Person getPerson() {
		return person;
	}

	public void setPerson(Person person) {
		this.person = person;
	}
}
package com.main;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import com.model.PersonDogAmountReport;

public class Page13 {

	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		CodeGenerator.startConnection();

		CodeGenerator.generateData();

		EntityManager em = CodeGenerator.getEntityManager();

		Query query = em.createQuery("select new com.model.PersonDogAmountReport(p, size(p.dogs)) from Person p group by p.id");

		List<PersonDogAmountReport> persons = query.getResultList();
		for (PersonDogAmountReport personReport : persons) {
			System.out.println(personReport.getPerson().getName() + " has: " + personReport.getDogAmount() + " dogs.");
		}

		CodeGenerator.closeConnection();
	}
}

Notice that inside our query we create a new object. The good news is that you can create any object, it does not need to be an entity. You just need to pass the full path of the class and the JPA will handle new class instantiation.

This is a very useful functionality to use with reports that you need of specifics fields but those fields do not exists in the entity.

16 Thoughts on “JPA Queries and Tips

  1. Hi uaihebert…

    I am a beginer in using JPA query ..
    I have wasted lots of time for finding LIKE query.
    But i found the exact one here..
    Thanx for the help.

  2. Pingback: Thema der Woche: JPA

  3. ragnor on July 19, 2012 at 9:05 am said:

    Hi! Nice article but few mistakes have crept into the queries:

    select p, count(p) from Person p join p.dogs d where d.weight > :weight group by p

    select min(weight), max(weight) from Dog

    select p, count(p) from Person p join p.dogs group by p.id having count(p) > :dogAmount

    the correct versions IMO are:
    select p, count(d) from Person p join p.dogs d where d.weight > :weight group by p

    select min(d.weight), max(d.weight) from Dog d

    select p, count(p.dogs) from Person p join p.dogs group by p.id having count(p) > :dogAmount

  4. Pingback: JPA Queries and Tips   | Hibernate | Scoop.it

  5. Wouter Oet on July 12, 2012 at 12:21 am said:

    Another couple of things:

    You shouldn’t introduce dublicated literal Strings:
    @Entity
    @NamedQueries({
    @NamedQuery(name=”Person.findByName”, query=”select p from Person p where p.name = :name”),
    @NamedQuery(name=”Person.findByAge”, query=”select p from Person p where p.age = :age”)})
    })
    public class Person {

    public static final String FIND_BY_NAME = “Person.findByName”;
    public static final String FIND_BY_AGE = “Person.findByAge”;
    ….

    Should be:
    @Entity
    @NamedQueries({
    @NamedQuery(name=Person.FIND_BY_NAME, query=”select p from Person p where p.name = :name”),
    @NamedQuery(name=Person.FIND_BY_AGE, query=”select p from Person p where p.age = :age”)})
    })
    public class Person {

    public static final String FIND_BY_NAME = “Person.findByName”;
    public static final String FIND_BY_AGE = “Person.findByAge”;
    ….

    You should make use of TypedQueries when using normal, named or even native queries:
    private static List getDogsByDayOfBirth(EntityManager em, Date dateOfBirth) {
    TypedQuery query = em.createNamedQuery(Dog.FIND_BY_DATE_OF_BIRTH, Dog.class);
    query.setParameter(“dateOfBirth”, dateOfBirth, TemporalType.DATE);
    return query.getResultList();
    }

    Instead of:
    @SuppressWarnings(“unchecked”)
    private static List getDogsByDayOfBirth(EntityManager em, Date dateOfBirth) {
    Query query = em.createNamedQuery(Dog.FIND_BY_DATE_OF_BIRTH);
    query.setParameter(“dateOfBirth”, dateOfBirth, TemporalType.DATE);
    return query.getResultList();
    }

    You don’t need to use EJB’s for transactions. It can easily be done in Java SE. You
    (basically) just need to start and end the transaction.

    The CriteriaBuilder API might be verbose but it allows you to create (compile-time) type-safe
    queries and build generic queries (for DAO’s for example). I personally can recommend JPA 2 by
    Mike Keith and Merrick Schincariol if you want a good book about JPA which includes the
    CriteriaBuilder API.

    • uaihebert on July 12, 2012 at 12:32 am said:

      Hello again Wouter!

      I am really thankful for your observation. Really! :D

      About the TypedQuery I answered you in the topic above.

      About the NamedQuery name I did not though about that. It is a really better practice.

      Thanks for sharing your knowledge.

      I will consider to edit this post later! =D

  6. Wouter Oet on July 11, 2012 at 11:49 pm said:

    You’re very generous with the @SuppressWarnings(‘unchecked’) annotation. In 9/10 cases you don’t need it.
    E.g. on page 4, this:

    @SuppressWarnings(‘unchecked’)
    private static List listAllDogs(EntityManager em) {
    Query query = em.createQuery(‘select d from Dog d’, Dog.class);
    return query.getResultList();
    }

    Should be:

    private static List listAllDogs(EntityManager em) {
    TypedQuery query = em.createQuery(‘select d from Dog d’, Dog.class);
    return query.getResultList();
    }

    • uaihebert on July 12, 2012 at 12:30 am said:

      Hello Wouter,

      Indeed I could change the @SuppressWarnings(‘unchecked’) with the TypedQuery interface.

      When I wrote this tutorial I did not had any knowledge about JPA 2.0.

      Two weeks after I wrote this I was reading the Pro JPA 2 book and found out about the TypedQuery.

      Thanks for the observation.

      It will help others that pass by here.

      [=

  7. matcouto on July 11, 2012 at 10:29 am said:

    Hello Hebert,
    Firstly congrats for this post, really good tips.
    I just didn’t get why you’re flushing after every operation!? It could compromise your application, like, what if you want to rollback this updated object on setAddressToOtherPerson() method due to an error/exception on deletePerson()?

    • uaihebert on July 11, 2012 at 3:04 pm said:

      Hello matcouto,

      If a developer uses the flush method to many times that will decrease the application performance for sure.

      For this post it is used just to process the data correctly. [=

      A developer can use the Open Session in View pattern to avoid this or handle the transaction in the View. [=

      Thanks for passing by, and for the support.

  8. John on July 11, 2012 at 4:12 am said:

    Great article but unfortunate page layout makes code samples impossible to read.
    You have to scroll left-right in every code window.
    This is torture! like making us look at code samples through keyhole.

    • uaihebert on July 11, 2012 at 2:59 pm said:

      Hello John,

      I do not have a good knowledge of css to edit it know, but I will someday.

      Thanks for the tip. [=

Leave a Reply

Post Navigation