Q1. How can we model a ternary relationship using Hibernate? For example, how can we model the ternary relationship presented here using Hibernate (or JPA)? (...)
I would remodel the association with an intermediate entity class (and that's the recommended way with Hibernate). Applied to your example:
@Entity
public class Sale {
@Embeddable
public static class Pk implements Serializable {
@Column(nullable = false, updatable = false)
private Long soldById;
@Column(nullable = false, updatable = false)
private Long buyerId;
@Column(nullable = false, updatable = false)
private Long productId;
public Pk() {}
public Pk(Long soldById, Long buyerId, Long productId) { ... }
// getters, setters, equals, hashCode
}
@EmbeddedId
private Pk pk;
@ManyToOne
@JoinColumn(name = "SOLDBYID", insertable = false, updatable = false)
private SaleAssistant soldBy;
@ManyToOne
@JoinColumn(name = "BUYERID", insertable = false, updatable = false)
private Customer buyer;
@ManyToOne
@JoinColumn(name = "PRODUCTID", insertable = false, updatable = false)
private Product product;
// getters, setters, equals, hashCode
}
Q1.1. How can we model this variation, in which each Sale item might have many Products?
I wouldn't use a composite primary key here and introduce a PK for the Sale
entity.
Q2. In general, how can we model n-ary, n >= 3 relationships with Hibernate?
I think that my answer to Q1. covers this. If it doesn't, please clarify.
Update: Answering comments from the OP
(...) the pk's fields are not getting populated and as a result I cannot save Sale items in the DB. Should I use setters like this for the Sale class? public void setBuyer(Customer cust) { this.buyer = cust; this.pk.buyerId = cust.getId(); }
You need to create a new Pk
(I removed the constructors from my original answer for conciseness) and to set it on the Sale
item. I would do something like this:
Sale sale = new Sale();
Pk pk = new Pk(saleAssistant.getId(), customer.getId(), product.getId());
sale.setPk(pk);
sale.setSoldBy(saleAssistant);
sale.setBuyer(customer);
sale.setProduct(product);
...
And then persist the sale
.
Also, in the JoinColumn annotations, what column are "name" fields referring to? The target relations' pks or the sale table's own column names?
To the columns for the attributes of the composite Pk
(i.e. the sale table's own column names), we want them to get PK and FK constraints.