You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by th...@apache.org on 2013/12/03 18:17:19 UTC

svn commit: r1547483 - /deltaspike/site/trunk/content/data.mdtext

Author: thug
Date: Tue Dec  3 17:17:19 2013
New Revision: 1547483

URL: http://svn.apache.org/r1547483
Log:
Data module documentation initial version.

Added:
    deltaspike/site/trunk/content/data.mdtext   (with props)

Added: deltaspike/site/trunk/content/data.mdtext
URL: http://svn.apache.org/viewvc/deltaspike/site/trunk/content/data.mdtext?rev=1547483&view=auto
==============================================================================
--- deltaspike/site/trunk/content/data.mdtext (added)
+++ deltaspike/site/trunk/content/data.mdtext Tue Dec  3 17:17:19 2013
@@ -0,0 +1,1127 @@
+Title:     Data Module
+Notice:    Licensed to the Apache Software Foundation (ASF) under one
+           or more contributor license agreements.  See the NOTICE file
+           distributed with this work for additional information
+           regarding copyright ownership.  The ASF licenses this file
+           to you under the Apache License, Version 2.0 (the
+           "License"); you may not use this file except in compliance
+           with the License.  You may obtain a copy of the License at
+           .
+             http://www.apache.org/licenses/LICENSE-2.0
+           .
+           Unless required by applicable law or agreed to in writing,
+           software distributed under the License is distributed on an
+           "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+           KIND, either express or implied.  See the License for the
+           specific language governing permissions and limitations
+           under the License.
+
+[TOC]
+
+***
+
+# Introduction
+
+The repository pattern used to be one of the core J2EE patterns and could be found in 
+most enterprise applications reading and writing data to persistent stores. 
+While the Java Persistence API (JPA) as part of Java EE 5+ has replaced many aspects of the
+repository pattern, it is still a good approach to centralize complex query logic related to 
+specific entities.
+
+The DeltaSpike Data module is intended to help you simplifying your repository layer.
+While you will have complex queries in a repository requiring your full attention,
+there will also be many simple ones often requiring boilerplate code and clutter.
+This is where the DeltaSpike data module will help you keeping your repository lean so you 
+can focus on the though things.
+
+The code sample below will give you a quick overview on the common usage scenarios of the data module:
+
+    :::java
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+    
+        List<Person> findByAgeBetweenAndGender(int minAge, int maxAge, Gender gender);
+    
+        @Query("select p from Person p where p.ssn = ?1")
+        Person findBySSN(String ssn);
+    
+        @Query(named=Person.BY_FULL_NAME)
+        Person findByFullName(String firstName, String lastName);
+    
+    }
+
+As you see in the sample, there are several usage scenarios outlined here:
+
+* Declare a method which executes a query by simply translating its name and parameters into a query.
+* Declare a method which automatically executes a given JPQL query string with parameters.
+* Declare a method which automatically executes a named query with parameters. 
+
+The implementation of the method is done automatically by the CDI extension. 
+A client can declare a dependency to the interface only. The details on how to use those 
+features are outlines in the following chapters.
+
+# Installation
+
+## Prerequisites
+
+The simplest way using the DeltaSpike data module is to run your application in a Java EE container
+supporting at least the Java EE 6 Web Profile. Other configurations like running it inside Tomcat or 
+even a Java SE application should be possible - you need to include a JPA provider as well as a CDI container
+to your application manually.
+
+Also note that in order to use abstract classes as repositories, this currently requires the presence
+of the http://www.javassist.org[javassist] library in your classpath.
+
+**CAUTION:**
+
+> Using DeltaSpike data in an EAR deployment is currently restricted to annotation-based entities.
+
+
+## Maven Dependency Configuration
+
+If you are using Maven as your build tool, you can add the following dependencies to your +pom.xml+
+file to include the DeltaSpike data module:
+
+    <dependency>
+        <groupId>org.apache.deltaspike.modules</groupId>
+        <artifactId>deltaspike-data-module-api</artifactId>
+        <version>${deltaspike.version}</version>
+        <scope>compile</scope>
+    </dependency>
+    <dependency>
+        <groupId>org.apache.deltaspike.modules</groupId>
+        <artifactId>deltaspike-data-module-impl</artifactId>
+        <version>${deltaspike.version}</version>
+        <scope>runtime</scope>
+    </dependency>
+
+**TIP:**
+
+> Substitute the expression `${deltaspike.version}` with the most recent or appropriate version
+> of DeltaSpike. Alternatively, you can create a Maven user-defined property to satisfy this 
+> substitution so you can centrally manage the version. 
+
+Including the API at compile time and only include the implementation at runtime protects you from
+inadvertantly depending on an implementation class.
+
+## Setup your application
+
+DeltaSpike data requires an `EntityManager` exposed via a CDI producer - which is common practice
+in Java EE 6 applications.
+
+    :::java
+    public class DataSourceProducer
+    {
+
+        @PersistenceUnit
+        private EntityManagerFactory emf;
+
+        @Produces
+        public EntityManager create()
+        {
+            return emf.createEntityManager();
+        }
+
+        public void close(@Disposes EntityManager em)
+        {
+            if (em.isOpen())
+            {
+                em.close();
+            }
+        }
+
+    }
+
+
+This allows the `EntityManager` to be injected over CDI instead of only being used with a
+`@PersistenceContext` annotation. Using multiple `EntityManager` is explored in more detail
+in a following section.
+
+You're now ready to use repositories in your application!
+
+# Core Concepts
+
+## Repositories
+
+With the DeltaSpike data module, it is possible to make a repository out of basically any
+abstract class or interface (using a concrete class will work too, but you won't be able to use
+most of the CDI extension features). All that is required is to mark the type as such with a
+simple annotation:
+
+    :::java
+    @Repository(forEntity = Person.class)
+    public abstract class PersonRepository {
+        ...
+    }
+
+    @Repository(forEntity = Person.class)
+    public interface PersonRepository {
+        ...
+    }    
+
+
+The `@Repository` annotation tells the extension that this is a repository for the `Person` entity.
+Any method defined on the repository will be processed by the framework. The annotation does not
+require to set the entity class (we'll see later why) but if there are just plain classes or
+interfaces this is the only way to tell the framework what entity the repository relates to. 
+In order to simplify this, DeltaSpike data provides several base types.
+
+### The `EntityRepository` interface
+
+Although mainly intended to hold complex query logic, working with both a repository and an `EntityManager`
+in the service layer might unnecessarily clutter code. In order to avoid this for the most common cases,
+DeltaSpike Data provides base types which can be used to replace the entity manager.
+
+The top base type is the `EntityRepository` interface, providing common methods used with an `EntityManager`.
+The following code shows the most important methods of the interface:
+
+    :::java
+    public interface EntityRepository<E, PK extends Serializable>
+    {
+    
+        E save(E entity);
+    
+        void remove(E entity);
+    
+        void refresh(E entity);
+    
+        void flush();
+    
+        E findBy(PK primaryKey);
+    
+        List<E> findAll();
+    
+        List<E> findBy(E example, SingularAttribute<E, ?>... attributes);
+    
+        List<E> findByLike(E example, SingularAttribute<E, ?>... attributes);
+    
+        Long count();
+    
+        Long count(E example, SingularAttribute<E, ?>... attributes);
+    
+        Long countLike(E example, SingularAttribute<E, ?>... attributes);
+    
+    } 
+
+The concrete repository can then extend this basic interface. For our Person repository,
+this might look like the following:
+
+    :::java
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+    
+        Person findBySsn(String ssn);
+    
+    } 
+
+
+**TIP:**
+
+> Annotations on interfaces do not inherit. If the `EntityRepository` interface is extended by another
+> interface adding some more common methods, it is not possible to simply add the annotation there.
+> It needs to go on each concrete repository. The same is not true if a base class is introduced,
+> as we see in the next chapter. 
+
+### The `AbstractEntityRepository` class
+
+This class is an implementation of the `EntityRepository` interface and provides additional functionality
+when custom query logic needs also to be implemented in the repository.
+
+    :::java
+    public abstract class PersonRepository extends AbstractEntityRepository<Person, Long>
+    {
+    
+        public Person findBySSN(String ssn)
+        {
+            return getEntityManager()
+                    .createQuery("select p from Person p where p.ssn = ?1", Person.class)
+                    .setParameter(1, ssn)
+                    .getResultList();
+        }
+    
+    }
+
+
+## Using Multiple `EntityManager`
+
+While most applications will run just fine with a single `EntityManager`, there might be setups
+where multiple data sources are used. This can be configured with the `EntityManagerConfig` annotation:
+
+    :::java
+    @Repository
+    @EntityManagerConfig(entityManagerResolver = CrmEntityManagerResolver.class, flushMode = FlushModeType.COMMIT)
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+        ...
+    }
+    
+    public class CrmEntityManagerResolver implements EntityManagerResolver
+    {
+        @Inject @CustomerData // Qualifier - assumes a producer is around...
+        private EntityManager em;
+
+        @Override
+        public EntityManager resolveEntityManager()
+        {
+            return em;
+        }
+    }
+
+
+Again, note that annotations on interfaces do not inherit, so it's not possible to create something like a base
+`CrmRepository` interface with the `@EntityManagerConfig` and then extending / implementing this interface.
+
+
+# Query Method Expressions
+
+Good naming is a difficult aspects in software engineering. A good method name usually makes 
+comments unnecessary and states exactly what the method does. And with method expressions, the 
+method name is actually the implementation!
+
+## Using method expressions
+
+Let's start by looking at a (simplified for readability) example:
+
+    :::java
+    @Entity
+    public class Person
+    {
+
+        @Id @GeneratedValue
+        private Long id;
+        private String name;
+        private Integer age;
+        private Gender gender;
+
+    }
+
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        List<Person> findByNameLikeAndAgeBetweenAndGender(String name, 
+                                  int minAge, int maxAge, Gender gender);
+
+    }
+
+
+Looking at the method name, this can easily be read as query all Persons which have a name like
+the given name parameter, their age is between a min and a max age and having a specific gender.
+The DeltaSpike module can translate method names following a given format and directly generate
+the query implementation out of it (in EBNF-like form):
+
+
+    (Entity|List<Entity>) findBy(Property[Comparator]){Operator Property [Comparator]}
+
+
+Or in more concrete words:
+
+* The query method must either return an entity or a list of entities.
+* It must start with the `findBy` keyword (or related `findOptionalBy`, `findAnyBy`).
+* Followed by a property of the Repository entity and an optional comparator (we'll define this later). 
+  The property will be used in the query together with the comparator. Note that the number of arguments
+  passed to the method depend on the comparator.
+* You can add more blocks of property-comparator which have to be concatenated by a boolean operator. 
+  This is either an `And` or `Or`.
+
+Other assumptions taken by the expression evaluator:
+
+* The property name starts lower cased while the property in the expression has an upper cases first character. 
+
+Following comparators are currently supported to be used in method expressions:
+
+<table>
+  <thead>
+    <tr>
+      <td>Name</td><td># of Arguments</td><td>Description</td>
+    </tr>
+  </thead>
+  <tr><td>Equal</td>            <td>1</td><td>Property must be equal to argument value. If the operator is omitted in the expression, this is assumed as default.</td></tr>
+  <tr><td>NotEqual</td>         <td>1</td><td>Property must be not equal to argument value.</td></tr>
+  <tr><td>Like</td>             <td>1</td><td>Property must be like the argument value. Use the %-wildcard in the argument.</td></tr>
+  <tr><td>GreaterThan</td>      <td>1</td><td>Property must be greater than argument value.</td></tr>
+  <tr><td>GreaterThanEquals</td><td>1</td><td>Property must be greater than or equal to argument value.</td></tr>
+  <tr><td>LessThan</td>         <td>1</td><td>Property must be less than argument value.</td></tr>
+  <tr><td>LessThanEquals</td>   <td>1</td><td>Property must be less than or equal to argument value.</td></tr>
+  <tr><td>Between</td>          <td>2</td><td>Property must be between the two argument values.</td></tr>
+  <tr><td>IsNull</td>           <td>0</td><td>Property must be null.</td></tr>
+  <tr><td>IsNotNull</td>        <td>0</td><td>Property must be non-null.</td></tr>
+</table>
+
+Note that DeltaSpike will validate those expressions during startup, so you will notice early in case you have a typo
+in those expressions.
+
+## Query Ordering
+
+Beside comparators it's also possible to sort queries by using the `OrderBy` keyword, followed
+by the attribute name and the direction (`Asc` or `Desc`).
+
+    :::java
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        List<Person> findByLastNameLikeOrderByAgeAscLastNameDesc(String lastName);
+
+    } 
+
+## Nested Properties
+
+To create a comparison on a nested property, the traversal parts can be separated by a `_`:
+
+    ::java
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        List<Person> findByCompany_companyName(String companyName);
+
+    }
+
+## Query Options
+
+DeltaSpike supports query options on method expressions. If you want to page a query,
+you can change the first result as well as the maximum number of results returned:
+
+    :::java
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        List<Person> findByNameLike(String name, @FirstResult int start, @MaxResults int pageSize);
+
+    }
+
+## Method Prefix
+
+In case the `findBy` prefix does not comply with your team conventions, this can be adapted:
+
+    :::java
+    @Repository(methodPrefix = "fetchWith")
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        List<Person> fetchWithNameLike(String name, @FirstResult int start, @MaxResults int pageSize);
+
+    }
+
+# Query Annotations
+
+While method expressions are fine for simple queries, they will often reach their limit once things
+get slightly more complex. Another aspect is the way you want to use JPA: The recommended approach 
+using JPA for best performance is over named queries. To help incorporate those use cases, the 
+DeltaSpike data module supports also annotating methods for more control on the generated query.
+
+## Using Query Annotations
+
+The simples way to define a specific query is by annotating a method and providing the JPQL query
+string which has to be executed. In code, this looks like the following sample:
+
+    :::java
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        @Query("select count(p) from Person p where p.age > ?1")
+        Long countAllOlderThan(int minAge);
+
+    }
+
+The parameter binding in the query corresponds to the argument index in the method.
+
+You can also refer to a named query which is constructed and executed automatically. The `@Query`
+annotation has a named attribute which corresponds to the query name:
+
+    :::java
+    @Entity
+    @NamedQueries({
+        @NamedQuery(name = Person.BY_MIN_AGE,
+                    query = "select count(p) from Person p where p.age > ?1 order by p.age asc")
+    })
+    public class Person
+    {
+
+        public static final String BY_MIN_AGE = "person.byMinAge";
+        ...
+
+    }
+
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        @Query(named = Person.BY_MIN_AGE)
+        Long countAllOlderThan(int minAge);
+
+    }
+
+Same as before, the parameter binding corresponds to the argument index in the method. If the named
+query requires named parameters to be used, this can be done by annotating the arguments with the 
+`@QueryParam` annotation.
+
+**TIP:**
+
+> Java does not preserve method parameter names (yet), that's why the annotation is needed.
+
+    :::java
+    @NamedQuery(name = Person.BY_MIN_AGE,
+                query = "select count(p) from Person p where p.age > :minAge order by p.age asc")
+            
+    ...
+
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        @Query(named = Person.BY_MIN_AGE)
+        Long countAllOlderThan(@QueryParam("minAge") int minAge);
+
+    }
+
+It is also possible to set a native SQL query in the annotation. The `@Query` annotation has a native attribute
+which flags that the query is not JPQL but plain SQL:
+
+    :::java
+    @Entity
+    @Table(name = "PERSON_TABLE")
+    public class Person
+    {
+        ...
+    }
+
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        @Query(value = "SELECT * FROM PERSON_TABLE p WHERE p.AGE > ?1", isNative = true)
+        List<Person> findAllOlderThan(int minAge);
+
+    }
+
+## Annotation Options
+
+Beside providing a query string or reference, the `@Query` annotation provides also two more attributes:
+
+    :::java
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        @Query(named = Person.BY_MIN_AGE, max = 10, lock = LockModeType.PESSIMISTIC_WRITE)
+        List<Person> findAllForUpdate(int minAge);
+
+    }
+
+<table>
+  <thead>
+    <tr>
+      <td>Name</td><td>Description</td>
+    </tr>
+  </thead>
+  <tr><td>max</td> <td>Limits the number of results.</td></tr>
+  <tr><td>lock</td><td>Use a specific LockModeType to execute the query.</td></tr>
+</table>
+
+Note that these options can also be applied to method expressions.
+
+## Query Options
+
+All the query options you have seen so far are more or less static. But sometimes you might want
+to apply certain query options dynamically. For example, sorting criteria could come from a user
+selection so they cannot be known beforehand. DeltaSpike allows you to apply query options at runtime by
+using the `QueryResult` result type:
+
+    :::java
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        @Query("select p from Person p where p.age between ?1 and ?2")
+        QueryResult<Person> findAllByAge(int minAge, int maxAge);
+
+    }
+
+Once you have obtained a `QueryResult`, you can apply further options to the query:
+
+    :::java
+    List<Person> result = personRepository.findAllByAge(18, 65)
+        .sortAsc(Person_.lastName)
+        .sortDesc(Person_.age)
+        .lockMode(LockModeType.WRITE)
+        .hint("org.hibernate.timeout", Integer.valueOf(10))
+        .getResultList(); 
+
+**CAUTION:**
+
+> Note that sorting is only applicable to method expressions or non-named queries. For named queries it might be possible, but is currently only supported for Hibernate, EclipseLink and OpenJPA.
+
+Note that the `QueryResult` return type can also be used with method expressions.
+
+## Pagination
+
+We introduced the `QueryResult` type in the last chapter, which can also be used for pagination:
+
+    :::java
+    // Query API style
+    QueryResult<Person> paged = personRepository.findByAge(age)
+        .maxResults(10)
+        .firstResult(50);
+
+    // or paging style
+    QueryResult<Person> paged = personRepository.findByAge(age)
+        .withPageSize(10) // equivalent to maxResults
+        .toPage(5);
+
+    int totalPages = paged.countPages();
+
+## Bulk Operations
+
+While reading entities and updating them one by one might be fine for many use cases, applying bulk
+updates or deletes is also a common usage scenario for repositories. DeltaSpike supports this with a special
+marking annotation `@Modifying`:
+
+    :::java
+    @Repository
+    public interface PersonRepository extends EntityRepository<Person, Long>
+    {
+
+        @Modifying
+        @Query("update Person as p set p.classifier = ?1 where p.classifier = ?2")
+        int updateClassifier(Classifier current, Classifier next);
+
+    }
+
+Bulk operation query methods can either return void or int, which counts the number of entities affected
+by the bulk operation. 
+
+## Optional Query Results
+
+The JPA spec requires to throw exceptions in case the `getSingleResult()` method does either return 
+no or more than one result. This can result in tedious handling with try-catch blocks or have potential 
+impact on your transaction (as the `RuntimeException` might roll it back).
+
+DeltaSpike Data gives the option to change this to the way it makes most sense for the current usecase.
+While the default behavior is still fully aligned with JPA, it's also possible to request optional query results.
+
+## Zero or One Result
+
+With this option, the query returns `null` instead of throwing a `NoResultException` when there is no 
+result returned. It's usable with method expressions, `Query` annotations and `QueryResult<E>` calls.
+
+    :::java
+    @Repository(forEntity = Person.class)
+    public interface PersonRepository
+    {
+
+        Person findOptionalBySsn(String ssn);
+
+        @Query(named = Person.BY_NAME, singleResult = SingleResultType.OPTIONAL)
+        Person findByName(String firstName, String lastName);
+
+    }
+
+For method expressions, the `findOptionalBy` prefix can be used. For `@Query` annotations, the `singleResult`
+attribute can be overridden with the `SingleResultType.OPTIONAL` enum.
+
+In case the query returns more than one result, a `NonUniqueResultException` is still thrown.
+
+## Any Result
+
+If the caller does not really mind what kind if result is returned, it's also possible to request any 
+result from the query. If there is no result, same as for optional queries `null` is returned. In case 
+there is more than one result, any result is returned, or more concretely the first result out of the 
+result list.
+
+    :::java
+    @Repository(forEntity = Person.class)
+    public interface PersonRepository
+    {
+
+        Person findAnyByLastName(String lastName);
+
+        @Query(named = Person.BY_NAME, singleResult = SingleResultType.ANY)
+        Person findByName(String firstName, String lastName);
+
+    }
+
+For method expressions, the `findAnyBy` prefix can be used. For `@Query` annotations, the `singleResult`
+attribute can be overridden with the `SingleResultType.ANY` enum.
+
+This option will not throw an exception.
+
+# Extensions
+
+## Query Delegates
+
+While repositories defines several base interfaces, there might still be the odd convenience
+method that is missing. This is actually intentional - things should not get overloaded for each and
+every use case. That's why in DeltaSpike you can define your own reusable methods.
+
+For example, you might want to use the QueryDsl library in your repositories:
+
+    :::java
+    import com.mysema.query.jpa.impl.JPAQuery;
+
+    public interface QueryDslSupport
+    {
+        JPAQuery jpaQuery();
+    }
+
+    @Repository(forEntity = Person.class)
+    public interface PersonRepository extends QueryDslSupport
+    {
+       ...
+    }   
+
+## Implementing the Query Delegate
+
+The first step is to define an interface which contains the extra methods for your repositories
+(as shown above):
+
+    :::java
+    public interface QueryDslSupport
+    {
+        JPAQuery jpaQuery();
+    }
+
+As a next step, you need to provide an implementation for this interface once. It's also important
+that this implementation implements the `DelegateQueryHandler` interface (don't worry, this is just
+an empty marker interface):
+
+    :::java
+    public class QueryDslRepositoryExtension<E> implements QueryDslSupport, DelegateQueryHandler
+    {
+
+        @Inject
+        private QueryInvocationContext context;
+
+        @Override
+        public JPAQuery jpaQuery()
+        {
+            return new JPAQuery(context.getEntityManager());
+        }
+
+    }
+
+As you see in the sample, you can inject a `QueryInvocationContext` which contains utility methods
+like accessing the current `EntityManager` and entity class.       
+
+Note that, if you define multiple extensions with equivalent method signatures, there is no specific
+order in which the implementation is selected.
+
+# Mapping
+
+While repositories are primarily intended to work with Entities, it might be preferable in some
+cases to have an additional mapping layer on top of them, e.g. because the Entities are quite complex
+but the service layer needs only a limited view on it, or because the Entities are exposed over a
+remote interface and there should not be a 1:1 view on the domain model.
+
+DeltaSpike Data allows to directly plugin in such a mapping mechanism without the need to specify additional
+mapping methods:
+
+    :::java
+    @Repository(forEntity = Person.class)
+    @MappingConfig(PersonDtoMapper.class)
+    public interface PersonRepository
+    {
+
+        PersonDto findBySsn(String ssn);
+    
+        List<PersonDto> findByLastName(String lastName);
+
+    }
+
+The `PersonDtoMapper` class has to implement the `QueryInOutMapper` interface:
+
+    :::java
+    public class PersonDtoMapper implements QueryInOutMapper<Person>
+    {
+
+        @Override
+        public Object mapResult(Person result)
+        {
+            ... // converts Person into a PersonDto
+        }
+        ...
+    
+        @Override
+        public Object mapResultList(List<Simple> result)
+        {
+            ... // result lists can also be mapped into something different
+                // than a collection.
+        }
+    
+        @Override
+        public boolean mapsParameter(Object parameter)
+        {
+            return parameter != null && (
+                    parameter instanceof PersonDto || parameter instanceof PersonId);
+        }
+    
+        @Override
+        public Object mapParameter(Object parameter)
+        {
+            ... // converts query parameters if required
+        }
+    }
+
+The mapper can also be used to transform query parameters. Parameters are converted before
+executing queries and calling repository extensions.
+
+Note that those mapper classes are treated as CDI Beans, so it is possible to use injection
+in those beans (you might e.g. inject an `EntityManager` or other mappers). As the `@MappingConfig`
+refers to the mapper class directly, the mapper must be uniquely identifiable by its class.
+
+It's also possible to combine mappings with the base Repository classes:
+
+    :::java
+    @Repository(forEntity = Person.class)
+    @MappingConfig(PersonDtoMapper.class)
+    public interface PersonRepository extends EntityRepository<PersonDto, PersonId>
+    {
+        ...
+    }
+
+In this case, the `forEntity` attribute in the `@Repository` annotation is mandatory. Also it is up
+to the mapper to convert parameters correctly (in this example, a conversion from a `PersonDto`
+parameter to `Person` entity and from `PersonId` to `Long` is necessary).
+
+## Simple Mappings
+
+In many cases it's just required to map a DTO object back and forth. For this case, the `SimpleQueryInOutMapperBase` class 
+can be subclassed, which only requires to override two methods:
+
+    :::java
+    public class PersonMapper extends SimpleQueryInOutMapperBase<Person, PersonDto>
+    {
+        @Override
+        protected PersonDto toDto(Person entity)
+        {
+            ...
+        }
+
+        @Override
+        protected Person toEntity(PersonDto dto) {
+            ...
+        }
+    }
+
+# JPA Criteria API Support
+
+Beside automatic query generation, the DeltaSpike data module also provides a DSL-like API to create JPA 2 Criteria queries.
+It takes advantage of the JPA 2 meta model, which helps creating type safe queries.
+
+**TIP:**
+
+> The JPA meta model can easily be generated with an annotation processor. Hibernate or EclipseLink 
+> provide such a processor, which can be integrated into your compile and build cycle.
+
+Note that this criteria API is not intended to replace the standard criteria API - it's rather a utility
+API that should make life easier on the most common cases for a custom query. The JPA criteria API's 
+strongest point is certainly its type safety - which comes at the cost of readability. We're trying to 
+provide a middle way here. A less powerful API, but still type safe and readable.
+
+## API Usage
+
+The API is centered around the Criteria class and is targeted to provide a fluent interface
+to write criteria queries:
+
+    :::java
+    @Repository(forEntity = Person.class)
+    public abstract class PersonRepository implements CriteriaSupport<Person>
+    {
+
+        public List<Person> findAdultFamilyMembers(String name, Integer minAge)
+        {
+            return criteria()
+                    .like(Person_.name, "%" + name + "%")
+                    .gtOrEq(Person_.age, minAge)
+                    .eq(Person_.validated, Boolean.TRUE)
+                    .orderDesc(Person_.age)
+                    .getResultList();
+        }
+
+    }
+
+Following comparators are supported by the API:
+
+<table>
+  <thead>
+    <tr>
+      <td>Name</td><td>Description</td>
+    </tr>
+  </thead>
+  <tr><td>.eq(..., ...)  </td><td>Property value must be equal to the given value  </td></tr>
+  <tr><td>.in(..., ..., ..., ...)  </td><td>Property value must be in one of the given values.  </td></tr>
+  <tr><td>.notEq(..., ...)  </td><td>Negates equality  </td></tr>
+  <tr><td>.like(..., ...)  </td><td>A SQL `like` equivalent comparator. Use % on the value.  </td></tr>
+  <tr><td>.notLike(..., ...)  </td><td>Negates the like value  </td></tr>
+  <tr><td>.lt(..., ...)  </td><td>Property value must be less than the given value.  </td></tr>
+  <tr><td>.ltOrEq(..., ...)  </td><td>Property value must be less than or equal to the given value.  </td></tr>
+  <tr><td>.gt(..., ...)  </td><td>Property value must be greater than the given value.  </td></tr>
+  <tr><td>.ltOrEq(..., ...)  </td><td>Property value must be greater than or equal to the given value.  </td></tr>
+  <tr><td>.between(..., ..., ...)  </td><td>Property value must be between the two given values. </td></tr>
+  <tr><td>.isNull(...)  </td><td>Property must be `null`</td></tr>
+  <tr><td>.isNotNull(...)  </td><td>Property must be non-`null`  </td></tr>
+  <tr><td>.isEmpty(...)  </td><td>Collection property must be empty</td></tr>
+  <tr><td>.isNotEmpty(...)  </td><td>Collection property must be non-empty</td></tr>
+</table>
+
+The query result can be modified with the following settings:
+
+<table>
+  <thead>
+    <tr>
+      <td>Name</td><td>Description</td>
+    </tr>
+  </thead>
+  <tr><td>.orderAsc(...)</td><td>Sorts the result ascending by the given property. Note that this can be applied to several properties</td></tr>
+  <tr><td>.orderDesc(...)</td><td>Sorts the result descending by the given property. Note that this can be applied to several properties</td></tr>
+  <tr><td>.distinct()</td><td>Sets distinct to true on the query.</td></tr>
+</table>
+
+Once all comparators and query options are applied, the `createQuery()` method is called. 
+This creates a JPA TypedQuery object for the repository entity. If required, further processing can be applied here.
+
+## Joins
+
+For simple cases, restricting on the repository entity only works out fine, but once the data model
+gets more complicated, the query will have to consider relations to other entities. The module's criteria
+API therefore supports joins as shown in the sample below:
+
+    :::java
+    @Repository
+    public abstract class PersonRepository extends AbstractEntityRepository<Person, Long>
+    {
+
+        public List<Person> findByCompanyName(String companyName)
+        {
+            return criteria()
+                    .join(Person_.company,
+                        where(Company.class)
+                            .eq(Company_.name, companyName)
+                    )
+                    .eq(Person_.validated, Boolean.TRUE)
+                    .getResultList();
+        }
+
+    }
+
+Beside the inner and outer joins, also fetch joins are supported. Those are slighly simpler as seen in the next sample:
+
+    :::java
+    public abstract class PersonRepository extends AbstractEntityRepository<Person, Long>
+    {
+
+        public Person findBySSN(String ssn)
+        {
+            return criteria()
+                    .fetch(Person_.familyMembers)
+                    .eq(Person_.ssn, ssn)
+                    .distinct()
+                    .getSingleResult();
+        }
+
+    }
+
+## Boolean Operators
+
+By default, all query operators are concatenated as an and conjunction to the query. The DeltaSpike
+criteria API also allows to add groups of disjunctions.
+
+    :::java
+    public abstract class PersonRepository extends AbstractEntityRepository<Person, Long>
+    {
+
+        public List<Person> findAdults()
+        {
+            return criteria()
+                    .or(
+                        criteria().
+                            .gtOrEq(Person_.age, 18)
+                            .eq(Person_.origin, Country.SWITZERLAND),
+                        criteria().
+                            .gtOrEq(Person_.age, 21)
+                            .eq(Person_.origin, Country.USA)
+                    )
+                    .getResultList();
+        }
+
+    }
+
+## Selections
+
+It might not always be appropriate to retrieve full entities - you might also be interested
+in scalar values or by modified entity attributes. The Criteria interface allows this with the
+selection method:
+
+    :::java
+    public abstract class PersonRepository extends AbstractEntityRepository<Person, Long>
+    {
+
+        public Statistics ageStatsFor(Segment segment)
+        {
+            return criteria()
+                     .select(Statistics.class, avg(Person_.age), min(Person_.age), max(Person_.age))
+                     .eq(Person_.segment, segment)
+                     .getSingleResult();
+        }
+
+        public List<Object[]> personViewForFamily(String name)
+        {
+            return criteria()
+                     .select(upper(Person_.name), attribute(Person_.age), substring(Person_.firstname, 1))
+                     .like(Person_.name, name)
+                     .getResultList();
+        }
+
+    }
+
+There are also several functions supported which can be used in the selection clause:
+
+<table>
+  <thead>
+    <tr>
+      <td>Name</td><td>Description</td>
+    </tr>
+  </thead>
+  <tr><td>abs(...)</td><td>Absolute value. Applicable to Number attributes.</td></tr>
+  <tr><td>avg(...)</td><td>Average value. Applicable to Number attributes.</td></tr>
+  <tr><td>count(...) </td><td>Count function. Applicable to Number attributes.</td></tr>
+  <tr><td>max(...) </td><td>Max value. Applicable to Number attributes.</td></tr>
+  <tr><td>min(...) </td><td>Min value. Applicable to Number attributes.</td></tr>
+  <tr><td>modulo(...)</td><td>Modulo function. Applicable to Integer attributes.</td></tr>
+  <tr><td>neg(...)</td><td>Negative value. Applicable to Number attributes.</td></tr>
+  <tr><td>sum(...) </td><td>Sum function. Applicable to Number attributes.</td></tr>
+  <tr><td>lower(...)</td><td>String to lowercase. Applicable to String attributes.</td></tr>
+  <tr><td>substring(int from, ...)</td><td>Substring starting from. Applicable to String attributes.</td></tr>
+  <tr><td>substring(int from, int to, ...)</td><td>Substring starting from ending to. Applicable to String attributes.</td></tr>
+  <tr><td>upper(...) </td><td>String to uppercase. Applicable to String attributes.</td></tr>
+  <tr><td>currDate() </td><td>The DB sysdate. Returns a Date object.</td></tr>
+  <tr><td>currTime() </td><td>The DB sysdate. Returns a Time object.</td></tr>
+  <tr><td>currTStamp()</td><td>The DB sysdate. Returns a Timestamp object. </td></tr>
+</table>
+
+# Auditing
+
+A common requirement for entities is tracking what is being done with them. DeltaSpike provides
+a convenient way to support this requirement.
+
+**TIP:**
+
+> DeltaSpike does not support creating revisions of entities. If this is a requirement for your audits, 
+> have a look at Hibernate Envers.
+
+## Activating Auditing
+
+DeltaSpike uses an entity listener to update auditing data before entities get created or update.
+The entity listener must be activated before it can be used. This can either be done globally for
+all entities of a persistent unit or per entity.
+
+Activation per persistence unit in `orm.xml`:
+
+    <entity-mappings 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_2_0.xsd" version="2.0">
+        <persistence-unit-metadata>
+            <persistence-unit-defaults>
+                <entity-listeners>
+                    <entity-listener class="org.apache.deltaspike.data.impl.audit.AuditEntityListener" />
+                </entity-listeners>
+            </persistence-unit-defaults>
+        </persistence-unit-metadata>
+    </entity-mappings>
+
+Activation per entity:
+
+    :::java
+    @Entity
+    @EntityListeners(AuditEntityListener.class)
+    public class AuditedEntity
+    {
+
+        ...
+
+    } 
+
+Note that for this variant, you need a compile dependency on the impl module. Alternatively, also the per
+entity listener can be configured by XML.
+
+## Using Auditing Annotations
+
+All that has to be done now is annotating the entity properties which are used to audit the entity.
+
+### Updating Timestamps
+
+To keep track on creation and modification times, following annotations can be used:
+
+    :::java
+    @Entity
+    public class AuditedEntity
+    {
+
+        ...
+
+        @Temporal(TemporalType.TIMESTAMP)
+        @CreatedOn
+        private Date created;
+
+        @Temporal(TemporalType.TIMESTAMP)
+        @ModifiedOn
+        private Date updated;
+
+        ...
+
+    }
+
+In case the modification date should also be set during entity creation, the annotation can be customized:
+
+    :::java
+    @ModifiedOn(setOnCreate=true)
+
+### Who's Changing My Entities?
+
+Beside keeping track of when a change has happened, it's also often critical to track who's responsible
+for the change. Annotate a user tracking field with the following annotation:
+
+    :::java
+    @Entity
+    public class AuditedEntity
+    {
+
+        ...
+
+        @ModifiedBy
+        private String auditUser;
+
+        ... 
+
+    }
+
+Now a little help is needed. The entity listener needs to be able to resolve the current user -
+there must be a bean available of the matching type for the annotation property, exposed over a special CDI qualifier:
+
+    :::java
+    public class UserProvider
+    {
+
+        @Inject
+        private User user;
+
+        @Produces @CurrentUser
+        public String currentUser() {
+            return user.getUsername();
+        }
+
+        ... 
+
+    }        
+
+**TIP:**
+
+> The JPA Spec does not recommend to modify entity relations from within a lifecycle callback. 
+> If you expose another entity here, make sure that your persistence provider supports this. Also you 
+> should ensure that the entity is attached to a persistent context. Also, be aware that the CDI container
+> will proxy a scoped bean, which might confuse the persistence provider when persisting / updating the 
+> target entity.
\ No newline at end of file

Propchange: deltaspike/site/trunk/content/data.mdtext
------------------------------------------------------------------------------
    svn:eol-style = native