【问题标题】:When does hibernate load mapped relationshibernate什么时候加载映射关系
【发布时间】:2018-05-07 14:20:03
【问题描述】:

我正在创建一个 Spring Boot 应用程序并使用它在JpaRepository 接口中构建来存储我的实体。我有以下两个实体(为了便于阅读,删除了 getter 和 setter):

个人资料实体

@Entity
public class Profile {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @OneToMany(mappedBy = "profileOne", orphanRemoval = true)
    private List<Match> matchOnes;

    @OneToMany(mappedBy = "profileTwo", orphanRemoval = true)
    private List<Match> matchTwos;
}

匹配实体

@Entity
@Table(uniqueConstraints={
    @UniqueConstraint(columnNames = { "profileOne_id", "profileTwo_id" })
}) 
public class Match {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @ManyToOne
    @JoinColumn(name = "profileOne_id")
    private Profile profileOne;

    @ManyToOne
    @JoinColumn(name = "profileTwo_id")
    private Profile profileTwo;
}

为了理解JpaRepository 的行为,我编写了以下单元测试。

@RunWith(SpringRunner.class)
@DataJpaTest
public class IProfileDaoTest {

    @Autowired
    private IProfileDao profileDao; //This class extends JpaRepository<Profile, long>

    @Autowired
    private IMatchDao matchDao; //This class extends JpaRepository<Match, long>

    @Test
    public void saveProfileTest() throws Exception {

    @Test
    public void profileMatchRelationTest() throws Exception {
        //Test if matches stored by the IMatchDao are retrievable from the IProfileDao
        Profile profileOne = new Profile("Bob"),
            profileTwo = new Profile("Alex");
        profileDao.saveAndFlush(profileOne);
        profileDao.saveAndFlush(profileTwo);
        matchDao.saveAndFlush(new Match(profileOne, profileTwo));
        profileOne = profileDao.getOne(profileOne.getId());
        Assert.assertEquals("Match not retrievable by profile.", 1, profileOne.getMatchOnes().size());
    }
}

现在我预计匹配项会出现在配置文件实体中,但事实并非如此。我还尝试将CascadeType.ALL 添加到匹配实体中的@ManyToOne 注释,并将FetchType.EAGER 添加到配置文件实体中的@OneToMany 注释。

是否可以通过在 profileDao 中请求配置文件来获取 matchDao 保存的匹配项?或者我应该找到具有单独功能的配置文件的匹配项?

【问题讨论】:

  • 您是否尝试过(在您的测试中)在执行 getOne 之前保留匹配和更新的配置文件?
  • JpaRepository 没有持久化方法。相反,您可以致电 saveAndFlush()flush() 来保存您的更改。在这种情况下,我使用saveAndFlush() 来确保存储所有实体。
  • 坚持我的意思是执行 saveAndFlush,对不起。

标签: java jpa spring-data-jpa


【解决方案1】:

出于性能(可能还有其他)原因,Spring Data 存储库不会立即写入数据库。在测试中,如果你需要测试查询方法,你需要使用@DataJpaTest提供的TestEntityManager(它只是存储库在后台使用的实体管理器,但有一些方便的测试方法)。

更新 1: 匹配项不会添加到配置文件中。为确保关系是双向的,匹配项应具有配置文件,但配置文件也应具有匹配项。

试试这个:

@RunWith(SpringRunner.class)
@DataJpaTest
public class IProfileDaoTest {

    @Autowired
    private IProfileDao profileDao; //This class extends JpaRepository<Profile, long>

    @Autowired
    private IMatchDao matchDao; //This class extends JpaRepository<Match, long>

    @Autowired
    private TestEntityManager testEntityManager;

    @Test
    public void saveProfileTest() throws Exception {

    @Test
    public void profileMatchRelationTest() throws Exception {
        //Test if matches stored by the IMatchDao are retrievable from the IProfileDao
        Profile profileOne = new Profile("Bob"),
            profileTwo = new Profile("Alex");

        //Persist the profiles so they exist when they are added to the match
        entityManager.persistAndFlush(profileOne);
        entityManager.persistAndFlush(profileTwo);

        //Create and persist the match with two profiles
        Match yourMatch = entityManager.persistFlushFind(new Match(profileOne, profileTwo));

        //Add the match to both profiles and persist them again.
        profileOne.matchOnes.add(yourMatch);
        entityManager.persistAndFlush(profileOne);
        profileTwo.matchTwos.add(yourMatch);
        entityManager.persistAndFlush(profileTwo);

        profileOne = profileDao.getOne(profileOne.getId());
        Assert.assertEquals("Match not retrievable by profile.", 1, profileOne.getMatchOnes().size());
    }
}

【讨论】:

  • 感谢您关注TestEntitymanager。然而,这并不能解决问题。检索配置文件后,它仍然没有匹配项。
  • 你没有给配置文件匹配。将新的 Match 实例添加到您的配置文件实例中的 Match(es) 列表中
  • 您的权利。将匹配项添加到配置文件解决了我的问题。我建议对您的答案进行修改,以便我可以接受。
  • @MaikoKingma 我看不到您建议的编辑,但我还是修复了答案。现在测试应该可以按预期进行
【解决方案2】:

测试中的所有内容都发生在同一个 JPA 会话中。这样的会话保证每个实体只包含一次。所以当你执行

profileOne = profileDao.getOne(profileOne.getId());

您将获得您在上面创建的 5 行的确切实例。 Hibernate 或任何其他 JPA 实现都会更改实体中的任何内容以进行加载。

如果您想真正重新加载一个实体,您必须先将其从实体管理器中逐出,或者使用新的Session/EntityManager

有关更多详细信息,请参阅 JPA 规范的第 3 章。

【讨论】:

    猜你喜欢
    • 2019-08-07
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 2020-01-16
    • 2020-10-11
    • 2020-12-04
    • 2013-05-26
    • 1970-01-01
    相关资源
    最近更新 更多