了解映射通过休眠中的注释

2022-09-03 09:24:03

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

@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=?

为什么休眠尝试在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

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

现在,如果我尝试保存客户及其订单,我会得到以下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属性的情况相比,我们没有额外的更新查询?


答案 1

这很正常。

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

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

例:

  • 堆栈溢出具有多个 .QuestionAnswer
  • An 由一个且只有一个 拥有。AnswerQuestion

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

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

其中 外键引用 。Question_IDQuestion.Question_ID

至于另一种情况,我没有真实的情况,因为几乎每次都有一个独特的约束(例如:a可能有几个,并且可能物理上有几个,但对于任何一个,只出现一次)。QuestionAnswerAnswerQuestionQuestion


答案 2

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

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

如果您离开映射并让它默认,则默认情况下它将使用关系表,这似乎是您想要的。如果不希望使用联接表,则可以指定一个,该连接表设置的外键关系与 一个非常相似,但方向相反 - 它告诉提供程序目标表中的哪个字段指向此实体的主键。但通常,目标外键映射在目标实体中 - 它毕竟是一个 - 因此用于指定这应该使用目标实体中已经定义的关系。OneToManyJoinColumnOneToOneManyToOnemappedbyOneToMany

在本例中,告诉它查看 Order 实体中的属性映射。在那里,它发现客户有一个映射,其中包含一个默认连接列,它也将其用于 .由于它已在 Order 实体中映射,因此 是只读的。这可确保如果两个关系不同步,则始终具有信任的一方并用于设置数据库字段。mappedBy=customercustomerManyToManycustomer_idOneToManyOneToManyJPA


推荐