I am quite new to Spring boot in general and I am trying to create an REST API application. I have ran into this problem. When I try to post an entity that references another via the foreign key I get this error message:
"messsage": "org.hibernate.TransientPropertyValueException:
object references an unsaved transient instance - save the transient instance before flushing :
com.internationalairport.airportmanagementsystem.entities.BoardingPass.ticket ->
com.internationalairport.airportmanagementsystem.entities.Ticket"
I have two entities that share a one to one relation ship. Here’s is the first entity SQL table tickets
structure:
CREATE TABLE IF NOT EXISTS tickets (
ticket_id INT AUTO_INCREMENT PRIMARY KEY,
flight_id INT,
passenger_id INT,
seat_number VARCHAR(6),
class VARCHAR(15),
price DECIMAL(10, 2),
FOREIGN KEY (flight_id) REFERENCES flights(flight_id),
FOREIGN KEY (passenger_id) REFERENCES passengers(passenger_id)
);
Here is the structure for the other table boarding_passes
that references the flights
table:
CREATE TABLE IF NOT EXISTS boarding_passes (
boarding_pass_id INT AUTO_INCREMENT PRIMARY KEY,
ticket_id INT,
gate VARCHAR(10),
boarding_time DATETIME NOT NULL,
FOREIGN KEY (ticket_id) REFERENCES tickets(ticket_id)
);
Here is the ticket
JPA entity (some methods and fields have not been added for brevity sake.
@Entity
@Table(name = "tickets")
public class Ticket {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ticket_id")
private Integer ticketId;
//Other fields and methods not added for brevity
@OneToOne(mappedBy = "ticket", cascade = CascadeType.ALL)
@JsonManagedReference
private BoardingPass boardingPass;
Here is the Boarding Pass
entity:
@Entity
@Table(name = "boarding_passes")
public class BoardingPass {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "boarding_pass_id")
private Integer boardingPassId;
//Other fields and methods not added for brevity
@OneToOne
@JoinColumn(name = "ticket_id")
@JsonBackReference
private Ticket ticket;
Now I am going to explain the process that my application follows to post a Boarding Pass
record. I am making use of DTOs. So I send an HTTP POST request via postman that has this body content: (The ticked has been previously created I don’t need to create it again)
{
"ticketId" : 1,
"gate" : "3B",
"boardingTime" : "2024-01-01T12:52:11"
}
I handle the POST Request in this endpoint:
@PostMapping("/boarding_passes")
public BoardingPass addBoardingPass(@RequestBody PostBoardingPassDto postBoardingPassDto){
return boardingPassService.save(postBoardingPassDto);
}
Here is the post Boarding Pass Dto:
public record PostBoardingPassDto(
Integer tickedId,
String gate,
LocalDateTime boardingTime
) {
}
Here is the service method that is supposed to save this entity using the default JPARepository method save()
:
@Override
public BoardingPass save(PostBoardingPassDto postBoardingPassDto) {
BoardingPass boardingPass = boardingPassMapper.toBoardingPass(postBoardingPassDto);
return boardingPassRepository.save(boardingPass);
}
The boardingPassMapper
transforms a DTO to an Entity it is implemented like this:
@Service
public class BoardingPassMapper {
public BoardingPass toBoardingPass(PostBoardingPassDto postBoardingPass){
BoardingPass boardingPass = new BoardingPass(
postBoardingPass.gate(),
postBoardingPass.boardingTime()
);
Ticket ticket = new Ticket();
ticket.setTicketId(postBoardingPass.tickedId());
boardingPass.setTicket(ticket);
return boardingPass;
}
}
So I have used the same approach in @ManyToOne
entities but I haven’t had any problems. However, here I am missing something. So I’m trying to insert a boarding pass which has a foreign key of an already existing Ticket
. So then that ticket will have a boarding pass object in it. I don’t need to create a new ticket when I make a POST request(hence why I don’t have a Cascade.ALL
type in the Boarding Pass entity. Here is a full screenshot:
So if anybody could help me out I would really appreciate it. I’ve been stuck for a long time. Any form of suggestion helps.