Una representación del módelo de nuestro twitter simple podría ser la siguiente.

Modelo de twitter

Traduciendo el diagrama a código quedaría:

app/models/User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package models;

import java.util.ArrayList; import java.util.List; import javax.persistence.Entity; import javax.persistence.ManyToMany; import play.db.jpa.Model;

@Entity public class User extends Model {

<span class="kd">public</span> <span class="n">String</span> <span class="n">username</span><span class="o">;</span>

<span class="kd">public</span> <span class="n">String</span> <span class="n">password</span><span class="o">;</span>

<span class="nd">@ManyToMany</span>
<span class="kd">public</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">User</span><span class="o">&gt;</span> <span class="n">follows</span><span class="o">;</span>

<span class="kd">public</span> <span class="nf">User</span><span class="o">(</span><span class="n">String</span> <span class="n">username</span><span class="o">,</span> <span class="n">String</span> <span class="n">password</span><span class="o">)</span> <span class="o">{</span>
    <span class="kd">super</span><span class="o">();</span>
    <span class="k">this</span><span class="o">.</span><span class="na">username</span> <span class="o">=</span> <span class="n">username</span><span class="o">;</span>
    <span class="k">this</span><span class="o">.</span><span class="na">password</span> <span class="o">=</span> <span class="n">password</span><span class="o">;</span>
    <span class="n">follows</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">User</span><span class="o">&gt;();</span>
<span class="o">}</span>

}

app/models/Tweet.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package models;

import java.util.Date; import javax.persistence.Entity; import javax.persistence.ManyToOne; import play.db.jpa.Model;

@Entity public class Tweet extends Model {

<span class="kd">public</span> <span class="n">String</span> <span class="n">msg</span><span class="o">;</span>

<span class="nd">@ManyToOne</span>
<span class="kd">public</span> <span class="n">User</span> <span class="n">author</span><span class="o">;</span>

<span class="kd">public</span> <span class="n">Date</span> <span class="n">date</span><span class="o">;</span>

<span class="kd">public</span> <span class="nf">Tweet</span><span class="o">(</span><span class="n">String</span> <span class="n">msg</span><span class="o">,</span> <span class="n">User</span> <span class="n">author</span><span class="o">){</span>
    <span class="k">this</span><span class="o">.</span><span class="na">msg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">;</span>
    <span class="k">this</span><span class="o">.</span><span class="na">author</span> <span class="o">=</span> <span class="n">author</span><span class="o">;</span>
    <span class="n">date</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Date</span><span class="o">();</span>
<span class="o">}</span>

}

Enteniendo la creación del módelo

@Entity, @ManyToOne, @ManyToMone

Play utiliza Hibernate. Hibernate es una herramienta de Mapeo objeto-relacional (ORM) que facilita el mapeo de atributos entre una base de datos relacional tradicional y el modelo de objetos de una aplicación, mediante archivos declarativos (XML) o anotaciones en los beans de las entidades que permiten establecer estas relaciones.

Hibernate es una implementación del standard JPA. Java Persistence API, es la API de persistencia desarrollada para la plataforma Java EE e La Java Persistence API, a veces referida como JPA, es un framework del lenguaje de programación Java que maneja datos relacionales en aplicaciones usando la Plataforma Java en sus ediciones Standard (Java SE) y Enterprise (Java EE).

Además Hibernate añade algunas anotaciones propias que no están dentro del standard. Es conveniente utilizar las anotaciones del standard siempre que sea posible.

Documentación de Hibernate 3.6

Haciendo un resumen rápido de las anotaciones más utilizadas:

También JPA cuenta con su propio lenguaje de consultas JPQL, que es similar a SQL. La principale ventaja que tiene JPQL es que trabaja con nombre de entidades y de atributos y no con el esquema de base de datos directamente. Además permite navegar mediante las relaciones sin necesidad de hacer incomodos JOIN.

http://en.wikipedia.org/wiki/Java_Persistence_Query_Language

JPA/Hibernate es muy amplio y en este curso solo veremos lo que nos vaya haciendo falta. Nos vamos a centrar más en estudiar la capa de ayuda que pone Play trabajar con los modelos.

