javajpaannotationsone-to-one

How to create a one-to-one relationship between two entities on a PK using JPA?


I'm trying to link two entities using JPA via a one-to-one relationship, but I'm getting a "referenced property unknown" error one one of the classes. Here is a diagram of the two entities in question:

Model diagram

The vehicle_id column of the appraisal table links to the id of the vehicle. For that reason, I added the @PrimaryKeyJoinColumn annotation in the Appraisal class:

@Entity
@Table(name = "appraisal")
@Data
@IdClass(AppraisalId.class)
public class Appraisal {
    
    @Id
    @Column(name="vehicle_id")
    private Long vehicleId;
    
    @PrimaryKeyJoinColumn
    @OneToOne(mappedBy = "appraisal")
    private Vehicle vehicle;
    
    @Id
    @Column(name="customer_id")
    private Long customerId;
    
    @OneToOne
    @JoinColumn(name="appraised_for", referencedColumnName="id")
    private Customer customer;
    
    //1 column omitted for brevity
}

Notice that the Appraisal class uses a composite PK. Here is the AppraisalId class:

@Data
public class AppraisalId implements Serializable {
    
    private static final long serialVersionUID = -5373569618334807665L;
    
    private Long vehicleId;
    private Long customerId;

}

Here's the Vehicle class:

@Entity
@Table(name = "vehicle")
@Getter
@Setter
public class Vehicle {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private Long id;
    
    @OneToOne(mappedBy = "vehicle")
    private Appraisal appraisal;
    
    //other columns omitted for brevity
}

Note that I'm using the Lombok @Data annotation to generate getters and setters.

The exact error is "Unknown mappedBy in: ca.allauto.ups.model.Appraisal.vehicle, referenced property unknown: ca.allauto.ups.model.Vehicle.appraisal".

Any ideas what I'm doing wrong?


Solution

  • Since you have a composite primary key mapped in the entity that references other entities, you might want to let JPA handle the foreign key values directly so you don't have to set them yourself. With JPA 2.0 and beyond, you can mark relationship with @Id or if using basic/embeddableId mappings for the identifiers, tell JPA that the relationship controls the mapping using @MapsId instead:

    @Entity
    @Table(name = "appraisal")
    @IdClass(AppraisalId.class)
    public class Appraisal {
        
        @Id
        private Long vehicleId;
        
        @MapsId("vehicleId")
        @OneToOne
        @JoinColumn(name="vehicle_id")
        private Vehicle vehicle;
        
        @Id
        private Long customerId;
        
        @MapsId("customerId")
        @OneToOne
        @JoinColumn(name="appraised_for", referencedColumnName="id")
        private Customer customer;
        
        ..
    }