JPA and Hibernate One To One Shared Primary Key Uni-directional Mapping in Spring Boot

I want to have one-to-one uni-directional mapping with 2 child entities using shared primary key. Below are model classes

public class Template implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "templatekey")
    Integer templateKey;

    @Column(name = "templateid", unique = true)
    String templateId;
    
    @OneToOne(cascade = CascadeType.ALL, optional = false)
    @PrimaryKeyJoinColumn(name = "templatekey", referencedColumnName = "templatekey")
    InstantOfferNoEsp instantOfferNoEsp;

    @OneToOne(cascade = CascadeType.ALL, optional = false)
    @PrimaryKeyJoinColumn(name = "templatekey", referencedColumnName = "templatekey")
    Mobile mobile;

     //constructor , setter and getters

}

Child 1 :

public class Mobile implements Serializable {
   
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "templatekey")
    Integer templateKey;
    
    String mobileNewUrl;


    //constructor , setter and getters

}

Child 2:

public class InstantOfferNoEsp {

    @Id
    @Column(name = "templatekey")
    Integer templateKey;

    String offerCodeType;

    String headerUrl;
 
    //constructor , setter and getters
}

I want templateKey as PK in all tables. and I am calling templateRepository.save(template); to save all entities at once but its not working and getting ids for this class must be manually assigned before calling save() error.

Any suggestions would be of great help. Thank you.

1 answer

  • answered 2021-02-24 09:13 SternK

    I was able to do what you want with bidirectional @OneToOne like below:

    @Entity
    public class Mobile {
    
        @Id
        Integer templateKey;
        
        @OneToOne
        @MapsId
        @JoinColumn(name = "templatekey")
        Template template;
    
        // ...
    }
    
    @Entity
    public class InstantOfferNoEsp {
    
        @Id
        Integer templateKey;
    
        @OneToOne
        @MapsId
        @JoinColumn(name = "templatekey")
        Template template;
     
        // ...
    }
    
    
    @Entity
    public class Template {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        @Column(name = "templatekey")
        Integer templateKey;
    
        
        @OneToOne(cascade = CascadeType.ALL, mappedBy = "template", optional = false)
        InstantOfferNoEsp instantOfferNoEsp;
    
        @OneToOne(cascade = CascadeType.ALL, mappedBy = "template", optional = false)
        Mobile mobile;
    
        // ...
    
        public void setMobile(Mobile mobile)
        {
            this.mobile = mobile;
            this.mobile.setTemplate(this);
        }
    
        public void setInstantOfferNoEsp(InstantOfferNoEsp instantOfferNoEsp)
        {
            this.instantOfferNoEsp = instantOfferNoEsp;
            this.instantOfferNoEsp.setTemplate(this);
        }
    }
    

    and an example of saving:

    Mobile mobile = new Mobile();
    mobile.setMobileNewUrl("MOB1");
    
    InstantOfferNoEsp instant = new InstantOfferNoEsp();
    instant.setOfferCodeType("INST_OFF1");
          
    Template template = new Template();
    template.setTemplateId("TMP1");
    template.setInstantOffer(instant);
    template.setMobile(mobile);
    entityManager.persist(template);
    

    P.S. The following mapping works too, but only if we set Template.templateKey manually.

    @Entity
    public class Template
    {
       @Id
       // @GeneratedValue(strategy = GenerationType.AUTO)
       @Column(name = "templatekey")
       Integer templateKey;
    
       @OneToOne(cascade = CascadeType.ALL, optional = false)
       @JoinColumn(name = "templatekey", insertable = false, updatable = false)
       InstantOfferNoEsp instantOfferNoEsp;
    
       @OneToOne(cascade = CascadeType.ALL, optional = false)
       @JoinColumn(name = "templatekey", insertable = false, updatable = false)
       Mobile mobile;
     
       // ...
    }
    

    and an example of saving:

    Mobile mobile = new Mobile();
    mobile.setMobileNewUrl("MOB1");
    
    InstantOfferNoEsp instant = new InstantOfferNoEsp();
    instant.setOfferCodeType("INST_OFF1");
          
    Template template = new Template();
    template.setTemplateKey(20);
    template.setTemplateId("TMP1");
    template.setInstantOffer(instant);
    template.setMobile(mobile);
    entityManager.persist(template);
    

    Also I would suggest your explicitly specify what generation strategy you want to use (do not use GenerationType.AUTO) and use corresponding object wrapper classes instead of primitive types for @Id fields.