@Transactional в двунаправленной связи с Spring Data возвращает ноль - PullRequest
0 голосов
/ 02 ноября 2018

Я использую Spring Data и аннотацию @Transactional (для автоматического отката после тестов). У меня есть простая двунаправленная связь между учетной записью и пользователем (владеющая сторона):

@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;
}

Я использую JpaRepositories, и выборка настроена на нетерпение. Почему иногда, когда я получаю объекты из базы данных, я не могу получить их ребенка Нулевой объект возвращается. Это зависит от того, с какой стороны я добавляю объекты. Я написал простой тест с использованием 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
    }
}

Без @Transactional все работает нормально - я не получаю нулевое значение. Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Это потому, что вы не устанавливаете учетную запись в userEntity. Пожалуйста, попробуйте как следует:

userEntity.setAccount(accountEntity);
0 голосов
/ 02 ноября 2018

Вам нужно установить обе стороны отношения для его явного определения. Попробуйте добавить userEntity.setAccount(accountEntity) во время настройки, это решит проблему.

Hibernate вам не поможет, и предположим, что если вы установите a -> b, он установит b <- a для вас в другой сущности.

Причина, по которой он может работать без @Transactional, заключается в том, что без аннотации вы фиксируете свои установочные данные в любом источнике данных, который вы используете, и в конце ничего не откатывается, и поскольку вы выбираете данные без каких-либо id при findAll вы получаете предыдущие пользовательские / учетные записи, которые уже были зафиксированы, некоторые с отношениями, а некоторые без, таким образом, вы получаете случайную ошибку.

...