JPA 2.0 molti-a-molti con colonna aggiuntiva

Sto provando a fare una relazione ManyToMany in JPA 2.0 (JBoss 7.1.1) con una colonna in più (in grassetto, sotto) nella relazione, come:

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

Non vorrei avere attributi duplicati, quindi vorrei applicare la seconda soluzione presentata in http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table -with-extra-column-using-jpa / . Ma non riesco a farlo funzionare, ottengo diversi errori come:

  1. La class ID incorporata non dovrebbe contenere i mapping delle relazioni (infatti le specifiche lo dicono);
  2. Nell’attributo “employerDeliveryAgent”, il valore “mappato da” “pk.deliveryAgent” non può essere risolto con un attributo sull’ quadro di destinazione;
  3. Nell’attributo “employerDeliveryAgent”, il valore “mappato da” “pk.employer” non può essere risolto con un attributo sull’ quadro di destinazione;
  4. Il tipo persistente di attributo override “pk.deliveryAgent” non può essere risolto;
  5. Il tipo persistente di attributo override “pk.employer” non può essere risolto;

Molte persone su quel link hanno detto che ha funzionato bene, quindi suppongo che qualcosa sia diverso nel mio ambiente, forse nella versione JPA o Hibernate. Quindi la mia domanda è: come faccio a raggiungere questo scenario con JPA 2.0 (Jboss 7.1.1 / usando Hibernate come implementazione JPA)? E per completare questa domanda: dovrei evitare di utilizzare le chiavi composite e utilizzare invece l’ID generato in modo semplice e un vincolo univoco?

Grazie in anticipo.

Obs .: Non ho copiato il mio codice sorgente qui perché è essenzialmente una copia di quello al link sopra, solo con classi e nomi di attributi diversi, quindi immagino che non sia necessario.

Prima di tutto È necessario generare una class EmployerDeliveryAgentPK perché ha un PK multiplo:

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

Successivamente, è necessario creare una class EmployerDeliveryAgent . Questa class rappresenta una tabella molti a molti di Employer e 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; } 

Dopodiché, nella class Employer devi aggiungere:

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

E nella class DeliveryAgent è necessario aggiungere:

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

Questo è tutto! In bocca al lupo!!

Entrambe le risposte di Eric Lucio e Renan hanno aiutato, ma l’uso degli id ​​nella tabella delle associazioni è ridondante. Hai sia le entity framework associate che i loro id nella class. Questo non è richiesto. È ansible mappare l’entity framework associata nella class di associazione con la @Id nel campo quadro associata.

 @Entity public class Employer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @OneToMany(mappedBy = "employer") private List deliveryAgentAssoc; // other properties and getters and setters } @Entity public class DeliveryAgent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @OneToMany(mappedBy = "deliveryAgent") private List employerAssoc; // other properties and getters and setters } 

La class di associazione

 @Entity @Table(name = "employer_delivery_agent") @IdClass(EmployerDeliveryAgentId.class) public class EmployerDeliveryAgent { @Id @ManyToOne @JoinColumn(name = "employer_id", referencedColumnName = "id") private Employer employer; @Id @ManyToOne @JoinColumn(name = "delivery_agent_id", referencedColumnName = "id") private DeliveryAgent deliveryAgent; @Column(name = "is_project_lead") private boolean isProjectLead; } 

Ancora bisogno della class PK dell’associazione. Si noti che i nomi dei campi dovrebbero corrispondere esattamente ai nomi dei campi nella class di associazione, ma i tipi dovrebbero essere il tipo dell’ID nel tipo associato.

 public class EmployerDeliveryAgentId implements Serializable { private int employer; private int deliveryAgent; // getters/setters and most importantly equals() and hashCode() } 

OK, ho capito che funziona sulla base della soluzione disponibile su

http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany#Mapping_a_Join_Table_with_Additional_Columns .

Questa soluzione non genera attributi duplicati sul database, ma genera attributi duplicati nelle mie entity framework JPA (il che è molto accettabile, dal momento che è ansible inoltrare il lavoro aggiuntivo a un costruttore o un metodo – che diventa trasparente). Le chiavi primarie e quelle esterne generate nel database sono corrette al 100%.

Come indicato sul link, non ho potuto utilizzare @PrimaryKeyJoinColumn e invece ho usato @JoinColumn (name = “projectId”, updatable = false, insertable = false, referencedColumnName = “id”). Un’altra cosa degna di nota: ho dovuto usare EntityManager.persist (associazione), che manca nell’esempio al collegamento.

Quindi la mia soluzione finale è:

 @Entity public class Employee { @Id private long id; ... @OneToMany(mappedBy="employee") private List projects; ... } @Entity public class Project { @PersistenceContext EntityManager em; @Id private long id; ... @OneToMany(mappedBy="project") private List employees; ... // Add an employee to the project. // Create an association object for the relationship and set its data. public void addEmployee(Employee employee, boolean teamLead) { ProjectAssociation association = new ProjectAssociation(); association.setEmployee(employee); association.setProject(this); association.setEmployeeId(employee.getId()); association.setProjectId(this.getId()); association.setIsTeamLead(teamLead); em.persist(association); this.employees.add(association); // Also add the association object to the employee. employee.getProjects().add(association); } } @Entity @Table(name="PROJ_EMP") @IdClass(ProjectAssociationId.class) public class ProjectAssociation { @Id private long employeeId; @Id private long projectId; @Column(name="IS_PROJECT_LEAD") private boolean isProjectLead; @ManyToOne @JoinColumn(name = "employeeId", updatable = false, insertable = false, referencedColumnName = "id") private Employee employee; @ManyToOne @JoinColumn(name = "projectId", updatable = false, insertable = false, referencedColumnName = "id") private Project project; ... } public class ProjectAssociationId implements Serializable { private long employeeId; private long projectId; ... public int hashCode() { return (int)(employeeId + projectId); } public boolean equals(Object object) { if (object instanceof ProjectAssociationId) { ProjectAssociationId otherId = (ProjectAssociationId) object; return (otherId.employeeId == this.employeeId) && (otherId.projectId == this.projectId); } return false; } }