Home > Mobile >  JPA Hibernate Problem for One to One Relationship with Embedded ID
JPA Hibernate Problem for One to One Relationship with Embedded ID

Time:11-15

I am struggling with the following problem that I've been trying to solve. After checking solutions on StackOverflow and articles on Baeldung I still get different JPA errors when trying to map the following ONE-TO-ONE relationship between 2 Oracle SQL tables with composite PK in a SpringBoot application:

MASTER

ID VERSION
1 2022.1

Constraint:

PK_MASTER PRIMARY KEY(ID, VERSION)

MASTER_DETAILS

MASTER_ID VERSION DETAILS
1 2022.1 details

Constraint:

PK_MASTER_DETAILS PRIMARY KEY(MASTER_ID, VERSION)

FK_MASTER_DETAILS FOREIGN KEY(MASTER_ID, VERSION) REFERENCES MASTER(ID, VERSION)

After some failures in trying to map it using the @OneToOne JPA annotation with both classes having @EmbeddedId set on the composite PK, I also installed JPA Buddy to check how it will be generated and that resulted in the following 4 classes:

Master.java

@Getter
@Setter
@Entity
@Table(name = "master")
public class Master {
    @EmbeddedId
    private MasterId id;

    @OneToOne(mappedBy = "master")
    private MasterDetails masterDetails;
}

MasterId.java

@Getter
@Setter
@Embeddable
public class MasterId implements Serializable {
    private static final long serialVersionUID = 8254837075462858051L;
    @Column(name = "id", nullable = false)
    private BigDecimal id;

    @Lob
    @Column(name = "version", nullable = false)
    private String version;
}

MasterDetails.java

@Getter
@Setter
@Entity
@Table(name = "master_details")
public class MasterDetails {
    @EmbeddedId
    private MasterDetailsId id;

    @MapsId
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumns({
            @JoinColumn(name = "master_id", referencedColumnName = "id", nullable = false),
            @JoinColumn(name = "version", referencedColumnName = "version", nullable = false)
    })
    private Master master;

    @Lob
    @Column(name = "details", nullable = false)
    private String details;
}

MasterDetailsId.java

@Getter
@Setter
@Embeddable
public class MasterDetailsId implements Serializable {
    private static final long serialVersionUID = -8375336118866998644L;
    @Column(name = "master_id", nullable = false)
    private BigDecimal masterId;

    @Lob
    @Column(name = "version", nullable = false)
    private String version;
}

When running the SpringBoot application with this JPA structure the run time error received is: org.hibernate.PropertyNotFoundException: Could not locate field [id] on class [org.project.packages.MasterDetails]

After removing the @MapsId that cause this error the application starts but when trying to insert data in the tables I get the following error: org.hibernate.id.IdentifierGenerationException: null id generated for:class org.project.packages.MasterDetails

Checking in the H2 test database I noticed that the FK on the Master_Details table was not present, but only the PK was set.

I would appreciate any help in pointing out how this problem can be solved: other annotations required (Cascade/FetchType) or in case there are any changes to be made to the database level (I also tried adding a separate identifier column in the Master_Details table defined as PK and only keep the FK to the Master table). Thanks in advance!

CodePudding user response:

After many tries, I figured out to solve the issue.

I had to use a common key between the two entities and also FetchType.LAZY.

MasterDetails.class

public class MasterDetails {

    @EmbeddedId
    @AttributeOverrides({
       @AttributeOverride(name="ID", column=@Column(name="MASTER_ID"))
    })
    private MasterId id;

    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumns({
        @JoinColumn(name = "master_id", referencedColumnName = "id", nullable = false),
        @JoinColumn(name = "version", referencedColumnName = "version", nullable = false)
    })
    
    private Master master;

    @Lob
    @Column(name = "guidance", nullable = false)
    private String guidance;
}

Master.class

public class MasterSheet {
   @EmbeddedId
   private MasterId id;

   @OneToOne(mappedBy = "master", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   private MasterDetails masterDetails;
}
  • Related