extends play.db.jpa.Model

Si tu entidad extiende de la clase play.db.jpa.Model contará con varios métodos que te permitiran hacer el CRUD (Create, Read, Update, Delete) de la entidad. Sin más complicaciones. Sin tener que escribir ni una linea de código más. Nos olvidamos de toda la capa de DAOs que es un patrón común en las aplicaciones Java EE.

Además le añadirá un campo “id” de tipo Long a tu entidad, que será la clave primaria de la tabla. Es una buena práctica por cuestiones de rendimiento que la clave primaria sea de tipo Long, a pesar de que conceptualmente pueda haber otro tipo de clave. Esta otra clave se puede definir como un campo unique, para conservar la restricción.

Métodos que aporta extender de play.db.jpa.Model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Recuperando objetos
Post post = Post.findById(5L);
List<Post> posts = Post.findAll(); List<Post> posts = Post.all().fetch(); List<Post> posts = Post.all().fetch(100); //limit 100 List<Post> posts = Post.all().from(50).fetch(100);

//Búsqueda usando querys simplicados Post.find(“byTitle”, “My first post”).fetch(); Post.find(“byTitleLike”, “%hello%”).fetch(); Post.find(“byAuthorIsNull”).fetch(); Post.find(“byTitleLikeAndAuthor”, “%hello%”, connectedUser).fetch();

//Busquedas utilizando JPQL Post.find( “select p from Post p, Comment c ” + “where c.post = p and c.subject like ?”, “%hop%” );

//Contar objetos long postCount = Post.count(); long userPostCount = Post.count(“author = ?”, connectedUser);

//Crear o editar post.save();

Manejo de transacciones

Play maneja automáticamente las transacciones. Por cada HTTP request crea una nueva petición y realiza el commit cuando envia el HTTP response. En el caso de que el código lance una excepción, la transacción hace rollback automáticamente.

Para forzar un rollback se puede utilizar

JPA.setRollbackOnly()

Si marcamos la transacción como sólo de lectura, mejoraremos el rendimiento del acceso a base de datos. Anotaremos el método de nuestro controlador con:

@play.db.jpa.Transactional(readOnly=true)

Si un método de un controlador o un controlador entero no va a hacer uso de base de datos se le puede indicar a Play que no cree una transacción con el HTTP Request:

@play.db.jpa.NoTransaction 

Configuración de la base de datos

Por ahora no hemos definido qué tipo de base de datos vamos a utilizar. Para ellos editamos el fichero conf/application.conf y busca las lineas

# To quickly set up a development database, use either:
#   - mem : for a transient in memory database (H2 in memory)
#   - fs  : for a simple file written database (H2 file stored)
# db=mem
#
# To connect to a local MySQL5 database, use:
# db=mysql:user:pwd@database_name   

