@OneToOne bidirectional mapping with @JoinColumn

后端 未结 2 810
春和景丽
春和景丽 2020-12-03 16:53

Let\'s say I have Person

class Person{
    @Id Integer id;

    @OneToOne
    @JoinColumn(name = \"person_id\")
    Job myJob;
}

and Job

相关标签:
2条回答
  • 2020-12-03 17:09

    This discussion assumes that a property such as "update" is assigned to hibernate.hbm2ddl.auto in persistence.xml to enable Hibernate to establish a One-To-One relationship and create a foreign key in the owning entity for the non-owning entity, together with a foreign key identity column in the corresponding table. However, this process will succeed only if the relationship is established at the time the tables are created. Adding @JoinColumn and @OneToOne(mappedBy) to existing entities will cause Hibernate to complain that the FK column doesn't exist in the owning table. So when implementing the relationship between tables containing live data, it is necessary to add the FK column manually. Hibernate will then be able to establish the FK constraint with an odd name like FKg6wt3d1u6o13gdc1hj36ad1ot.

    The nuances involved are illustrated by a slightly more detailed example. Consider a database in which the entity Contact will be a common component of various tables (employee, customer, vendor, etc.) joined OneToOne. As a preliminary consideration, while a OneToOne relationship may be bi-directional, its implementation in Hibernate dictates that the common entity be assigned the non-owning designation so that a FK will be created in each owning entity's table. Implementing OneToOne the other way around will cause Hibernate to look for the foreign key in the NON-owning class and throw an error when it isn't found. (Been there, done that.)

    @Entity // common, non-owning entity
    public class Contact implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", updatable = false, nullable = false)
    
    private Integer id;
    
        @Column(name="fn")
        private String firstName;
    
        @Column(name="ln")
        private String lastName;
    
    // "person" is the Contact entity as declared in Director
      @OneToOne(optional=false, mappedBy = "person")    
      private Director director;
    
     // GETTERS & SETTERS
    

    AND

    @Entity // owning entity
    public class Director implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", updatable = false, nullable = false)
    
    private Integer id;
    
        @Column(name="title")
        private String title;
    
    @OneToOne
        @JoinColumn
        private Contact person;
    
    public Integer getId() {
            return id;
    }   
    public String getTitle() {
            return title;
    }
    public void setTitle(String title) {
            this.title = title;
    }
    public Contact getPerson() {
            return person;
    }
    public void setPerson(Contact person) {
            this.person = person;
    }
    

    Assuming the FK column exists in Director, the code produces:

    alter table Director 
       add constraint FKg6wt3d1u6o13gdc1hj36ad1ot 
       foreign key (person_id) 
       references Contact (id)
    

    The derivation of the FK name Hibernate assigns to the Contact entity in Director is a bit obscure. It is a concatenation of the variable name assigned to the Contact instance variable in the owning entity (here, person) + "_" + the entity's primary key "id," producing person_id. Note also that the @OneToOne(mappedBy = "person") annotation references this same Contact instance variable. Finally, Hibernate accesses the FK column directly without the need for corresponding getters and setters in the Director class.

    0 讨论(0)
  • 2020-12-03 17:14

    Your code should be:

    @Entity
    public class Person implements Serializable {
    
        @Id Integer id;
    
        @OneToOne
        @JoinColumn(name = "id")
        Job myJob;
    }
    
    @Entity
    public class Job implements Serializable {
    
        @Id Integer id;
    
        @OneToOne(mappedBy = "myJob")
        Person currentWorker;
    }  
    

    (pay attemption to remove duplicated colum 'person_id' from Job)

    or other approach sharing primary key:

    @Entity
    public class Person {
        @Id Integer id;
    
        @OneToOne(cascade = CascadeType.ALL)
        @PrimaryKeyJoinColumn
        Job myJob;
    }            
    
    @Entity
    public class Job {
        @Id Integer id;
    } 
    
    0 讨论(0)
提交回复
热议问题