Modelo
Una representación del módelo de nuestro twitter simple podría ser la siguiente.
- Entidad User, con username y password.
- Entidad Tweet, con el contenido del tweet msg y la fecha de publicación date.
- Todos los Tweets tienen un autor de tipo User. Un mismo Usuario puede ser autorde múltiples Tweets.
- Un Usuario puede seguir a muchos Usuarios y un Usuario puede ser seguido por muchos Usuarios.
Traduciendo el diagrama a código quedaría:
app/models/User.java
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 { }
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;
<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"><</span><span class="n">User</span><span class="o">></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"><</span><span class="n">User</span><span class="o">>();</span>
<span class="o">}</span>
app/models/Tweet.java
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import play.db.jpa.Model; @Entity
public class Tweet extends 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
package models;
<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:
- @Entity - Marca una clase como entidad (Tendrá un mapeo en base de datos)
- Relaciones
- @OneToOne -
- @OneToMany -
- @ManyToMany -
- @ManyToMany -
- @Column - Permite especificar atributos de las columnas de la tabla.
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
//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();
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);
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
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:
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:
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:
- mem - Para crear una base de datos en memoria. Cada vez que reiniciemos la aplicación se borraran los datos que tengamos almacenados.
- fs - Para crear una base de datos en fichero.
- mysql - Para utilizar una base de datos MySQL.
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)
Tweet(t1u1):
msg: “Tweet 1 de user1”
author : user1
date: 2011-01-01
1
2
3
4
5
6
7
8
User(user1):
username: user1
password: user1
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:
- Crear un test (test1) que añada varios usuarios a la base de datos y que posteriormente comprueba que están todos añadidos y que busque un usuario por su id, y que compruebe que los datos son correctos.
- Crear un test (test2) que añada varios tweets a la base de datos y que posteriormente compruebe que están todos añadidos a la base de datos. No te olvides de añadir la relación con el autor. Realiza también una consulta buscando un tweet por su id.
- Crear un test (test3) que cree varios tweets de varios autores y que luego haga una consulta contando los tweets de un usuario en concreto.
- Crear un test (test4) que añada varios tweets con diferentes fechas. Luego haga una consulta contando los tweets que son anteriores a una fecha concreta.
- Crear un test (test5) que cree varios usuarios y que se sigan entre si. Contar cuantos usuarios sigue a uno en concreto.
- Crear un test (test6) que cree varios usuarios y que se sigan entre si. Contar cuantos usuarios siguen a uno en concreto.
- Crear un test (test7) que utilizando la clase Fixtures, pueble la base de datos a partir de un fichero .yml y que realice alguna comprobación, para asegurarnos que se ha leído desde fichero correctamente.
- Crea un test (test8) que cree un usuario en base de datos. Modifique algunos datos y haga un Rollback. Consulta la base de datos para comprobar que los datos del usuario están en el estado original.
Consejos
- Busca información de la anotación @Before de JUnit
- Consulta la documentación de la clase Fixtures
- No olvides extender de la clase UnitTest
- No olvides anotar tus métodos con @Test
- Puedes utilizar este fichero para poblar la base de datos
Solución
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 { }
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;
<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"><</span><span class="n">Tweet</span><span class="o">></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"><</span><span class="n">Tweet</span><span class="o">></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"><</span><span class="n">User</span><span class="o">></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>