Home > Net >  JpaSystemException when using composite key
JpaSystemException when using composite key

Time:03-05

I am building a spring boot application and I am stuck with the JpaSystemException: attempted to assign id from null one-to-one property error. Let me give you some details about the project.

First of all, I have the following db schema

describe airports;

 -------------------------- ------------ ------ ----- --------- ------- 
| Field                    | Type       | Null | Key | Default | Extra |
 -------------------------- ------------ ------ ----- --------- ------- 
| airport_id               | int(11)    | NO   | PRI | NULL    |       |
| airport_name             | text       | NO   |     | NULL    |       |
 -------------------------- ------------ ------ ----- --------- ------- 

describe flights;

 ------------------------ --------- ------ ----- --------- ------- 
| Field                  | Type    | Null | Key | Default | Extra |
 ------------------------ --------- ------ ----- --------- ------- 
| flight_from_airport_id | int(11) | NO   | PRI | NULL    |       |
| flight_to_airport_id   | int(11) | NO   | PRI | NULL    |       |
| flight_type            | int(11) | NO   | PRI | NULL    |       |
 ------------------------ --------- ------ ----- --------- ------- 

Basically, table flights is used to store data for flights from one airport to another.

I have two entities; airport and flight as follows:

Airport.java

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "airports")
public class Airport {
    @Id
    @Column(name="airport_id")
    private int airportId;
    
    @Column(name="airport_name")
    private String airportName;
    
    //Getters and Setters

    public Airport(int airportId, String airportName) {
        this.airportId = airportId;
        this.airportName = airportName;
    }
}

Flight.java

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.Table;

@Entity
@Table(name = "flights")
public class Flight {
    
    @EmbeddedId
    FlightPrimaryKey flightPrimaryKey;

    @MapsId("fromAirport")
    @ManyToOne
    @JoinColumn(name = "flightFromAirportId")
    private Airport fromAirport;

    @MapsId("toAirport")
    @ManyToOne
    @JoinColumn(name = "flightToAirportId")
    private Airport toAirport;

    @Column(name="flight_type")
    private int flightType;

    //Getters and Setters

    public Flight(FlightPrimaryKey flightPrimaryKey, int flightType) {
        this.flightPrimaryKey = flightPrimaryKey;
        this.flightType = flightType;
    }
}

Because I want a composite key for the class Flight, I have an Id class.

FlightId.java


import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class FlightId implements Serializable {
        
    @Column(name = "flight_from_airport_id")
    private int fromAirport;

    @Column(name = "flight_to_airport_id")
    private int toAirport;

    // Getters and Setters, hashcode, equals

    public TransferPrimaryKey(int fromAirport, int toAirport) {
        this.fromAirport = fromAirport;
        this.toAirport = toAirport;
    }
}

Then I have a JPA repository

FlightRepository.java

public interface FlightRepository extends JpaRepository<Flight, FlightId>{}

And to test the above I use the following code:

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class FlightTest {

    @Autowired
    private AiportRepository airportRepository;

    @Autowired
    private FlightRepository flightRepository;

    @Test
    public void shouldStoreAFlight() {
        Airport fromAirport = airportRepository.save(new Airport(1, "LAX");
        Airport toAirport = airportRepository.save(new Airport(2, "JFK")
        FlightId flightId = new FlightId(fromAirport.getId(), toAirport.getId());
        Flight flight = flightRepository.save(new Flight(flightId, 1));
    }
}

When I run the above code, I get the JpaSystemException. I also cannot understand why the error says about one-to-one property. I have only defined a many-to-one property. Clearly I am missing something.

CodePudding user response:

Solution should be to set your references:

public void shouldStoreAFlight() {
  Airport fromAirport = airportRepository.save(new Airport(1, "LAX");
  Airport toAirport = airportRepository.save(new Airport(2, "JFK")
  FlightId flightId = new FlightId(fromAirport.getId(), toAirport.getId());
  Flight flight  = new Flight(flightId, 1);
  flight.setFromAirport(fromAirport);
  flight.setToAirport(toAirport);
  flight = flightRepository.save(flight);
}

There should be no need to set the values in FlightId with the above code, but I left it to match your constructors, and because you have them set to int instead of an Integer that allows nulls.

  • Related