Reputation: 21445
I am trying to understand the differences in the DML queries generated if I use @JoinColumn compared to mappedBy attribute of @OneToMany mapping in Hibernate.
If I have my java classes defined as:
@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;
}
Then id I save a Product and Parts then hibernate generates inserts and also update queries:
Hibernate: insert into Product (serialNumber) values (?)
Hibernate: insert into Part (partName, id) values (?, ?)
Hibernate: update Part set PRODUCT_ID=? where id=?
Now if I have my java classes defined as:
@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();
}
}
Then Hibernate generates only insert queries without any updates:
Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TBL_ORDER (customer_id, orderNumber, id) values (?, ?, ?)
If my relationship between entities is only one-to-many then why hibernate needs insert & updates for first case and only insert queries in second case? Please explain.
Upvotes: 1
Views: 1707
Reputation: 1758
In the first version that uses @JoinColumn
, you need to persist Part
first before Product
, for example:
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)
When persisting part1
and part2
, Hibernate generates insert SQL for Part
. Hibernate doesn't know what is the id
for Product
yet so PRODUCT_ID
column will be null.
When persisting product
, Hibernate generates insert SQL for Product
. Now Hibernate knows what is the generated id
for Product
. Hibernate then issue update SQL to update existing record for Part
by setting the appropriate value for PRODUCT_ID
column.
In the second version that uses mappedBy
, you're persisting them like:
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)
The difference is when you persisting order1
and order2
, you're telling Hibernate what is the Customer
for that Order
. The id for the related customer is saved in each orders.
If you want to have something like the first version with @JoinColumn
but without extra updates SQL, you can use @ElementCollection
, for example:
@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;
}
The mapping above will generate an extra relation table such as product_part
.
Upvotes: 1