I have the following two entities:
class Role {
@Id Long id;
@Column String email;
String role;
@ManyToOne User user;
}
class User {
@Id Long id;
@Column(unique=true) String email;
String password;
@OneToMany(mappedBy = "user")
@OrderBy("role asc")
List<Role> roles;
}
The SQL is:
CREATE TABLE USER (
ID BIGINT NOT NULL,
EMAIL VARCHAR(255) UNIQUE,
PASSWORD VARCHAR(255),
PRIMARY KEY (ID)
)
CREATE TABLE ROLE (
ID BIGINT NOT NULL,
EMAIL VARCHAR(255),
ROLE VARCHAR(255),
USER_ID BIGINT,
PRIMARY KEY (ID),
FOREIGN KEY (USER_ID) REFERENCES USER(ID)
)
The following JUnit fails on the second last line. I get the user (the parent) automatically loaded from the child, but I don’t get the children automatically loaded from the parent. What have I done wrong?
Role r = em.createQuery("select r from Role r where r.email = :email", Role.class)
.setParameter("email", "john@google.com")
.getSingleResult();
assertEquals("registered", r.role());
assertEquals("john@google.com", r.user().email());
User u = em.createQuery("select u from User u where u.email = :email", User.class)
.setParameter("email", "john@google.com")
.getSingleResult();
assertEquals("john@google.com", u.email());
assertEquals("asdf", u.password());
assertEquals(1, u.roles().size()); FAILS HERE!!!
assertEquals("registered", u.roles().get(0).role());
I’m using EclipseLink 2.3.2 (JPA)
There’s multiple ways in which you can tell how the other and of a relation should be loaded. One is at the query level, using fetch join, something like this:
The other is at the relation declaration level, something like this:
The reason why when you load a Role you also get the user without any special annotation or join in your query is that ManyToOne relations in JPA have fetch=EAGER by default:
http://docs.oracle.com/javaee/5/api/javax/persistence/ManyToOne.html#fetch()
while one to many have fetch=lazy by default:
http://docs.oracle.com/javaee/5/api/javax/persistence/OneToMany.html#fetch()