【问题标题】:Understanding mappedBy annotation in Hibernate理解 Hibernate 中的 mappedBy 注解
【发布时间】:2014-08-18 20:25:39
【问题描述】:

我试图理解 JPA 中 @OneToMany 注释的 mappedBy 属性。我创建了下面的示例,其中客户有一个订单列表:

@Entity
public class Customer {
   @Id @GeneratedValue public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   private Integer id;

   @OneToMany(mappedBy="customer")
   @OrderColumn(name="orders_index")
   public List<Order> getOrders() { return orders; }
   public void setOrders(List<Order> orders) { this.orders = orders; }
   private List<Order> orders;
}

@Entity
@Table(name="TBL_ORDER")
public class Order {
   @Id @GeneratedValue public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   private Integer id;

   public int getOrderNumber() { return orderNumber; }
   public void setOrderNumber(int orderNumber) { this.orderNumber = orderNumber; }
   private int orderNumber;

   @ManyToOne
   public Customer getCustomer() { return customer; }
   public void setCustomer(Customer customer) { this.customer = customer; }
   private Customer customer;
}

现在当我使用 Hibernate 生成表时,我看到 Hibernate 只创建了 2 个表:

Hibernate: create table Customer (id number(10,0) not null, primary key (id))
Hibernate: create table TBL_ORDER (id number(10,0) not null, orderNumber number(10,0) not null, customer_id number(10,0), orders_index number(10,0), primary key (id))
Hibernate: alter table TBL_ORDER add constraint FK_nt24krtgqwcsynosqgk4jkvfv foreign key (customer_id) references Customer

此外,如果我尝试保存客户和一些订单,我会在 Hibernate 生成的 DML 语句下方看到:

Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TBL_ORDER (customer_id, orderNumber, id) values (?, ?, ?)
Hibernate: update TBL_ORDER set orders_index=? where id=?

为什么 hibernate 尝试插入和更新 TBL_ORDER 中的记录而不是只运行单个插入查询?

现在,如果我删除 mappedBy 属性并尝试生成表,这次我会看到 3 个表:

Hibernate: create table Customer (id number(10,0) not null, primary key (id))
Hibernate: create table Customer_TBL_ORDER (Customer_id number(10,0) not null, orders_id number(10,0) not null, orders_index number(10,0) not null, primary key (Customer_id, orders_index))
Hibernate: create table TBL_ORDER (id number(10,0) not null, orderNumber number(10,0) not null, customer_id number(10,0), primary key (id))
Hibernate: alter table Customer_TBL_ORDER add constraint UK_sw94jktvh72tripj876s31052  unique (orders_id)
Hibernate: alter table Customer_TBL_ORDER add constraint FK_sw94jktvh72tripj876s31052 foreign key (orders_id) references TBL_ORDER
Hibernate: alter table Customer_TBL_ORDER add constraint FK_f03up2h945cg0dcbo2pdb1d3c foreign key (Customer_id) references Customer
Hibernate: alter table TBL_ORDER add constraint FK_nt24krtgqwcsynosqgk4jkvfv foreign key (customer_id) references Customer

为什么在这种情况下hibernate会创建一个额外的表? mappedBy 属性如何控制这一点?为什么我们对 Customer_TBL_ORDER 表中的 orders_id 列有一个额外的唯一键约束?

现在,如果我尝试保存客户及其订单,我会得到以下 DML 操作:

Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TBL_ORDER (customer_id, orderNumber, id) values (?, ?, ?)
Hibernate: insert into Customer_TBL_ORDER (Customer_id, orders_index, orders_id) values (?, ?, ?)

与我声明了 mappedBy 属性的情况相比,为什么在这种情况下我们没有额外的更新查询?

【问题讨论】:

    标签: java hibernate jpa


    【解决方案1】:

    这很正常。

    使用mappedBy,您可以直接告诉 Hibernate/JPA 一个表拥有该关系,因此它被存储为该表的一列。

    没有,关系是外部的,Hibernate/JPA 需要创建另一个表来存储关系。

    例子:

    • 一个stackoverflow Question 有几个Answer
    • Answer 由一个且只有一个 Question 拥有。

    在普通的 JDBC 中,您将创建两个表:

    Questions(Question_ID, ...);
    Answers(Answer_ID, Question_ID, ...);
    

    其中Question_ID 是引用Question.Question_ID 的外键。

    至于另一种情况,我没有一个真实的案例,因为几乎每次都有唯一约束的多对多(例如:Question 可能有多个Answer , 而Answer 可能实际上有多个Question,但对于任何Question 只出现一次。

    【讨论】:

      【解决方案2】:

      OneToMany 有两种主要方式可以在数据库中完成。

      1. 使用关系表 (M:M)
      2. 在目标表中使用外键。 (1:M)

      如果您保留OneToMany 映射并让它默认,它将默认使用关系表,这似乎是您想要的。如果你不想使用连接表,你可以指定一个JoinColumn,它设置一个外键关系,很像OneToOne,但方向相反——它告诉提供者目标中的哪个字段table 指向该实体的主键。但通常目标外键映射到目标实体中——毕竟它是ManyToOne——因此mappedby用于指定这个OneToMany应该使用已经在目标实体中定义的关系。

      在这种情况下,mappedBy=customer 告诉它查看 Order 实体中的 customer 属性映射。在那里,它发现客户有一个 ManyToMany 映射和一个默认的 joinColumn customer_id,它也用于OneToMany。因为它已经在 Order 实体中映射,所以 OneToMany 是只读的。这确保了如果这两个关系不同步,JPA 有一方始终信任并用于设置数据库字段。

      【讨论】:

        【解决方案3】:

        这种行为mappedBy是正常的,只是表明这一方的实体是关系的逆,所有者驻留在“其他”实体中。

        我建议你这个link

        【讨论】:

          猜你喜欢
          • 2016-07-22
          • 2014-10-03
          • 1970-01-01
          • 2012-02-24
          • 2013-08-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-21
          相关资源
          最近更新 更多