h1. JPA persistence

Play provides a set of very useful helpers to simplify the management of your JPA entities.

p(note). **Note** that you can still go back to the plain JPA API whenever you want.

h2. <a name="starting">Starting the JPA entity manager</a>

Play will automatically start the Hibernate entity manager when it finds one or more classes annotated with the <code>@javax.persistence.Entity</code> annotation. However, make sure that you have correctly configured a JDBC datasource or it will fail.

h2. <a name="obtaining">Obtaining the JPA entity manager</a>

When the JPA entity manager is started you can get it from the application code, using the JPA helper. For example:

bc. public static index() {
    Query query = JPA.em().createQuery("select * from Article");
    List<Article> articles = query.getResultList();
    render(articles);
}

h2. <a name="transactions">Transaction management</a>

Play will automatically manage transactions for you. It will start a transaction for each HTTP request and commit it when the HTTP response is sent. If your code throws an exception, the transaction will automatically rollback.

If you need to force transaction rollback from the application code, you can use the @JPA.setRollbackOnly()@ method, which tells JPA not to commit the current transaction.

You can also use annotations to specify how transactions should be handled.

If you annotated the method in the controller with <code>@play.db.jpa.Transactional(readOnly=true)</code>, then the transaction will be read-only.

If you want to prevent Play from starting any transaction at all, you can annotate the method with <code>@play.db.jpa.NoTransaction</code>.

To prevent transactions for all methods, you can annotate the Controller-class with <code>@play.db.jpa.NoTransaction</code>.

When using <code>@play.db.jpa.NoTransaction</code>, Play does not get a connection from the connection pool at all - which improves speed.


h2. <a name="support">The **play.db.jpa.Model** support class</a>

This is the main helper class for JPA. If you make one of your JPA entities extend the @play.db.jpa.Model@ class, it will give you a lot of helper methods to simplify the JPA access.

For example, look at this Post model object:

bc.. @Entity
public class Post extends Model {

    public String title;
    public String content;
    public Date postDate;

    @ManyToOne
    public Author author;

    @OneToMany
    public List<Comment> comments;
}

p. The @play.db.jpa.Model@ class automatically provides an autogenerated @Long id@ field. We think that it’s generally a good idea to keep an auto-generated @Long id@ as primary key for JPA models (the technical primary key) and manage your functional primary key using another field.

Note that we have used the fact that Play automatically considers the Post class’ **public** members as **properties**. So we don’t need to write all setter/getter methods for this object.

h2. <a name="genericmodel">Custom id mapping with GenericModel</a>

Nothing forces you to base your entities on @play.db.jpa.Model@. Your JPA entities can also extend the @play.db.jpa.GenericModel@ class. This is required if you do not want to use a @Long id@ as the primary key for your entity.

For example, here is a mapping for a very simple @User@ entity. The @id@ is a UUID, the @name@ and @mail@ properties are required, and we use Play Validation to enforce simple business rules.

bc.. @Entity
public class User extends GenericModel {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    public String id;

    @Required
    public String name;

    @Required
    @MaxSize(value=255, message = "email.maxsize")
    @play.data.validation.Email
    public String mail;
}

h2. <a name="finding">Finding objects</a>

The @play.db.jpa.Model@ gives you several ways to find data. For example:

h3. Find by ID

The simplest way to find an object.

bc. Post aPost = Post.findById(5L);

h3. Find all

bc. List<Post> posts = Post.findAll();

This is the simplest way to retrieve **all** posts, but you can do the same using:

bc. List<Post> posts = Post.all().fetch();

This allows you to paginate results:

bc. // 100 max posts
List<Post> posts = Post.all().fetch(100);

or even,

bc. 
// 100 max posts start at 50
List<Post> posts = Post.all().from(50).fetch(100);

h3. Find using a simplified query

That allows you to create very expressive finders, but will only work for simple queries.

bc. Post.find("byTitle", "My first post").fetch();
Post.find("byTitleLike", "%hello%").fetch();
Post.find("byAuthorIsNull").fetch();
Post.find("byTitleLikeAndAuthor", "%hello%", connectedUser).fetch();

Simple queries follow the following syntax <code>==[Property][Comparator]And?==</code> where Comparator can be the following:

