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



我是Spring启动的新手,我正在编写一个应用程序来练习,使用Postresql作为db。这个应用程序是关于航空的。有4个实体:航空公司、飞机、机场和航班。

我尝试了GET, POST和DELETE请求,所有工作在航空公司,飞机和机场,但我有一个问题,试图添加和更新航班。Flight有4个ManyToOne关系,这是类:

@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;
...
}

我不明白的是如何插入和更新这个实体,而不需要传递Objects(AirlineAirport),而只是外键(如直接在db上工作时)。

下面是我的代码添加一个新的航班,需要的对象:

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关系的整个对象。

方法addFlight(Flight flight)是从你的控制器调用吗?如果是这种情况,你应该从你的控制器获得一个DTO,你将映射到你的服务层中的实体中。

从DTO你需要提供Airline,AirplaneAirport对象的id,这样你就可以从DB中检索它们,并在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
...
}

如果您想更进一步,从Spring Data JPA的2.7版本开始,您可以使用getReferenceById方法而不是findById。在这种情况下,Spring Data JPA不会生成SQL语句来获取实体,在我们的情况下,我们只想设置外键。你可以在这里找到更多信息

相关内容

  • 没有找到相关文章

最新更新