:toc: macro
toc::[]

= Data Access Object

The _Data Access Objects_ (DAOs) are part of the persistence layer.
They are responsible for a specific xref:entity[entity] and should be named `«Entity»Dao` and `«Entity»DaoImpl`.
The DAO offers the so called CRUD-functionalities (create, retrieve, update, delete) for the corresponding entity.
Additionally a DAO may offer advanced operations such as link:guide-jpa-query[query] or locking methods.

== DAO Interface
For each DAO there is an interface named `«Entity»Dao` that defines the API. For CRUD support and common naming we derive it from the `ApplicationDao` interface that comes with the devon application template:
[source,java]
----
public interface MyEntityDao extends ApplicationDao<MyEntity> { 
  List<MyEntity> findByCriteria(MyEntitySearchCriteria criteria);
}
----
All CRUD operations are inherited from `ApplicationDao` so you only have to declare the additional methods.

== DAO Implementation
Implementing a DAO is quite simple. We create a class named `«Entity»DaoImpl` that extends `ApplicationDaoImpl` and implements your `«Entity»Dao` interface:
[source,java]
----
public class MyEntityDaoImpl extends ApplicationDaoImpl<MyEntity> implements MyEntityDao { 

  public List<MyEntity> findByCriteria(MyEntitySearchCriteria criteria) {
    TypedQuery<MyEntity> query = createQuery(criteria, getEntityManager());
    return query.getResultList();
  }
  ...
}
----

Again you only need to implement the additional non-CRUD methods that you have declared in your `«Entity»Dao` interface.
In the DAO implementation you can use the method `getEntityManager()` to access the `EntityManager` from the JPA. You will need the `EntityManager` to create and execute link:guide-jpa-query[queries].

=== Static queries for DAO Implementation
All static link:guide-jpa-query[queries] are declared in the file `src\main\resources\META-INF\orm.xml`:
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="1.0" xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd">
  <named-query name="find.dish.with.max.price">
    <query><![SELECT dish FROM DishEntity dish WHERE dish.price <= :maxPrice]]></query>
  </named-query>
  ...
</hibernate-mapping>
----
When your application is started, all these static queries will be created as prepared statements. This allows better performance and also ensures that you get errors for invalid JPQL queries when you start your app rather than later when the query is used.

To avoid redundant occurrences of the query name (`get.open.order.positions.for.order`) we define a constant for each named query:
[source,java]
----
public class NamedQueries {
  public static final String FIND_DISH_WITH_MAX_PRICE = "find.dish.with.max.price"; 
}
----
Note that changing the name of the java constant (`FIND_DISH_WITH_MAX_PRICE`) can be done easily with refactoring. Further you can trace where the query is used by searching the references of the constant.

The following listing shows how to use this query:
[source,java]
----
public List<DishEntity> findDishByMaxPrice(BigDecimal maxPrice) {
  Query query = getEntityManager().createNamedQuery(NamedQueries.FIND_DISH_WITH_MAX_PRICE);
  query.setParameter("maxPrice", maxPrice);
  return query.getResultList();
}
----
Via `EntityManager.createNamedQuery(String)` we create an instance of `Query` for our predefined static query.
Next we use `setParameter(String, Object)` to provide a parameter (`maxPrice`) to the query. This has to be done for all parameters of the query.

Note that using the `createQuery(String)` method, which takes the entire query as string (that may already contain the parameter) is not allowed to avoid SQL injection vulnerabilities.
When the method `getResultList()` is invoked, the query is executed and the result is delivered as `List`. As an alternative, there is a method called `getSingleResult()`, which returns the entity if the query returned exactly one and throws an exception otherwise.