@JoinColumn is part of the composite primary keys

Whilst it is not very common (hmmm … , come to think of it, it may be quite common), there are cases where one would require the use of composite primary keys in JPA, but at the same time, one of the key is actually a foreign key to another parent table.

Let’s just say for example there are table CUSTOMER and PRODUCT (Smith 2007), in this case the PRODUCT uses composite primary key of PRIMARY KEY (customer_id, product_id).

In JPA, they are mapped as follows:

CUSTOMER

package com.wordpress.dwuysan;

// imports omitted

@Entity
@Table(name = "customer")
public class Customer implements Serializable {
    @Id
    @Column(name = "customer_id")
    private String customerId;

    @OneToMany(
        fetch = FetchType.EAGER,
        mappedBy = "customer")
    private Set<Product> products = new HashSet<Product>();

    /* the rest of the code omitted */
}

PRODUCTPK

package com.wordpress.dwuysan;

// imports omitted

@Embeddable
public class ProductPK implements Serializable {
    private String productId;
    private String customerId;

    /* the rest of the code omitted */
}

PRODUCT

package com.wordpress.dwuysan;

// imports omitted

@Entity
@Table(name = "product")
public class Product implements Serializable {

    @AttributeOverrides({
        @AttributeOverride(
            name = "customerId",
            column = @Column(name = "customer_id")),
        @AttributeOverride(
            name = "productId",
            column = @Column(name = "productId"))
    })
    private ProductPK productPK;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "customer_id")
    private Customer customer;
}

However, on compiling, I got the following error from JUnit:

Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.wordpress.dwuysan.Product column: customer_id (should be mapped with insert="false" update="false")
	at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:652)
	at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:674)
	at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:696)
	at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:450)
	at org.hibernate.mapping.RootClass.validate(RootClass.java:192)
	at org.hibernate.cfg.Configuration.validate(Configuration.java:1108)

So, to resolve this, we need to modify the Product class to:

PRODUCT

package com.wordpress.dwuysan;

// imports omitted

@Entity
@Table(name = "product")
public class Product implements Serializable {

    @AttributeOverrides({
        @AttributeOverride(
            name = "customerId",
            column = @Column(name = "customer_id")),
        @AttributeOverride(
            name = "productId",
            column = @Column(name = "productId"))
    })
    private ProductPK productPK;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "customer_id", insertable = false, updatable = false)
    private Customer customer;
}

Reference:
Smith, J, 2007, ‘Composite Primary Keys’, accessed 22 February 2012.

Advertisements