I have three entity classes: 1. Theatre, 2. Screen, and 3. SeatCategory. The Theatre class has a one-to-many bidirectional mapping with the Screen class, and the Screen class has a one-to-many bidirectional mapping with the SeatCategory class.
When I try to create a Theatre, I am using a DTO that contains information for all three classes. First, I create a Theatre instance, and then I create a list of Screens and SeatCategories respectively.
The problem arises when I try to set the Theatre in the Screen entity object or the Screen in the SeatCategory entity object; I get a stack overflow error. As a result, I do not set these, causing the Theatre ID column in the Screen table to be null in the database.
Please help me solve this issue. Here is a simplified version of my code:
Theatre entity
@Entity
@Table(name = "theatres")
public class Theatre {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String theatreId;
private String name;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,mappedBy = "theatre")
Set<Screen> screens = new HashSet<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,mappedBy = "theatre")
Set<Show> shows = new HashSet<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,mappedBy = "theatre")
Set<Movie> movies = new HashSet<>();
@ManyToOne
@JoinColumn(name = "location_id")
Location location;
@JsonIgnore
@ManyToOne
@JoinColumn(name="user_id")
User user;
}
Screeen Entity
@Entity
@Table(name = "screens")
public class Screen {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String screenId;
private String name;
@ManyToOne
@JoinColumn(name = "theatre_id")
Theatre theatre;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,mappedBy = "screen")
Set<SeatCategory> seatCategories = new HashSet<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY,mappedBy = "screen")
Set<Seat> seats = new HashSet<>();
}
SeatCategory
@Entity
@Table(name = "seat_category")
public class SeatCategory {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String seatCategoryId;
private String name;
private int capacity;
private int price;
@ManyToOne
@JoinColumn(name = "screen_id")
Screen screen;
}
Service Method
public ResponseEntity<Theatre> createTheatre(CreateTheatreDTO createTheatreDTO,String userName){
Optional<User> user = userRepository.findByUserName(userName);
User userObj=null;
if(user.isPresent()){
userObj=user.get();
}else {
throw new UsernameNotFoundException("User not found");
}
Theatre theatre = Theatre.builder()
.name(createTheatreDTO.getName())
.build();
Set<Screen> screens = createTheatreDTO.getScreens().stream()
.map(screenDTO -> {
Screen screen = new Screen();
screen.setName(screenDTO.getName());
//screen.setTheatre(theatre);
Set<SeatCategory> seatCategories = screenDTO.getSeatCategories().stream()
.map(seatCategoryDTO -> {
SeatCategory seatCategory = new SeatCategory();
seatCategory.setName(seatCategoryDTO.getName());
seatCategory.setCapacity(seatCategoryDTO.getCapacity());
seatCategory.setPrice(seatCategoryDTO.getPrice());
//seatCategory.setScreen(screen);
return seatCategory;
}).collect(Collectors.toSet());
screen.setSeatCategories(seatCategories);
return screen;
}).collect(Collectors.toSet());
theatre.setScreens(screens);
theatre.setUser(userObj);
theatreRepository.save(theatre);
return ResponseEntity.ok().body(theatre);
}
In the above code, if I do not comment out screen.setTheatre(theatre)
or seatCategory.setScreen(screen)
, I get a StackOverflowError.
java.lang.StackOverflowError: null
Otherwise, I get the following response for the below request
Request
{
"name": "Test Theatre1234",
"screens": [
{
"name": "Screen 1",
"seatCategories": [
{
"name": "VIP",
"capacity": 50,
"price": 100
},
{
"name": "Standard",
"capacity": 100,
"price": 50
}
]
},
{
"name": "Screen 2",
"seatCategories": [
{
"name": "Premium",
"capacity": 60,
"price": 80
},
{
"name": "Regular",
"capacity": 120,
"price": 40
}
]
}
]
}
Response
{
"theatreId": "18f20c7a-4126-4d54-bb2e-fcecd0eeca2f",
"name": "Test Theatre1234",
"screens": [
{
"screenId": "0df03616-63a0-4ca1-ba73-d456b9056c24",
"name": "Screen 1",
"theatre": null,
"seatCategories": [
{
"seatCategoryId": "13d5f037-11a2-4b88-8b3a-63e455c5761c",
"name": "Standard",
"capacity": 100,
"price": 50,
"screen": null
},
{
"seatCategoryId": "766ce71b-7652-49c4-80b0-02c25030f4af",
"name": "VIP",
"capacity": 50,
"price": 100,
"screen": null
}
],
"seats": []
},
{
"screenId": "a3effae5-ae05-4666-8394-1e014a87b60f",
"name": "Screen 2",
"theatre": null,
"seatCategories": [
{
"seatCategoryId": "afbec81a-207e-4460-84ca-6b52be8ece61",
"name": "Premium",
"capacity": 60,
"price": 80,
"screen": null
},
{
"seatCategoryId": "9d61bd81-1584-4687-ba0c-2e26ac59ab05",
"name": "Regular",
"capacity": 120,
"price": 40,
"screen": null
}
],
"seats": []
}
],
"shows": null,
"movies": null,
"location": null
}
The theatre and screen fields are null, which is preventing me from achieving the bidirectional relationship that I am trying to establish.
enter image description here