* @LessThan@ - less than the given value
* @LessThanEquals@ - less than or equal a give value
* @GreaterThan@ - greater than a given value
* @GreaterThanEquals@ - greater than or equal a given value
* @Like@ - Equivalent to a SQL like expression, except that the property will always convert to lower case.
* @Ilike@ - Similar to a Like, except case insensitive, meaning that your argument will convert to lower case too.
* @Elike@ - Equivalent to a SQL like expression, no conversion.
* @NotEqual@ - Negates equality
* @Between@ - Between two values (requires two arguments)
* @IsNotNull@ - Not a null value (doesn't require an argument)
* @IsNull@ - Is a null value (doesn't require an argument)

h3. Find using a JPQL query

You can use a JPQL query:

bc. Post.find(
    "select p from Post p, Comment c " +
    "where c.post = p and c.subject like ?", "%hop%"
);

or even a part of:

bc. Post.find("title", "My first post").fetch();
Post.find("title like ?", "%hello%").fetch();
Post.find("author is null").fetch();
Post.find("title like ? and author is null", "%hello%").fetch();
Post.find("title like ? and author is null order by postDate", "%hello%").fetch();

You can even specify only the @order by@ statement:

bc. Post.find("order by postDate desc").fetch();

h2. <a name="counting">Counting objects</a>

You can easily count objects.

bc. long postCount = Post.count();

Or even count using a query:

bc. long userPostCount = Post.count("author = ?", connectedUser);


h2. <a name="files">Storing uploaded files with play.db.jpa.Blob</a>

You can use the @play.db.jpa.Blob@ type to store uploaded files in the file system (not in the database). On the server, Play stores the uploaded image in a file in the @attachments/@ folder, inside the application folder. The file name (a "UUID":http://en.wikipedia.org/wiki/Uuid) and MIME type are stored in a database attribute whose SQL type is @VARCHAR@.

The basic use case of uploading, storing and serving a file is extremely easy in Play. This is because the binding framework automatically binds a file uploaded from an HTML form to your JPA model, and because Play provides convenience methods that make serving binary data as easy as serving plain text. To store file uploads in your model, add a property of type @play.db.jpa.Blob@

bc. import play.db.jpa.Blob;
 
@Entity
public class User extends Model {
 
   public String name;
   public Blob photo;
}

To upload files, add a form to your view template, and use a file upload form control for the model’s @Blob@ property:

bc. #{form @addUser(), enctype:'multipart/form-data'}
   <input type="file" name="user.photo">
   <input type="submit" name="submit" value="Upload">
#{/form}

Then, in the controller, add an action that saves the upload in a new model object:

bc. public static void addUser(User user) {
   user.save();
   index();
}

This code does not appear to do anything other than save the JPA entity, because the file upload is handled automatically by Play. First, before the start of the action method, the uploaded file is saved in a sub-folder of @tmp/uploads/@. Next, when the entity is saved, the file is copied to the @attachments/@ folder, with a UUID as the file name. Finally, when the action is complete, the temporary file is deleted.

If you upload another file for the same user, this will be saved as a new file on the server, whose name is a new UUID. This means that the original file will now be orphaned. If you do not have unlimited disk space then you will have to implement your own scheme for cleaning up, perhaps with an "asynchronous job":jobs.

If the HTTP request did not specify the file’s correct MIME type, you can use file name extension mapping, as described in the "controller file upload":controllers#file section.

To save attachments in a different folder, configure "attachments.path":configuration#attachments.path.

To serve a stored file, pass @Blob.get()@ to the controller’s @renderBinary@ method, as described in the "controller binary response":controllers#binary section.



h2. <a name="save">Explicit save</a>

Hibernate maintains a cache of Objects that have been queried from the database. These Objects are referred to as persistent Objects as long as the EntityManager that was used to fetch them is still active. That means that any changes to these Objects within the bounds of a transaction are automatically persisted when the transaction is committed. In standard JPA, these updates are implicit within the transaction’s boundary; you don’t have to explicitly call any method to persist the values.

The main downside is that we must manage all of our Objects manually. Instead of telling the EntityManager to update an Object (which would be far more intuitive), we must tell the EntityManager which Objects NOT to update. We do this by calling @refresh()@, which essentially rolls back a single entity. We do this just prior to calling commit on the transaction or when we realise the Object shouldn’t be updated.

Here is a common use case, when editing a persistent object after a form submit:

bc. public static void save(Long id) {
    User user = User.findById(id);
    user.edit("user", params.all());
    validation.valid(user);
    if(validation.hasErrors()) {
        // Here we have to explicitly discard the user modifications...
        user.refresh();
        edit(id);
    }
    show(id);
}

From what I’ve seen, most developers are not aware of this, and forget to discard the object state in case of errors, assuming that the object will not be saved without an explicit call to @save()@.

So that’s exactly what we’ve changed in Play. All the persistent objects extending the JPASupport/JPAModel will not be saved without an explicit call to the @save()@ method. So you can actually rewrite the previous code as:

bc. public static void save(Long id) {
    User user = User.findById(id);
    user.edit("user", params.all());
    validation.valid(user);
    if(validation.hasErrors()) {
        edit(id);
    } else{
       user.save(); // explicit save here
       show(id);
    }
}

This is far more intuitive. Moreover since it could be tedious to explicitly call @save()@ on a large object graph, the @save()@ call is automatically cascaded to the relationships annotated with the @cascade=CascadeType.ALL@ attribute.

h2. <a name="typing">More about generic typing problems</a>

The @play.db.jpa.Model@ defines a set of generic methods. These generic methods use a type parameter to specify the method’s return type. When using those methods, the concrete type to be used as return value is derived from the invocation context using type inference.

For example, the @findAll@ method is defined as:

bc. <T> List<T> findAll();

And you use it as:

bc. List<Post> posts = Post.findAll();

Here the Java compiler resolves the actual type of @T@ using the fact that you assign the method result to a ==List&lt;Post&gt;==. So T is resolved as a Post type.

Unfortunately, this doesn’t work if the generic method’s return value is directly used as a parameter for another method invocation or used in a loop. So the following code fails with a compiler error saying "Type mismatch: cannot convert from element type Object to Post":

bc. for(Post p : Post.findAll()) {
    p.delete();
}

Of course you can resolve this issue using a temporary local variable, as:

bc. List<Post> posts = Post.findAll(); // type inference works here!
for(Post p : posts) {
    p.delete();
}

But wait, there is a better way. You can use a practical but somewhat unknown Java language feature, which makes the code shorter while more readable at the same time:

bc. for(Post p : Post.<Post>findAll()) {
    p.delete();
}


p(note). It is important to notice that Play does not support XA (two-phase commits). If you use several different JPA configurations in the same request, **Play will try to commit as many transactions as possible**. If the commit to the first database succeeds and the second commit to the other database fails, the first commit will not get rolled back. Bear this in mind when using multiple JPA configurations in the same request.

p(note). **Continuing the discussion**

Now we’ll check some %(next)"Play libraries":libs%.
