gert-wijns / TypeSafeQueryBuilder

Compile time assistence while creating queries, making them more type safe and easier to refactor
6 stars 8 forks source link

The goal of TypeSafeQueryBuilder is to allow writing queries using your hibernate configured entity classes rather than hand-coded HQL strings.

For an overview of the available functionality, see Functionality overview. The rest of this page will be a basic tutorial to get started. Basic knowledge of HQL is required to understand the examples and functionality overview.

Setup

Add library using maven:

<dependency>
    <groupId>com.github.gert-wijns</groupId>
    <artifactId>TypeSafeQueryBuilder</artifactId>
    <version>4.0.0</version>
</dependency>

To obtain a query, create a TypeSafeQueryDao with the hibernate sessionFactory and call the createQuery() method on it.

TypeSafeQueryDao dao = new TypeSafeQueryDaoImpl(sessionFactory);
TypeSafeRootQuery query = dao.createQuery();

To list the query results, call the doQuery(TypeSafeRootQuery query) method available on the TypeSafeQueryDao.

// build useful query and then use doQuery to list the results:
List<InterestingData> results = dao.doQuery(query);

From clause

To query from an entity, use the query.from(Class<?> entityClass) method. This will return a proxy of the entityClass to continue building the query.

Person person = query.from(Person.class); // would select people

=> "from Person hobj1" // Note: automatic unique alias provided

See also:

Select clause

There is a wide range of select options for various cases. This example will deal with selecting a subset of entity properties into a dto.

To select data into a dto, create a dto proxy using the query.select(Class<?> dtoClass) method. This will return a proxy of the dtoClass to which data of the entity can be set using a setter of the dto proxy with a getter of the entity proxy. Note: calling the setter and getter will only bind the property to be selected into the dto. The value is only available after listing the query results.

// select creates proxy instance of dto class
PersonDto personDto = query.select(PersonDto.class);
// binds person age to the personAge property
personDto.setPersonAge(person.getAge());

=> "select hobj1.age as personAge from Person hobj1"

See also:

Where clause

To specificy the where clause of a query, start by using the query.where(property) method. Depending on the property type, a list of relevant methods to build the restriction will be available. For example: using a Date as property, it is possible to check if the date is not before some other date while this check would not be available when using a Number property.

query.where(person.getAge()).gt(50)

=> "from Person hobj1 where hobj1.age > :np1" [np1=50]

Adding more and restrictions and grouping or restrictions is covered in the functionality overview.

See also:

Join clause

Entities can be joined by using the query.join(...) methods. Additionally, entities may also be joined implicitely by using the getter method of an entity proxy. It is only possible to obtain a proxy of a collection relation by using the join(...) methods.

// join and obtain a proxy of a collection element
Relation childRelation = query.join(parent.getChildRelations());
// join implicitly, returns a proxy of the getter type
Person child = childRelation.getChild();

=> "from Person hobj1 join hobj1.childRelations hobj2 join hobj2.child hobj3"

Entities could also be joined even when there is no explicit object relation using class joins.

// join to obtain a proxy of an entity, parent is needed to link the joined entity to the parent
Relation childRelation = query.join(parent, Relation.class, ClassJoinType.Inner);
// joinWith is required for class joins, specifies how the entities are related in sql
query.joinWith(childRelation).where(parent.getId()).eq(childRelation.getParent().getId());

=> from Person hobj1 join Relation hobj2 on hobj1.id = hobj2.parent.id

See also:

Order By clause

Sorting values can be done by using the query.orderBy() method and subsequently calling the desc(...) or asc(...) methods. These methods can be chained to sort by multiple values.

query.orderBy().desc(person.getName()).
                 asc(person.getAge());

=> "from Person hobj1 order by hobj1.name desc, hobj1.age"

See also:

Group By clause

Grouping values can be done by using the query.groupBy(...) method.

PersonDto personDto = query.select(PersonDto.class);
personDto.setPersonAge(person.getAge());
query.groupBy(person.getAge());

=> "select hobj1.age as personAge from Person hobj1 group by hobj1.age"

See also:

Having clause

Having restrictions can be add by using query.having(...).

Building building = query.from(Building.class);
query.select(building.getConstructionDate());
query.groupBy(building.getConstructionDate());

Date dateArg = new Date();
query.having(building.getConstructionDate()).after(dateArg);

=> "select hobj1.constructionDate
    from Building hobj1
    group by hobj1.constructionDate
    having hobj1.constructionDate > :np1"
params [np1=dateArg]