Мое приложение с JPA (Hibernate) и Spring. Мои энититы:
отделение
@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<>();
}
Пользователь
@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;
}
ДАО для отдела:
@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();
}
}
Когда я запускаю код в основном классе, он объединяет сущности:
Главный
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']}]
Когда я запускаю модульный тест с тем же кодом, у отдела есть пустой список пользователей:
@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 = []}]
}
}
Итак, мой вопрос: почему ЖАЖДУЩИЙ работает в Main, а в тесте - нет?
Я создаю пользовательские сущности внутри одной транзакции и пытаюсь получить их внутри другой транзакции? Я правильно вас понял?
Не могли бы вы показать конструктор объекта User?




Я предполагаю, что вы не добавляете нового пользователя в список пользователей в отделе.
Ваш конструктор должен выглядеть так:
public User(
// other fields,
Department department) {
// set all fields.
department.getUsers().add(this);
}
В Main это работает, потому что у вас есть две транзакции, а при чтении это отдельная транзакция, а отдел извлекается из БД.
Но в Unit Test возвращает отдел из памяти, где список пользователей пуст.
Перед сохранением объектов очень важно правильно настроить отношения.
Да, мне помогло. Спасибо! Но еще один вопрос. Создает ли сохранение в БД или чтение из БД в модульных тестах реальные транзакции? Или все манипуляции с данными внутри java памяти?
Если вы используете Transactional в модульном тесте с SpringRunner, он создает транзакцию базы данных и по умолчанию выполняет откат в конце метода тестирования.
Разница заключается в том, что ваш модульный тест выполняется внутри транзакции.