Reputation: 939
I am creating a spring boot application and use it's build in JpaRepository
interface to store my entities. I have the following two entities (removed getters and setters for readability):
@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;
}
To understand the JpaRepository
behavior I wrote the following unit test.
@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());
}
}
Now I expected the matches to have appeared in the profile entity but they do not. I also tried adding CascadeType.ALL
to the @ManyToOne
annotation in the match entity and adding FetchType.EAGER
to the @OneToMany
annotation in the profile entity.
Is it possible to get the matches saved with the matchDao by requesting a profile in the profileDao? Or should I find the matches with a profile with a separate function?
Upvotes: 0
Views: 71
Reputation: 5748
Spring Data repositories don't write to the database immediately for performance (and probably other) reasons. In tests, if you need to test query methods you need to use the TestEntityManager provided by @DataJpaTest
(it's just the entity manager that the repositories use anyway in the background, but with a few convenience methods for testing).
Update 1: The matches aren't added to the profile. To make sure the relationship is bidirectional the matches should have the profiles but the profiles should also have the matches.
Try this:
@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());
}
}
Upvotes: 1
Reputation: 81970
Everything in your test happens in the same JPA session. Such a session guarantees that every entity is included only once. So when you execute
profileOne = profileDao.getOne(profileOne.getId());
you are getting the exact instance back you created 5 lines above. Hibernate nor any other JPA implementation will change anything in the entity for loading.
If you want to actually reload an entity you'll have to either evict it first from the entity manager or use a fresh Session
/EntityManager
.
For more details see chapter 3 of the JPA specification.
Upvotes: 0