Hello there. I have a many to many relationship that is as follows: MotionPicture → MotionPictureEmployee → Employee. I have all the relationship fields set to lazily loaded.
My goal is to use NamedEntityGraph annotations to choose when the relationship field in MotionPicture should be loaded eagerly.
@Entity
@Table(name = "motion_pictures")
@NamedEntityGraph(name = "motion_picture.employees", attributeNodes = @NamedAttributeNode("employees"))
public class MotionPicture {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
...
...
...
@OneToMany(
mappedBy = "motionPicture",
orphanRemoval = true,
fetch = FetchType.LAZY
)
List<MotionPictureEmployee> employees = new ArrayList<>();
Using the NamedEntityGraph…
Session session = sessionFactory.openSession();
SelectionQuery<MotionPicture> motionPictureQuery = session.createSelectionQuery("select m from MotionPicture m where m.originalTitle = :motionPictureOriginalTitle"
+ " and m.releaseDate = :releaseDate", MotionPicture.class).setParameter("motionPictureOriginalTitle", title)
.setParameter("releaseDate", releaseDate);
if (getEmployees) {
motionPictureQuery.setHint("jakarta.persistence.fetchgraph", session.getEntityGraph("motion_picture.employees"));
}
MotionPicture motionPicture = motionPictureQuery.getSingleResultOrNull();
session.close();
Note that session is closed. In my test I get this result:
MotionPicture alien = this.motionPictureService.getMotionPicture("Alien", LocalDate.of(1979, 6, 22), true);
// we expect the employees to not be present because they are lazily loaded and we didn't ask for them
assertTrue(Hibernate.isInitialized(alien.getEmployees()));
assertTrue(Hibernate.isInitialized(alien.getEmployees().getFirst()));
assertTrue(Hibernate.isInitialized(alien.getEmployees().getFirst().getMotionPicture().getEmployees()
.getFirst().getMotionPicture().getEmployees()
.getLast().getMotionPicture().getEmployees()
.getFirst().getMotionPicture().getEmployees()));
Why are the relationships getting recursively set, motionPicture ->motionPictureEmployees->motionPicture->motionPictureEmployees?
This doesn’t happen when going from motionPicture->motionPictureEmployees->employee. Obviously the difference here being that Employee doesn’t have a namedEntityGraph like motionPicture.
For reference:
MotionPictureEmployee class, which represents the “junction” table in my database.
@Entity
@Table(name = "motion_pictures_employees")
public class MotionPictureEmployee {
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "motion_picture_id")
private MotionPicture motionPicture;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "employee_id")
private Employee employee;
public MotionPictureEmployee() {
}
Employee
@Entity
@Table(name = "employees")
@NamedEntityGraph(name = "employee.motionPictures", attributeNodes = @NamedAttributeNode("motionPictures"))
public class Employee {
@Column(name = "birth_date")
private LocalDate birthDate;
@Column(name = "country_of_origin")
private String countryOfOrigin;
@Column(name = "date_of_death")
private LocalDate dateOfDeath;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "img_location")
private String imgLocation;
private String name;
private String overview;
@Column(name = "popularity_ranking")
private Integer popularityRanking;
@OneToMany(
mappedBy = "employee",
orphanRemoval = true,
fetch = FetchType.LAZY
)
List<MotionPictureEmployee> motionPictures = new ArrayList<>();