Es necesario descomentar la linea (quitar el #) para decirle a play que nuestra aplicación va a utilizar base de datos.

Tenemos tres opciones:

En este mismo fichero, casi al final, está la linea

%test.db.url=jdbc:h2:mem:play;MODE=MYSQL;LOCK_MODE=0

Que especifica que cuando play arranca en modo test (play test). Utilizará una base de datos en memoria.

Play trae integrado un administrador de base de datos vía web en http://localhost:9000/@db

En el caso de que estemos trabajando con una base de datos MySQL en Windows, recomiendo utilizar HeidiSQL.

Poblando la base de datos para los test

Play incluye la clase Fixtures que permite cargar datos en la base de datos desde un fichero .yml.

Por ejemplo (initial-data.yml)

1
2
3
4
5
6
7
8
User(user1):
   username: user1
   password: user1

Tweet(t1u1): msg: “Tweet 1 de user1” author : user1 date: 2011-01-01

Ejercicio: Trabajando con el modelo

Partiendo del modelo de datos definido anteriormente. El objetivo de este ejercicio es familiarizarse con el uso de las entidades:

Consejos

Solución

Puedes ver y descargarte el código del ejercicio desde https://github.com/axelhzf/play-curso/tree/47d94bec3d04476cce572088bf89dad4342f03e3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityTransaction;

import org.junit.Before; import org.junit.Test;

import junit.framework.Assert; import models.Tweet; import models.User; import play.db.jpa.GenericModel.JPAQuery; import play.db.jpa.JPA; import play.db.jpa.JPABase; import play.test.Fixtures; import play.test.UnitTest;

public class ModelTest extends UnitTest {

<span class="nd">@Before</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setup</span><span class="o">(){</span>
    <span class="n">Fixtures</span><span class="o">.</span><span class="na">deleteDatabase</span><span class="o">();</span>
<span class="o">}</span>

<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">test1</span><span class="o">(){</span>
    <span class="n">User</span> <span class="n">u1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user1"</span><span class="o">,</span> <span class="s">"password1"</span><span class="o">);</span>
    <span class="n">u1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>
    <span class="n">User</span> <span class="n">u2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user2"</span><span class="o">,</span> <span class="s">"password2"</span><span class="o">);</span>
    <span class="n">u2</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>
    <span class="n">User</span> <span class="n">u3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user3"</span><span class="o">,</span> <span class="s">"password3"</span><span class="o">);</span>
    <span class="n">u3</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="kt">long</span> <span class="n">count</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="na">count</span><span class="o">();</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span> <span class="n">count</span><span class="o">);</span>

    <span class="n">User</span> <span class="n">u1Found</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">u1</span><span class="o">.</span><span class="na">id</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertNotNull</span><span class="o">(</span><span class="n">u1Found</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="s">"user1"</span><span class="o">,</span> <span class="n">u1Found</span><span class="o">.</span><span class="na">username</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="s">"password1"</span><span class="o">,</span> <span class="n">u1Found</span><span class="o">.</span><span class="na">password</span><span class="o">);</span>
<span class="o">}</span>

<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">test2</span><span class="o">(){</span>
    <span class="n">User</span> <span class="n">u1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user1"</span><span class="o">,</span> <span class="s">"password1"</span><span class="o">);</span>
    <span class="n">u1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">Tweet</span> <span class="n">t1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"msg1"</span><span class="o">,</span> <span class="n">u1</span><span class="o">);</span>
    <span class="n">t1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">Tweet</span> <span class="n">t2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"msg2"</span><span class="o">,</span> <span class="n">u1</span><span class="o">);</span>
    <span class="n">t2</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">Tweet</span> <span class="n">t3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"msg3"</span><span class="o">,</span> <span class="n">u1</span><span class="o">);</span>
    <span class="n">t3</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="kt">long</span> <span class="n">count</span> <span class="o">=</span> <span class="n">Tweet</span><span class="o">.</span><span class="na">count</span><span class="o">();</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span> <span class="n">count</span><span class="o">);</span>

    <span class="n">Tweet</span> <span class="n">t1Found</span> <span class="o">=</span> <span class="n">Tweet</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">t1</span><span class="o">.</span><span class="na">id</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertNotNull</span><span class="o">(</span><span class="n">t1Found</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="s">"msg1"</span><span class="o">,</span> <span class="n">t1Found</span><span class="o">.</span><span class="na">msg</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="s">"user1"</span><span class="o">,</span> <span class="n">t1Found</span><span class="o">.</span><span class="na">author</span><span class="o">.</span><span class="na">username</span><span class="o">);</span>
<span class="o">}</span>

<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">test3</span><span class="o">(){</span>
    <span class="n">User</span> <span class="n">u1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user1"</span><span class="o">,</span> <span class="s">"password1"</span><span class="o">);</span>
    <span class="n">u1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">u2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user2"</span><span class="o">,</span> <span class="s">"password2"</span><span class="o">);</span>
    <span class="n">u2</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">Tweet</span> <span class="n">t1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"msg1"</span><span class="o">,</span> <span class="n">u1</span><span class="o">);</span>
    <span class="n">t1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">Tweet</span> <span class="n">t2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"msg2"</span><span class="o">,</span> <span class="n">u1</span><span class="o">);</span>
    <span class="n">t2</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">Tweet</span> <span class="n">t3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"msg3"</span><span class="o">,</span> <span class="n">u2</span><span class="o">);</span>
    <span class="n">t3</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="kt">long</span> <span class="n">count</span> <span class="o">=</span> <span class="n">Tweet</span><span class="o">.</span><span class="na">count</span><span class="o">();</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span> <span class="n">count</span><span class="o">);</span>

    <span class="n">List</span><span class="o">&lt;</span><span class="n">Tweet</span><span class="o">&gt;</span> <span class="n">founds</span> <span class="o">=</span> <span class="n">Tweet</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">"byAuthor"</span><span class="o">,</span> <span class="n">u1</span><span class="o">).</span><span class="na">fetch</span><span class="o">();</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertNotNull</span><span class="o">(</span><span class="n">founds</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="n">founds</span><span class="o">.</span><span class="na">size</span><span class="o">());</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">t1</span><span class="o">));</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">t2</span><span class="o">));</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertFalse</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">t3</span><span class="o">));</span>
