Tengo un problema con una asociación muchos a muchos en mi capa de persistencia. Mi situación es la siguiente:Hibernate Asociación muchos a muchos: la colección del lado izquierdo contiene elementos, pero la colección del lado derecho está vacía
Un usuario puede tener varios roles y un rol puede tener varios usuarios conectados. Durante las pruebas, encontré un comportamiento extraño. Creé un objeto de rol y varios objetos de usuario. El rol se estableció para cada uno de los usuarios. Después de esto, los usuarios se salvaron usando un DAO. Luego uno de los usuarios se carga para verificar si obtuvo el rol que se le pasó antes de guardar el objeto del usuario. Llamar al getRoles()
en el usuario muestra que el rol se configuró correctamente.
Para comprobar si la dirección inversa también funciona, el objeto de rol se carga de la base de datos utilizando una función DAO. Pero al llamar al getUsers()
en el objeto de la función simplemente devuelve un conjunto vacío, aunque debe contener a todos los usuarios con esta función.
Comprobé dos veces la tabla de la base de datos, pero todo parece estar bien. El usuario, la función y la tabla user_role se completaron correctamente.
¿Por qué el objeto de rol no contiene ningún usuario?
Estoy usando Hibernate y Spring con las siguientes clases.
clase Usuario
@Entity
@Table
public class User extends BusinessObject {
...
// Option 1
@ManyToMany(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
targetEntity=Role.class)
@JoinTable(name= "user_role",
joinColumns = {@JoinColumn(name="user_id")},
inverseJoinColumns = {@JoinColumn(name="role_id")})
// Option 2
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name= "user_role",
joinColumns = {@JoinColumn(name="user_id")},
inverseJoinColumns = {@JoinColumn(name="role_id")})
private Set<Role> roles = new HashSet<Role>();
...
}
clase Rol
@Entity
@Table
public class Role extends BusinessObject {
...
// Option 1
@ManyToMany(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy= "roles",
targetEntity = User.class)
// Option 2
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name= "user_role",
joinColumns = {@JoinColumn(name="role_id")},
inverseJoinColumns = {@JoinColumn(name="user_id")})
private Set<User> users = new HashSet<User>();
...
}
Para probar que estoy usando el siguiente código en una clase de prueba JUnit.
@Test
public void test(){
Transaction trans = sessionFactory.getCurrentSession().beginTransaction();
Role userAdminRole = new Role();
userAdminRole.setName(RoleName.USER_ADMIN);
Role userRole = new Role();
userRole.setName(RoleName.USER);
User user1 = new User();
user1.setEmail("[email protected]");
user1.getRoles().add(userAdminRole);
user1.getRoles().add(userRole);
userDao.save(user1);
User user2 = new User();
user2.setEmail("[email protected]");
user2.getRoles().add(role);
userDao.save(user2);
User user3 = new User();
user3.setEmail("[email protected]");
user3.getRoles().add(role);
userDao.save(user3);
trans.commit();
User loadedUser = userDao.load(user1.getId());
// Tests passes
Assert.assertNotNull(loadedUser);
Assert.assertEquals(user1, loadedUser);
Set<Role> roles = loadedUser.getRoles();
// Tests passes
Assert.assertEquals(2, roles.size());
Role loadedUserAdminRole = roleDao.findByName(RoleName.USER_ADMIN);
Set<User> users = loadedUserAdminRole.getUsers();
// Test fails: Count is 0 instead of 3 !!!!!!!
Assert.assertEquals(3, users.size());
}
ACTUALIZACIÓN
Lo siento, se olvidó de mencionar una cosa. Cuando probé el código, por supuesto, no marqué la asociación de muchos a muchos dos veces en cada archivo de clase. En cambio, utilicé la opción 1 o la opción 2 en cada archivo de clase.
¿Dónde está iniciando y terminando sesiones (o 'EntityManager's en JPA)? Sospecho que si cierras una sesión después del 'save's y comienzas una nueva antes de' load's, las cosas funcionarán, porque extraerá los objetos de la base de datos en vez de la caché de la sesión. –
La sesión se abre durante todo el método de prueba. Llamar a getSession() en uno de los métodos de DAO devuelve siempre el mismo objeto de sesión siempre que se invoquen en un método de prueba. – Flo