JPA 2.0 many-to-many with extra column

亡梦爱人 提交于 2019-11-26 20:22:28

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 many to many table of 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!!

Paul Samsotha

Both answers from Eric Lucio and Renan helped, but there use of the ids in the association table is redundant. You have both the associated entities and their ids in the class. This is not required. You can simple map the associated entity in the association class with the @Id on the associated entity field.

@Entity
public class Employer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @OneToMany(mappedBy = "employer")
    private List<EmployerDeliveryAgent> deliveryAgentAssoc;

    // other properties and getters and setters
}

@Entity
public class DeliveryAgent {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @OneToMany(mappedBy = "deliveryAgent")
    private List<EmployerDeliveryAgent> employerAssoc;

    // other properties and getters and setters
}

The association class

@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;
}

Still need the association PK class. Notice the fields names should correspond exactly to the field names in the association class, but the types should be the type of the id in the associated type.

public class EmployerDeliveryAgentId implements Serializable {

    private int employer;
    private int deliveryAgent;

    // getters/setters and most importantly equals() and hashCode()
}
Renan

OK, I got it working based on the solution available at

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

This solution does not generate duplicate attributes on the database, but it does generate duplicate attributes in my JPA entities (which is very acceptable, since you can relay the extra work to a constructor or method - it ends up being transparent). The primary and foreign keys generated in the database are 100% correct.

As stated on the link, I couldn't use @PrimaryKeyJoinColumn and instead used @JoinColumn(name = "projectId", updatable = false, insertable = false, referencedColumnName = "id"). Another thing worth mentioning: I had to use EntityManager.persist(association), which is missing on the example at the link.

So my final solution is:

@Entity
public class Employee {
  @Id
  private long id;
  ...
  @OneToMany(mappedBy="employee")
  private List<ProjectAssociation> projects;
  ...
}
@Entity
public class Project {

  @PersistenceContext
  EntityManager em;

  @Id
  private long id;
  ...
  @OneToMany(mappedBy="project")
  private List<ProjectAssociation> 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;
  }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!