<span class="o">}</span>

<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">test4</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">ParseException</span><span class="o">{</span>
    <span class="n">SimpleDateFormat</span> <span class="n">formatter</span> <span class="o">=</span> <span class="k">new</span> <span class="n">SimpleDateFormat</span><span class="o">(</span><span class="s">"dd/MM/yyyy"</span><span class="o">);</span>

    <span class="n">Tweet</span> <span class="n">t1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"tweet1"</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
    <span class="n">t1</span><span class="o">.</span><span class="na">date</span> <span class="o">=</span> <span class="n">formatter</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"01/01/2000"</span><span class="o">);</span>
    <span class="n">t1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>
    <span class="n">Tweet</span> <span class="n">t2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"tweet2"</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
    <span class="n">t2</span><span class="o">.</span><span class="na">date</span> <span class="o">=</span> <span class="n">formatter</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"01/02/2000"</span><span class="o">);</span>
    <span class="n">t2</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>
    <span class="n">Tweet</span> <span class="n">t3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Tweet</span><span class="o">(</span><span class="s">"tweet3"</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
    <span class="n">t3</span><span class="o">.</span><span class="na">date</span> <span class="o">=</span> <span class="n">formatter</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"02/01/2010"</span><span class="o">);</span>
    <span class="n">t3</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">List</span><span class="o">&lt;</span><span class="n">Tweet</span><span class="o">&gt;</span> <span class="n">founds</span> <span class="o">=</span> <span class="n">Tweet</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">"byDateGreaterThan"</span><span class="o">,</span> <span class="n">formatter</span><span class="o">.</span><span class="na">parse</span><span class="o">(</span><span class="s">"01/01/2010"</span><span class="o">)).</span><span class="na">fetch</span><span class="o">();</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertNotNull</span><span class="o">(</span><span class="n">founds</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="n">founds</span><span class="o">.</span><span class="na">size</span><span class="o">());</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">t3</span><span class="o">));</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertFalse</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">t1</span><span class="o">));</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertFalse</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">t2</span><span class="o">));</span>
<span class="o">}</span>

<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">test5</span><span class="o">(){</span>
    <span class="n">User</span> <span class="n">u1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"usur1"</span><span class="o">,</span> <span class="s">"password1"</span><span class="o">);</span>
    <span class="n">u1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">u2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user2"</span><span class="o">,</span> <span class="s">"password2"</span><span class="o">);</span>
    <span class="n">u2</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">u3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user3"</span><span class="o">,</span> <span class="s">"password3"</span><span class="o">);</span>
    <span class="n">u3</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">u4</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user4"</span><span class="o">,</span> <span class="s">"password4"</span><span class="o">);</span>
    <span class="n">u4</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">u1</span><span class="o">);</span>
    <span class="n">u4</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">u2</span><span class="o">);</span>
    <span class="n">u4</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">u3</span><span class="o">);</span>
    <span class="n">u4</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">uFound</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">u4</span><span class="o">.</span><span class="na">id</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertNotNull</span><span class="o">(</span><span class="n">uFound</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span> <span class="n">uFound</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">size</span><span class="o">());</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">uFound</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">u1</span><span class="o">));</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">uFound</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">u2</span><span class="o">));</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">uFound</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">u3</span><span class="o">));</span>
<span class="o">}</span>

