Java 理解Hibernate中的mappedBy注解

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25371481/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:14:11  来源:igfitidea点击:

Understanding mappedBy annotation in Hibernate

javahibernatejpa

提问by Chaitanya

I am trying to understand the mappedByattribute of @OneToManyannotation in JPA. I created below example where a Customer has a list of Orders:

我想了解JPAmappedBy@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;
}

Now when I use Hibernate to generate the tables then I see that Hibernate created only 2 tables:

现在,当我使用 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

Also if I try to save a customer and some Orders I see below DML statements generated by Hibernate:

此外,如果我尝试保存客户和一些订单,我会在 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=?

Why hibernate tried to insert and updates the record in TBL_ORDER instead of just running a single insert query?

为什么 hibernate 试图在 TBL_ORDER 中插入和更新记录,而不是仅仅运行一个插入查询?

Now if I remove the mappedBy attribute and try to generate the tables, I see 3 tables this time:

现在,如果我删除了 mappingBy 属性并尝试生成表,这次我会看到 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

Why hibernate creates an additional table in this case? How the mappedBy attribute is controlling this? Why we have an additional unique key constraint on orders_id column in Customer_TBL_ORDER table?

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

Now if I try to save a customer and its orders I get below DML operations:

现在,如果我尝试保存客户及其订单,我会得到以下 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 (?, ?, ?)

Why we don't have an additional update query in this case compared to the case where I have declared the mappedBy attribute?

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

采纳答案by NoDataFound

That's normal.

这是正常的。

With the mappedBy, you directly tell Hibernate/JPA that one table owns the relationship, and therefore it is stored as a column of that table.

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

Without, the relationship is external and Hibernate/JPA need to create another table to store the relationship.

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

Example:

例子:

  • A stackoverflow Questionhave several Answer.
  • An Answeris owned by one and only one Question.
  • 一个 stackoverflowQuestion有几个Answer.
  • AnAnswer由一个且仅一个拥有Question

In plain JDBC, you would create two table:

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

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

Where Question_IDis foreign key referencing Question.Question_ID.

Question_ID外键引用在哪里Question.Question_ID

As for the other case, I don't have a real case since there are almost every time many to many with a unique constraint(eg: a Questionmay have several Answer, and Answermay have physically have several Question, but appears only once for any Question).

至于另一种情况,我没有真正的案例,因为几乎每次都有多对多的唯一约束(例如:aQuestion可能有几个Answer,并且Answer可能在物理上有几个Question,但 any 只出现一次Question)。

回答by Xstian

Is normal this behavior mappedByindicates only that the entity in this side is the inverse of the relationship, and the owner resides in the "other" entity.

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

I suggest you this link

我建议你这个链接

回答by Chris

A OneToManyhas two main ways it can be accomplished in the database.

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

  1. using a relation table (M:M)
  2. using a foreign key in the target table. (1:M)
  1. 使用关系表 (M:M)
  2. 在目标表中使用外键。(1:M)

If you leave a OneToManymapping and let it default, it will by default use a relation table, which is what you seem to want. If you don't want a join table to be used, you would either specify a JoinColumnwhich sets up a foreign key relationship much like a OneToOne, but in the opposite direction - it tells the provider what field in the target table points to this entity's primary key. But commonly the target foreign key is mapped in the target entity - it is a ManyToOneafter all - and so the mappedbyis used to specify that this OneToManyshould use the relationship already defined in the target entity.

如果你留下一个OneToMany映射并让它默认,它会默认使用一个关系表,这就是你想要的。如果您不想使用连接表,您可以指定 aJoinColumn来设置外键关系,就像 a 一样OneToOne,但方向相反 - 它告诉提供者目标表中的哪个字段指向该实体的主字段钥匙。但通常目标外键映射在目标实体中 -ManyToOne毕竟它是一个- 因此mappedby用于指定这OneToMany应该使用已经在目标实体中定义的关系。

In this case, mappedBy=customertells it to look at the customerproperty mapping within the Order entity. There, it finds customer has a ManyToManymapping with a default joinColumn customer_idthat it also uses for the OneToMany. Because it is already mapped within the Order entity, the OneToManyis read-only. This ensures that should the two relationships be out of sync, JPAhas one side to always trust and use to set the database field.

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