Spring Boot中如何通过外键而非关联对象增改Flight实体
解决方案
一、新增Flight(仅传外键ID)
不需要传入完整的关联实体对象,只需通过ID获取关联实体的懒加载代理对象即可(Spring Data JPA的getReferenceById方法不会触发实际数据库查询,仅返回代理,性能更优),再将其设置到Flight实体中保存。
示例代码:
Service层修改:
@Service @Transactional public class FlightService { private final FlightRepository flightRepository; private final AirportRepository airportRepository; private final AirlineRepository airlineRepository; private final AirplaneRepository airplaneRepository; // 构造注入依赖 public FlightService(FlightRepository flightRepository, AirportRepository airportRepository, AirlineRepository airlineRepository, AirplaneRepository airplaneRepository) { this.flightRepository = flightRepository; this.airportRepository = airportRepository; this.airlineRepository = airlineRepository; this.airplaneRepository = airplaneRepository; } public void addFlight(String flightNumber, String originId, String destinationId, String airlineId, Long airplaneId, Timestamp departureTime, Timestamp arrivalTime, Time duration, int passengers) { if (flightRepository.existsById(flightNumber)) { throw new IllegalStateException("Flight with number " + flightNumber + " already exists"); } // 通过ID获取关联实体的代理对象(不查询完整数据) Airport origin = airportRepository.getReferenceById(originId); Airport destination = airportRepository.getReferenceById(destinationId); Airline airline = airlineRepository.getReferenceById(airlineId); Airplane airplane = airplaneRepository.getReferenceById(airplaneId); // 构建Flight实体并保存 Flight flight = new Flight(); flight.setFlightNumber(flightNumber); flight.setOrigin(origin); flight.setDestination(destination); flight.setAirline(airline); flight.setAirplane(airplane); flight.setDepartureTime(departureTime); flight.setArrivalTime(arrivalTime); flight.setDuration(duration); flight.setPassengers(passengers); flightRepository.save(flight); } }
二、更新Flight(仅传外键ID)
你之前的自定义JPQL报错是因为直接用ID赋值给实体类型字段不符合JPQL语法,需修改语句,通过关联实体的ID属性来关联外键,同时确保方法添加事务和修改注解。
示例代码:
Repository层修改:
@Repository public interface FlightRepository extends JpaRepository<Flight, String> { @Modifying @Transactional @Query("update Flight f " + "set f.origin.id = :originId, " + "f.destination.id = :destinationId, " + "f.departureTime = :departureTime, " + "f.arrivalTime = :arrivalTime, " + "f.airline.id = :airlineId, " + "f.airplane.id = :airplaneId, " + "f.passengers = :passengers, " + "f.duration = :duration " + "where f.flightNumber = :flightNumber") void updateFlight(@Param("flightNumber") String flightNumber, @Param("originId") String originId, @Param("destinationId") String destinationId, @Param("departureTime") Timestamp departureTime, @Param("arrivalTime") Timestamp arrivalTime, @Param("airlineId") String airlineId, @Param("airplaneId") Long airplaneId, @Param("passengers") Integer passengers, @Param("duration") Time duration); }
说明:
- JPQL中通过
f.origin.id直接关联外键字段,允许传入ID字符串/数值,无需完整实体对象。 @Modifying标记这是修改操作,@Transactional确保操作在事务上下文执行。
三、进阶:使用DTO接收参数
为了更规范地处理前端传入的参数,可定义DTO类封装所有字段(含外键ID),再在Service层将DTO转换为Flight实体:
FlightDTO示例:
public class FlightDTO { private String flightNumber; private String originId; private String destinationId; private Timestamp departureTime; private Timestamp arrivalTime; private String airlineId; private Long airplaneId; private Time duration; private int passengers; // Getters and Setters }
Service层使用DTO:
public void addFlight(FlightDTO flightDTO) { if (flightRepository.existsById(flightDTO.getFlightNumber())) { throw new IllegalStateException("Flight with number " + flightDTO.getFlightNumber() + " already exists"); } Airport origin = airportRepository.getReferenceById(flightDTO.getOriginId()); Airport destination = airportRepository.getReferenceById(flightDTO.getDestinationId()); Airline airline = airlineRepository.getReferenceById(flightDTO.getAirlineId()); Airplane airplane = airplaneRepository.getReferenceById(flightDTO.getAirplaneId()); Flight flight = new Flight(); BeanUtils.copyProperties(flightDTO, flight); // 复制非关联字段 flight.setOrigin(origin); flight.setDestination(destination); flight.setAirline(airline); flight.setAirplane(airplane); flightRepository.save(flight); }
内容的提问来源于stack exchange,提问作者Raul
相关产品推荐
相关产品推荐

