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


Reply via email to