与 Spring Data 双向关系的 @Transactional 返回 null [英] @Transactional in bidirectional relation with Spring Data returns null

查看:29
本文介绍了与 Spring Data 双向关系的 @Transactional 返回 null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Spring Data 和 @Transactional 注释(用于测试后的自动回滚).我在帐户和用户(拥有方)之间有简单的双向关系:

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

我正在使用 JpaRepositories 并且获取设置为eager.为什么有时当我从数据库中获取对象时我无法获取他们的孩子返回objects-null.这取决于我从哪一边添加对象.我使用 Junit5 编写了简单的测试:

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

没有 @Transactional 一切正常 - 我没有得到 null.我做错了什么?

Without @Transactional everything works fine - I am not getting null. What am I doing wrong?

推荐答案

您需要设置关系的双方以明确定义它.尝试在您的设置案例中添加 userEntity.setAccount(accountEntity),这将解决问题.

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 不会帮助你并且仅​​仅因为你设置了 a ->b,它会在另一个实体中为你设置 b <- a.

Hibernate won't help you and assume just because you set a -> b, it would set b <- a for you within the other entity.

它在没有 @Transactional 的情况下可能工作的原因是,如果没有注释,您将设置数据提交到您正在使用的任何数据源中,并且最后没有任何回滚,并且因为您是使用 findAll 选择没有任何 id 的数据,您将获得之前已经提交的用户/帐户实体,其中一些与 &有些没有,因此你得到的随机错误.

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.

这篇关于与 Spring Data 双向关系的 @Transactional 返回 null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