My application with JPA (Hibernate) and Spring. My enitites are:
Department
@Entity
@Table(schema = "myschema")
public class Department {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Column(columnDefinition = "BINARY(16)", length = 16 )
private UUID uuid;
@Column(name = "name", length = 200, nullable = false)
private String name;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
List<User> users = new ArrayList<>();
}
User
@Entity
@Table(schema = "myschema")
public class User {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
@Column(columnDefinition = "BINARY(16)", length = 16 )
private UUID uuid;
@NotNull
@Column(name = "login", length = 100, nullable = false)
private String login;
@ManyToOne
@JoinColumn(name = "department_fk", nullable = false)
private Department department;
}
DAO for Department:
@Repository("departmentDao")
public class DepartmentDao {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public UUID save(Department entity) {
log.info("Department entity will be persisted", entity);
entityManager.persist(entity);
return entity.getUuid();
}
@Transactional
public List<Department> getAllWithUsers() {
log.info("Select all departments");
CriteriaQuery<Department> criteria = entityManager.getCriteriaBuilder().createQuery(Department.class);
Root<Department> root = criteria.from(Department.class);
criteria.select(root);
return entityManager.createQuery(criteria).getResultList();
}
}
Whan I run the code in Main class it joins the entities:
Main
ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
DepartmentDao departmentDao = (DepartmentDao) context.getBean("departmentDao");
Department newDep = new Department("WebDepartment", new Date());
departmentDao.save(newDep);
User newUser1 = new User("Test1", newDep);
User newUser2 = new User("Test2", newDep);
userDao.save(newUser1);
userDao.save(newUser2);
List<Department> deps = departmentDao.getAllWithUsers();
//deps
//[Department{name='WebDepartment', users = ['Test1', 'Test2']}]
Whan I run a unit test with the same code, the department has empty list of users:
@ContextConfiguration(locations = "classpath:META-INF/spring-test.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class DaoTests {
@Autowired
private DepartmentDao departmentDao;
@Autowired
private UserDao userDao;
@Test
@Transactional
public void daoTests() throws NoSuchAlgorithmException {
Department newDep = new Department("WebDepartment", new Date());
departmentDao.save(newDep);
User newUser1 = new User("Test1", newDep);
User newUser2 = new User("Test2", newDep);
userDao.save(newUser1);
userDao.save(newUser2);
List<Department> deps = departmentDao.getAllWithUsers();
//deps
//[Department{name='WebDepartment', users = []}]
}
}
So, my question is: why EAGER works in Main, but in test it doesn't?
I assume that you are not adding the new User to the list of users in the Department.
Your constructor must look like:
public User(
// other fields,
Department department) {
// set all fields.
department.getUsers().add(this);
}
In the Main it's working because you have two transactions and in the reading is in a separate transaction and the Department is fetched from DB.
But in the Unit Test it returns the Department from the memory where the users list is empty.
It's very important to keep your relationships set correctly before saving entities.