<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">test6</span><span class="o">(){</span>
    <span class="n">User</span> <span class="n">u1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"usur1"</span><span class="o">,</span> <span class="s">"password1"</span><span class="o">);</span>
    <span class="n">u1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">u2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user2"</span><span class="o">,</span> <span class="s">"password2"</span><span class="o">);</span>
    <span class="n">u2</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">u1</span><span class="o">);</span>
    <span class="n">u2</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">u3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user3"</span><span class="o">,</span> <span class="s">"password3"</span><span class="o">);</span>
    <span class="n">u3</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">u1</span><span class="o">);</span>
    <span class="n">u3</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">u4</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user4"</span><span class="o">,</span> <span class="s">"password4"</span><span class="o">);</span>
    <span class="n">u4</span><span class="o">.</span><span class="na">follows</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">u1</span><span class="o">);</span>
    <span class="n">u4</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>

    <span class="n">List</span><span class="o">&lt;</span><span class="n">User</span><span class="o">&gt;</span> <span class="n">founds</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">"select user from User user where ? member of user.follows"</span><span class="o">,</span><span class="n">u1</span><span class="o">).</span><span class="na">fetch</span><span class="o">();</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertNotNull</span><span class="o">(</span><span class="n">founds</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span> <span class="n">founds</span><span class="o">.</span><span class="na">size</span><span class="o">());</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">u2</span><span class="o">));</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">u3</span><span class="o">));</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertTrue</span><span class="o">(</span><span class="n">founds</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">u4</span><span class="o">));</span>
<span class="o">}</span>

<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">test7</span><span class="o">(){</span>
    <span class="n">Fixtures</span><span class="o">.</span><span class="na">loadModels</span><span class="o">(</span><span class="s">"initial-data.yml"</span><span class="o">);</span>
    <span class="kt">long</span> <span class="n">usersCount</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="na">count</span><span class="o">();</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">4</span><span class="o">,</span> <span class="n">usersCount</span><span class="o">);</span>
    <span class="kt">long</span> <span class="n">tweetsCount</span> <span class="o">=</span> <span class="n">Tweet</span><span class="o">.</span><span class="na">count</span><span class="o">();</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="mi">9</span><span class="o">,</span> <span class="n">tweetsCount</span><span class="o">);</span>
<span class="o">}</span>

<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">test8</span><span class="o">(){</span>
    <span class="n">EntityTransaction</span> <span class="n">tx</span> <span class="o">=</span> <span class="n">JPA</span><span class="o">.</span><span class="na">em</span><span class="o">().</span><span class="na">getTransaction</span><span class="o">();</span>

    <span class="n">User</span> <span class="n">u1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">User</span><span class="o">(</span><span class="s">"user1"</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
    <span class="n">u1</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>
    <span class="n">tx</span><span class="o">.</span><span class="na">commit</span><span class="o">();</span>

    <span class="n">tx</span><span class="o">.</span><span class="na">begin</span><span class="o">();</span>
    <span class="n">User</span> <span class="n">userFound</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">u1</span><span class="o">.</span><span class="na">id</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertNotNull</span><span class="o">(</span><span class="n">userFound</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="s">"user1"</span><span class="o">,</span> <span class="n">userFound</span><span class="o">.</span><span class="na">username</span><span class="o">);</span>

    <span class="n">userFound</span><span class="o">.</span><span class="na">username</span> <span class="o">=</span> <span class="s">"not user1"</span><span class="o">;</span>
    <span class="n">userFound</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>
    <span class="n">tx</span><span class="o">.</span><span class="na">rollback</span><span class="o">();</span>

    <span class="n">tx</span><span class="o">.</span><span class="na">begin</span><span class="o">();</span>
    <span class="n">User</span> <span class="n">userFound2</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">u1</span><span class="o">.</span><span class="na">id</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertNotNull</span><span class="o">(</span><span class="n">userFound2</span><span class="o">);</span>
    <span class="n">Assert</span><span class="o">.</span><span class="na">assertEquals</span><span class="o">(</span><span class="s">"user1"</span><span class="o">,</span> <span class="n">userFound2</span><span class="o">.</span><span class="na">username</span><span class="o">);</span>      
<span class="o">}</span>

}