Learner
Learner

Reputation: 21445

Hibernate queries for @JoinColumn and mappedBy

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

Answers (1)

jocki
jocki

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 Partby 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

Related Questions