views:

375

answers:

2

Q 1) How can we model a ternary relationship using Hibernate? For example, how can we model the ternary relationship presented here using Hibernate (or JPA)?

NOTE: I know that JPA 2 has added some constructs for building ternary relationships using maps. However, this question assumes JPA 1 or Hibernate 3.3.x and I don't like to use maps to model this.

ER Model


ER Model with ternary relationships replaced

Ideally I prefer my model to be like this:

class SaleAssistant {
Long id;
//...
}

class Customer {
Long id;
//...
}

class Product {
Long id;
//...
}

class Sale {
SalesAssistant soldBy;
Customer buyer;
Product product;
//...
}

Q 1.1)

How can we model this variation, in which each Sale item might have many Products?

class SaleAssistant {
Long id;
//...
}

class Customer {
Long id;
//...
}

class Product {
Long id;
//...
}

class Sale {
SalesAssistant soldBy;
Customer buyer;
Set<Product> products;
//...
}

Q 2) In general, how can we model n-ary, n >= 3 relationships with Hibernate?

Thanks in advance.

+2  A: 

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.

Pascal Thivent
Thank you for the response. But I am encountering a problem when I use this: 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();}Also, in the JoinColumn annotations, what column are "name" fields referring to? The target relations' pks or the sale table's own column names?
Bytecode Ninja
A: 

Are you using database generated primary keys for Customer, Product and SalesAssistant? That might cause an issue since it looks like you're trying to use the actual DB identities rather than letting Hibernate resolve the object references during actual persistence.

The embedded PK above looks odd to me personally but I've not had a chance to try it out. It seems like the columns are overlapping and clobbering each other.

I would think it sufficient to just have the ManyToOne references.

Also, turn on SQL statement debugging and see what's being sent to the DB.

pickles