hibernatejpaormjpa-2.0

JPA 2.0 many-to-many with extra column


I'm trying to do a ManyToMany relationship in JPA 2.0 (JBoss 7.1.1) with an extra column (in bold, below) in the relationship, like:

Employer           EmployerDeliveryAgent             DeliveryAgent
(id,...)   (employer_id, deliveryAgent_id, **ref**)  (id,...)

I wouldn't like to have duplicate attributes, so I would like to apply the second solution presented in http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/ . But I can't get it to work, I get several errors like:

  1. Embedded ID class should not contain relationship mappings (in fact the spec says so);
  2. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.deliveryAgent' cannot be resolved to an attribute on the target entity;
  3. In attribute 'employerDeliveryAgent', the "mapped by" value 'pk.employer' cannot be resolved to an attribute on the target entity;
  4. Persistent type of override attribute "pk.deliveryAgent" cannot be resolved;
  5. Persistent type of override attribute "pk.employer" cannot be resolved;

Many people on that link said that it worked fine, so I suppose something is different in my environment, perhaps JPA or Hibernate version. So my question is: how do I achieve such scenario with JPA 2.0 (Jboss 7.1.1 / using Hibernate as JPA implementation)? And to complement that question: should I avoid using composite keys and instead use plain generated id and a unique constraint?

Thanks in advance.

Obs.: I didn't copy my source code here because it is essentially a copy of the one at the link above, just with different classes and attributes names, so I guess it is not necessary.


Solution

  • First of all You need to generate a EmployerDeliveryAgentPK class because It has a multiple PK:

    @Embeddable
    public class EmployerDeliveryAgentPK implements Serializable {
    
        @Column(name = "EMPLOYER_ID")
        private Long employer_id;
    
        @Column(name = "DELIVERY_AGENT_ID")
        private Long deliveryAgent_id;
    }
    

    Next, You need to create a EmployerDeliveryAgent class. This class represent the relation many to many between Employer and DeliveryAgent:

    @Entity
    @Table(name = "EmployerDeliveryAgent")
    public class EmployerDeliveryAgent implements Serializable {
    
        @EmbeddedId
        private EmployerDeliveryAgentPK id;
    
        @ManyToOne
        @MapsId("employer_id") //This is the name of attr in EmployerDeliveryAgentPK class
        @JoinColumn(name = "EMPLOYER_ID")
        private Employer employer;
    
        @ManyToOne
        @MapsId("deliveryAgent_id")
        @JoinColumn(name = "DELIVERY_AGENT_ID")
        private DeliveryAgent deliveryAgent;    
    }
    

    After that, in Employer class You need to add:

        @OneToMany(mappedBy = "deliveryAgent")
        private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();
    

    And in DeliveryAgent class You need to add:

        @OneToMany(mappedBy = "employer")
        private Set<EmployerDeliveryAgent> employer = new HashSet<EmployerDeliveryAgent>();
    

    This is all! Good luck!!