繁体   English   中英

如何在 Spring Boot 中更新具有 OneToMany 关系的实体

[英]How to update entity with OneToMany relationship in Spring Boot

我是 Spring 引导的新手,我正在编写一个应用程序来练习,使用 Postresql 作为数据库。 该应用程序是关于航空的。 有 4 个实体:Airline、Airplane、Airport 和 Flight。

我尝试了 GET、POST 和 DELETE 请求,所有这些都适用于航空公司、飞机和机场,但我在尝试添加和更新航班时遇到了问题。 Flight 有 4 个 ManyToOne 关系,这是 class:

@Entity
@Table
public class Flight {
    @Id
    @Column(name = "flight_number")
    private String flightNumber;

    @ManyToOne
    @JoinColumn(name = "origin")
    private Airport origin;

    @ManyToOne
    @JoinColumn(name = "destination")
    private Airport destination;

    @Column(name = "departure_time")
    private Timestamp departureTime;

    @Column(name = "arrival_time")
    private Timestamp arrivalTime;

    @ManyToOne
    @JoinColumn(name = "airline")
    private Airline airline;

    @ManyToOne
    @JoinColumn(name = "airplane")
    private Airplane airplane;

    private Time duration;
    private int passengers;
    ...
}

我不明白的是如何插入和更新这个实体而不需要传递ObjectsAirlineAirport )而只传递外键(就像直接在数据库上工作时一样)。

这是我添加需要对象的新航班的代码:

public void addFlight(Flight flight) {
    boolean exists = flightRepository.existsById(flight.getFlightNumber());
    if (exists) {
        throw new IllegalStateException("Flight with number" + flight.getFlightNumber() 
        + "already exists");
    }
    flightRepository.save(flight);
}

我还尝试为存储库中的更新编写一个特定的查询,然后调用 PUT 请求,但我收到一些错误提示我需要传递 Airline 和 Airport,而不是表示这两个实体 ID 的字符串。

*@Modifying
@Query("update Flight " +
        "set origin = :origin, " +
        "destination = :destination, " +
        "departureTime = :departureTime, " +
        "arrivalTime = :arrivalTime, " +
        "airline = :airline, " +
        "airplane = :airplane, " +
        "passengers = :passengers, " +
        "duration = :duration " +
        "where flightNumber = :flightNumber")
void updateFlight(@Param("flightNumber") String flightNumber,
                  @Param("origin") String origin,
                  @Param("destination") String destination,
                  @Param("departureTime") Timestamp departureTime,
                  @Param("arrivalTime") Timestamp arrivalTime,
                  @Param("airline") String airline,
                  @Param("airplane") Long airplane,
                  @Param("passengers") Integer passengers,
                  @Param("duration") Time duration);*/

总结一下:我想知道是否有一种方法可以避免在创建和更新过程中传递表示 ManyToOne 关系的整个 Object。

方法addFlight(Flight flight)是从您的 controller 调用的吗? 如果是这种情况,您应该从您的 controller 获得一个DTO ,您将在服务层的实体中获得 map。

在 DTO 中,您需要提供AirlineAirplaneAirport对象的 ID,以便您可以从数据库中检索它们并将它们设置在Flight实体上。

这是我可以建议的解决方案:

void addFlight (FlightRequest flightRequest) {
    boolean exists = flightRepository.existsById(flightRequest.flightNumber());
    if (exists) {
        throw new IllegalStateException("Flight with number" + flight.getFlightNumber() 
        + "already exists");
    }
    
    Flight flight = new Flight();
    
    airportRepository.findById(flightRequest.airportOriginId())
                     .ifPresentOrElse(airportOrigin -> {  
                          flight.setAirportOrigin(airportOrigin);
                        },
                          () -> new IllegalStateException(...)
                      );

    airportRepository.findById(flightRequest.airportDestinationId())
                     .ifPresentOrElse(airportDestination -> {  
                          flight.setAirportDestination(airportDestination);
                        },
                          () -> new IllegalStateException(...)
                      );

    airlineRepository.findById(flightRequest.airlineId())
                     .ifPresentOrElse(airline -> {  
                          flight.setAirline(airline);
                        },
                          () -> new IllegalStateException(...)
                      );

    airplaneRepository.findById(flightRequest.airplaneId())
                     .ifPresentOrElse(airplane -> {  
                          flight.setAirplane(airplane);
                        },
                          () -> new IllegalStateException(...)
                      );

    flight.setFlightNumber(flightRequest.flightNumber());
    flight.setDepartureTime(flightRequest.departureTime());
    flight.setArrivalTime(flightRequest.arrivalTime());
    flight.setDuration(flightRequest.duration());
    flight.setPassengers(flightRequest.passengers());   
    ...

    flightRepository.save(flight);
}
public record FlightRequest(  
        String flightNumber,  
        String airportOriginId,  
        String airportDestinationId,  
        Timestamp departureTime,  
        Timestamp arrivalTime,  
        String airlineId,  
        String airplaneId,  
        Time duration,  
        int passengers,
        ...
) {  
}

为了更新您的Flight ,您可以这样做:

Flight updateFlight (FlightRequest flightRequest) {
    Flight flight = flightRepository.findById(flightRequest.flightNumber())
                        .orElseThrow(...);
                        
    // Same as above without the call for existsById
    ...
}

如果你想进一步了解 go,自 Spring 版本 2.7 数据 JPA 以来,你可以使用getReferenceById方法而不是findById 在那种情况下 Spring 数据 JPA 不会生成 SQL 语句来获取实体,在我们的例子中我们只想设置外键。 你可以在这里找到更多相关信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM