Hibernate/JPA @OneToOne 尝试使用外键插入实体时出现“对象引用未保存的瞬态实例”错误

问题描述 投票:0回答:1

我对 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
类型。这是完整的屏幕截图:

因此,如果有人可以帮助我,我将非常感激。我已经被困了很长时间了。任何形式的建议都有帮助。

java spring spring-boot hibernate jpa
1个回答
0
投票

在不查看您的代码的情况下,我只能假设...但根据您的错误,您尝试保存的 BoardingPass 中设置的票证对象不是持久的。

现在,这种情况下的“持久”可能有一个特定的定义,那就是它对于现有会话是持久的。换句话说,如果它是在不同的事务/会话中从数据库加载的,那么根据当前会话,它不是持久的,持久意味着“从当前会话中的数据库加载”或“在当前会话中持久”。

© www.soinside.com 2019 - 2024. All rights reserved.