我对 Spring boot 总体来说还很陌生,我正在尝试创建一个 REST API 应用程序。我遇到了这个问题。当我尝试发布通过外键引用另一个实体时,我收到此错误消息:
"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"
我有两个共享一对一关系的实体。这是第一个实体 SQL 表
tickets
结构:
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)
);
这是引用
boarding_passes
表的另一个表 flights
的结构:
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)
);
这是
ticket
JPA 实体(为了简洁起见,尚未添加一些方法和字段。
@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;
这是
Boarding Pass
实体:
@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;
现在我将解释我的申请发布
Boarding Pass
记录的流程。我正在使用 DTO。因此,我通过邮递员发送一个具有以下正文内容的 HTTP POST 请求:(勾选的内容之前已创建,我不需要再次创建)
{
"ticketId" : 1,
"gate" : "3B",
"boardingTime" : "2024-01-01T12:52:11"
}
我在此端点处理 POST 请求:
@PostMapping("/boarding_passes")
public BoardingPass addBoardingPass(@RequestBody PostBoardingPassDto postBoardingPassDto){
return boardingPassService.save(postBoardingPassDto);
}
这是邮寄的登机牌 Dto:
public record PostBoardingPassDto(
Integer tickedId,
String gate,
LocalDateTime boardingTime
) {
}
这里是应该使用默认 JPARepository 方法保存此实体的服务方法
save()
:
@Override
public BoardingPass save(PostBoardingPassDto postBoardingPassDto) {
BoardingPass boardingPass = boardingPassMapper.toBoardingPass(postBoardingPassDto);
return boardingPassRepository.save(boardingPass);
}
boardingPassMapper
将 DTO 转换为实体,其实现方式如下:
@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;
}
}
所以我在
@ManyToOne
实体中使用了相同的方法,但没有遇到任何问题。然而,我在这里遗漏了一些东西。因此,我尝试插入一张登机牌,该登机牌具有已存在的 Ticket
的外键。那么该机票中将包含一个登机牌对象。当我发出 POST 请求时,不需要创建新机票(因此我在登机牌实体中没有 Cascade.ALL
类型。这是完整的屏幕截图:
因此,如果有人可以帮助我,我将非常感激。我已经被困了很长时间了。任何形式的建议都有帮助。
在不查看您的代码的情况下,我只能假设...但根据您的错误,您尝试保存的 BoardingPass 中设置的票证对象不是持久的。
现在,这种情况下的“持久”可能有一个特定的定义,那就是它对于现有会话是持久的。换句话说,如果它是在不同的事务/会话中从数据库加载的,那么根据当前会话,它不是持久的,持久意味着“从当前会话中的数据库加载”或“在当前会话中持久”。