Hibernate queries for @JoinColumn and mappedBy



我试图理解如果我使用@JoinColumn与Hibernate中@OneToMany映射的mappedBy属性相比所生成的DML查询的差异。

如果我的java类定义为:

@Entity
public class Product {
  @Id
  String serialNumber;
  @OneToMany
  @JoinColumn(name = "PRODUCT_ID")
  Set<Part> parts = new HashSet<Part>();
}
@Entity
public class Part {
    @Id
    @GeneratedValue
    int id;
    String partName;
}

然后id我保存一个产品和零件,然后hibernate生成插入并更新查询:

Hibernate: insert into Product (serialNumber) values (?)
Hibernate: insert into Part (partName, id) values (?, ?)
Hibernate: update Part set PRODUCT_ID=? where id=?

现在如果我有我的java类定义为:

@Entity
public class Customer {
    @Id
    @GeneratedValue
    private Integer id;
    @OneToMany(mappedBy = "customer")
    private List<Order> orders;
}
@Entity
@Table(name="TBL_ORDER")
public class Order {
    @Id
    @GeneratedValue
    private Integer id;
    private int orderNumber;
    @ManyToOne
    private Customer customer;
    @Override
    public String toString() {
        return id.toString();
    }
}

Hibernate只生成插入查询,不生成任何更新:

Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TBL_ORDER (customer_id, orderNumber, id) values (?, ?, ?)

如果我的实体之间的关系只是一对多,那么为什么hibernate需要插入&更新第一种情况,只在第二种情况下插入查询?请解释。

在第一个使用@JoinColumn的版本中,需要先持久化Part,然后再持久化Product,例如:

Part part1 = new Part()
Part part2 = new Part()
em.persist(part1)
em.persist(part2)
Product product = new Product()
product.parts.add(part1)
product.parts.add(part2)
em.persist(product)

当持久化part1part2时,Hibernate为Part生成insert SQL。Hibernate不知道Productid是什么,所以PRODUCT_ID列将为空。

当持久化product时,Hibernate为Product生成insert SQL。现在Hibernate知道为Product生成的id是什么了。然后Hibernate发出update SQL,通过为PRODUCT_ID列设置适当的值来更新Part的现有记录。

在使用mappedBy的第二个版本中,您像这样持久化它们:

Customer customer = new Customer()
em.persist(customer)
Order order1 = new Order()  // using `Order` as entity name is not always valid because `Order` it is often confused with SQL clause
order1.setCustomer(customer)
em.persist(order1)
Order order2 = new Order()
order2.setCustomer(customer)
em.persist(order2)

区别在于当您持久化order1order2时,您告诉Hibernate Order对应的Customer是什么。相关客户的id保存在每个订单中。

如果你想拥有类似@JoinColumn的第一个版本,但没有额外的更新SQL,你可以使用@ElementCollection,例如:

@Entity
public class Product {
  @Id @GeneratedValue
  String serialNumber;
  @ElementCollection
  Set<Part> parts = new HashSet<Part>();
}
@Entity
public class Part {
    @Id @GeneratedValue
    int id;
    String partName;
}

上面的映射将生成一个额外的关系表,如product_part

最新更新