Hi folks. I am attempting to create a many to many relationship in Hibernate. The model is as follows:
Movie - MovieEmployee - Employee
Movie, movieEmployee, and employee are all tables in my database, where movieEmployee serves as the “join” table. I’m running tests for retrievals of some data that I manually inserted into my database (my “seed” data);
This is how I’m querying for a particular move in my database:
Movie returnedMovie = session.createSelectionQuery("select m from Movie m where m.moviePrimaryKey.originalTitle = :movie", Movie.class)
.setParameter("movie", "Alien 3")
.getSingleResultOrNull();
The associations are lazyily loaded, and when I’m debugger mode I notice that when I look at my
returnedMovie
variable and dig into the associated entity “employees” (MovieEmployee entity) I’ll notice that I can recursively keep going from MovieEmployee to Employee to MovieEmployee to Movie to MovieEmployee to Employee etc. How do I stop this from happening? When I create additional tests I want to control how many “levels” the queries retrieve. For example I’d like to only return the Movie, and MovieEmployees and stop there. I don’t want to see the entire Employe entity in MovieEmployees.
@Entity
@Table(name = "movies")
public class Movie {
@EmbeddedId
private MoviePrimaryKey moviePrimaryKey;
@Column(name = "alternative_title")
private String alternativeTitle;
@Column(name = "motion_picture_rating")
private String motionPictureRating;
@Column(name = "motion_picture_rating_desc")
private String motionPictureRatingDesc;
@Column(name = "running_time")
private Integer runningTime;
private String synopsis;
private String hook;
private String themes;
private Integer budget;
@Column(name = "box_office")
private Integer boxOffice;
private Double score;
@Column(name = "img_location")
private String imgLocation;
@OneToMany(
mappedBy = "movie",
orphanRemoval = true
)
List<MovieEmployee> employees = new ArrayList<>();
public Movie() {
}
/** constructors and getter/setters omitted for brevity **/
public void addEmployee(Employee employee, String jobPosition, String role) {
MovieEmployee movieEmployee = new MovieEmployee(this, employee, jobPosition, role);
employees.add(movieEmployee);
employee.getMovieEmployees().add(movieEmployee);
}
public void removeEmployee(Employee employee) {
MovieEmployee movieEmployee = new MovieEmployee(this, employee);
employees.remove(movieEmployee);
employee.getMovieEmployees().remove(movieEmployee);
movieEmployee.setEmployee(null);
movieEmployee.setMovie(null);
}
// Movie composite key class
@Embeddable
public class MoviePrimaryKey implements Serializable {
private static final long serialVersionUID = -1333454840943927255L;
@Column(name = "original_title")
private String originalTitle;
@Column(name = "release_date")
private LocalDate releaseDate;
Join/reference entity
@Entity
@Table(name = "movies_employees")
public class MovieEmployee {
@Id
@ManyToOne
private Movie movie;
@Id
@ManyToOne
private Employee employee;
@Column(name = "job_position")
private String jobPosition;
private String role;
public MovieEmployee() {
}
Employee entity
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="employeePrimaryKey")
@Table(name = "employees")
public class Employee {
@EmbeddedId
private EmployeePrimaryKey employeePrimaryKey;
@Column(name = "birth_date")
private LocalDate birthDate;
@Column(name = "country_of_origin")
private String countryOfOrigin;
private String synopsis;
@Column(name = "popularity_ranking")
private Integer popularityRanking;
@Column(name = "img_location")
private String imgLocation;
@OneToMany(
mappedBy = "employee",
orphanRemoval = true,
cascade = CascadeType.ALL
)
List<MovieEmployee> movieEmployees = new ArrayList<>();
@Embeddable
public class EmployeePrimaryKey implements Serializable {
private static final long serialVersionUID = 367980327517397257L;
@Column
private String name;
@Column(name = "identical_name_id")
private int identicalNameId;
public EmployeePrimaryKey() {
}