注解中的mappedBy属性是什么意思?

7

我是一个Hibernate的新手。我尝试在以下代码中创建Person和PersonDetail实体之间的一对一映射:

@Entity
public class Person {

    private int personId;
    private String personName;
    private PersonDetail personDetail;

    @OneToOne(mappedBy="person")
    public PersonDetail getPersonDetail() {
        return personDetail;
    }

    public void setPersonDetail(PersonDetail personDetail) {
        this.personDetail = personDetail;
    }

    @Id
    @GeneratedValue
    public int getPersonId() {
        return personId;
    }

    public void setPersonId(int personId) {
        this.personId = personId;
    }

    public String getPersonName() {
        return personName;
    }

    public void setPersonName(String personName) {
        this.personName = personName;
    }
}


@Entity
public class PersonDetail {

    private int personDetailId;
    private String zipCode;
    private String job;
    private double income;

    private Person person;

    @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    @Id
    @GeneratedValue
    public int getPersonDetailId() {
        return personDetailId;
    }

    public void setPersonDetailId(int personDetailId) {
        this.personDetailId = personDetailId;
    }

    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public double getIncome() {
        return income;
    }

    public void setIncome(double income) {
        this.income = income;
    }

}

我希望PersonDetail成为拥有实体(我知道反过来也是正确的,但我只是想测试)。我不明白的是在Person实体中放置的mappedBy属性的用途。如果我删除它,就会得到以下错误消息:“Could not determine type for: com.hibernate.onetoonemapping.PersonDetail, at table: Person, for columns: [org.hibernate.mapping.Column(personDetail)]”。这个mappedBy属性是什么作用?我已经读到mappedBy属性放置在非拥有端。但它具体做什么呢?
3个回答

11

这意味着实体之间的关系已经被映射,因此您不需要再次执行该操作。您只需使用mappedBy属性说“嘿,在那边做好了”。


9
当你想要使关系双向(可以从实体的任一侧访问)时,你需要在非拥有方使用mappedBy,因为你只能定义一次关系。 mappedBy告诉Hibernate如何创建你的实体实例并将数据加载到它们中。它应该引用你正在注释的类中的字段名称,在这个例子中是PersonDetail,关系是在这里定义的。

4

在您的场景中,mappedBy属性不应该有任何影响。

我对主键的名称感到困惑(它与"id"不同),但使用非标准名称作为标识符(出乎意料地)不会导致您面临的问题。

我已经尝试过OneToMany和OneToOne关联中的mappedBy参数,并想分享我的发现。我有一个类似的测试场景来说明影响。

Person.class:

@Entity
public class Person {

  @Id
  @GeneratedValue
  private Long id;

  @Column(name = "name")
  private String name;

  @OneToOne
  private Address address;
}

Address.class(用于 OneToOne 测试):


@Entity
public class Address {
  @Id
  @GeneratedValue
  private Long id;

  @Column(name = "address")
  private String address;


  @OneToOne(mappedBy="address")
  private Person person;

  @OneToMany(cascade = CascadeType.ALL)
  private Set<Phone> phone = new HashSet<Phone>();
}

Phone.class (用于OneToMany测试):

@Entity
public class Phone {

  @Id
  @GeneratedValue
  private Long id;

  @ManyToOne(optional = false)
  private Person person;

  @Column(name = "number")
  private String number;
}

通过调整 OneToOne 关联中的 "mappedBy" 参数,Hibernate 执行的 SQL 语句保持不变。
Hibernate: 
/* insert domain.Address
    */ insert 
    into
        Address
        (id, address) 
    values
        (default, ?)
Hibernate: 
/* insert domain.Person
    */ insert 
    into
        Person
        (id, address_id, name) 
    values
        (default, ?, ?)
OneToMany关联中,如果没有指定“mappedBy”,Hibernate会自动使用一个连接表,而使用“mappedBy”参数则将关联映射为实体表中的一个单独列。如果我使用...
 @OneToMany(cascade = CascadeType.ALL)
 private Set<Phone> phone = new HashSet<Phone>();

如果只在电话簿中存储一个人的电话入口,则会执行以下语句:

Hibernate: 
/* insert domain.Phone
    */ insert 
    into
        Phone
        (id, number, person_id) 
    values
        (default, ?, ?)
Hibernate: 
/* insert collection
    row domain.Person.phone */ insert 
    into
        Person_Phone
        (Person_id, phone_id) 
    values
        (?, ?)

Whereas using...

 @OneToMany(mappedBy="id", cascade = CascadeType.ALL)
 private Set<Phone> phone = new HashSet<Phone>();

这会导致略微不同的关系模型,更接近于在这种情况下可能期望的模型:
Hibernate: 
/* insert domain.Phone
    */ insert 
    into
        Phone
        (id, number, person_id) 
    values
        (default, ?, ?)

对于OneToMany关联,我发现如果您不指定“mappedBy”,Hibernate会自动使用一个连接表。如果您不喜欢连接表,请在OneToMany注释中使用JoinColumn注释。这也留下了一个问题 - mappedBy的确切含义是什么? - Andrey M. Stepanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接