I am using Spring Data and @Transactional annotation(for automatic rollback after tests). I have simple bidirectional relation between account and user(owning side):
@Entity
@Table(name = "ACCOUNT_T")
public class AccountEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String email;
private String password;
private String verificationCode;
private Boolean active = false;
@OneToOne(mappedBy = "account", fetch = FetchType.EAGER,
cascade = {CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.DETACH, CascadeType.REFRESH})
private UserEntity user;
}
@Entity
@Table(name = "USER_T")
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String surname;
private String phone;
private LocalDate birthDate;
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
@JoinColumn(name = "account_id")
private AccountEntity account;
}
I am using JpaRepositories and fetching is set to eager. Why sometimes when I get objects from database I can't get their child objects-null is returned. It depends on from which side I add objects. I have written simple test using Junit5:
@ExtendWith(SpringExtension.class)
@SpringBootTest
@Transactional
class UserAndAccountRepositoriesTest {
void testA() {
UserEntity userEntity = new UserEntity();
setUserProperties(userEntity);
AccountEntity accountEntity = new AccountEntity();
setAccountProperties(accountEntity); //just setting values for fields
accountEntity.setUser(userEntity);
accountRepository.save(accountEntity);
accountRepository.findAll().get(0).getUser(); //returns user
userRepository.findAll().get(0).getAccount(); //returns null,but should return account related to that user
}
void testB() {
UserEntity userEntity = new UserEntity();
setUserProperties(userEntity);
AccountEntity accountEntity = new AccountEntity();
setAccountProperties(accountEntity);
accountEntity.setUser(userEntity);
accountRepository.save(accountEntity);
accountRepository.findAll().get(0).getUser(); //again returns null,but shouldn't
userRepository.findAll().get(0).getAccount(); //returns account
}
}
Without @Transactional
everything works fine - I am not getting null.
What am I doing wrong?
You'd need to set both sides of a relationship for explicitly defining it.
Try adding userEntity.setAccount(accountEntity)
during your setup case, this would resolve the issue.
Hibernate won't help you and assume just because you set a -> b
, it would set b <- a
for you within the other entity.
The reason why it might work without @Transactional
is that, without the annotation you are committing your setup data into whatever datasource you are using, and nothing is rollbacked at the end, and since you are selecting data without any id
with findAll
, you are getting previous user/account entites that have already been committed, some with relationship & some without, thus the random error you are getting.