How to add finder methods to Parancoe DAOs

With Parancoe for having a DAO for an entity You simply need to define its interface.

As an example we will use the following entity:


package org.parancoe.example.po;

import java.util.Date;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@javax.persistence.Entity()
public class Person extends EntityBase {
    private String firstName;
    private String lastName;
    private Date birthDate;
    private String email;

    /** Creates a new instance of Person */
    public Person() {
    }

    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;
    }

    @Temporal(TemporalType.DATE)
    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }    

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Its base generic DAO is:


package org.parancoe.example.dao;

import org.parancoe.example.po.Person;
import org.parancoe.persistence.dao.generic.Dao;
import org.parancoe.persistence.dao.generic.GenericDao;

@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
}

Then You can use the methods available in the base generic DAO, and add finder methods to the interface. You don’t need to implements such methods, just declare them in the interface.

Find by field equality

For example, you need to find all people with first name equals to “John”. Add to the interface the following method:


@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
  List<Person> findByFirstName(String firstName);
}

Again, You don’t need to implement it, simply use it:


List<Person> people = dao.findByFirstName("John");

The dao object can be auto-wired by type in your Spring context.

If the finder needs to compare on more fields, simply list them in the method name separated by the “And” keyword:


@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
  List<Person> findByFirstName(String firstName);
  List<Person> findByFirstNameAndLastNameAndBirthDate(String firstName, String lastName, Date birthDate);
}

Ordering results

If you need to order (ascending) the results, declare a method as the following:


@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
  List<Person> findByBirthDateOrderByLastName(Date birthDate);
}

Again, If you need to order on more than one field, list the fields you need:


List<Person> findByBirthDateOrderByLastNameAndFirstName(Date birthDate);

If you don’t want to filter by equality, but the result must contains all records, omit the list of fields:


List<Person> findByOrderByLastNameAndFirstName();

Find a single object (from 0.3.3)

Define the finder method returning the entity type, not a List:


Person findByFirstNameAndLastName(String firstName, String lastName);

If the query will produce more than one result, only the first one in the list will be returned. If the query will produce no results, the method will return null.

Write the query in HQL

You can write an HQL query and add a method in the DAO interface that will execute it when invoked. Declare the method as you like in the DAO interface, and declare the query as a named query in the DAO’s entity. The name of the query must be <entity name>.<DAO method name>.

The method parameters are passed in the same order as values for the query parameters.

For example:


@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
  List<Person> findByPartialUncasedLastName(String partialLastName);
}

@Entity()
@NamedQueries({
  @NamedQuery(
    name="Person.findByPartialUncasedLastName",
    query="from Person p where lower(p.lastName) like lower(?) order by p.lastName")
}) 
public class Person extends EntityBase {
  // ...
}

Now You can invoke it:


List<Person> people = dao.findByPartialUncasedLastName("B%");

Finder method with support for the pagination of results (from 0.3.3)

You can annotate the finder method parameters with the @FirstResult and @MaxResults annotations.

For example:


@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
  List<Person> findByLastName(String lastName,
                              @FirstResult int firstResult,
                              @MaxResults int maxResults);
}

The type of the annotate parameter must be int.

You can apply this technique to finder methods associated to named queries, without the need to modify the query.

For example:


@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
  List<Person> findByPartialUncasedLastName(String partialLastName,
                                            @FirstResult int firstResult,
                                            @MaxResults maxResults);
}

@Entity()
@NamedQueries({
  @NamedQuery(
    name="Person.findByPartialUncasedLastName",
    query="from Person p where lower(p.lastName) like lower(?) order by p.lastName")
}) 
public class Person extends EntityBase {
  // ...
}

If there are situations in which you don’t want to limit the number of records, you can pass a negative value for the maxRecords parameter:


List<Person> people = dao.findByPartialUncasedLastName("B%", 0, -1);

It will return all records, from the first (0) to the end.

Using different strategies for comparing parameter values (from 0.3.3)

In totally dynamic finders you can choose the type of the comparison applied to each parameter using the @compare annotation.

For example:


@Dao(entity=Person.class)
public interface PersonDao extends GenericDao<Person, Long> {
  List<Person> findByLastName(
                 @Compare(CompareType.ILIKE) String lastName);
}

The supported comparison strategies are:

  • EQUAL: equality, it’s the default
  • LIKE: like, using ’%’
  • ILIKE: case-insensitive like
  • GE: greater than or equal
  • GT: greater than
  • LE: less than or equal
  • LT: less than
  • NE: not equal

Posted by Lucio Benfante on Tuesday, August 28, 2007