Java Persistence/ManyToMany – Wikibooks, open books for an open world.

A frequent problem is that two classes have a ManyToMany relationship, but the relational join table has additional data. For example if Employee has a ManyToMany with Project but the PROJ_EMP join table also has an IS_PROJECT_LEAD column. In this case the best solution is to create a class that models the join table. So a ProjectAssociation class would be created. It would have a ManyToOne to Employee and Project, and attributes for the additional data. Employee and Project would have a OneToMany to the ProjectAssociation. Some JPA providers also provide additional support for mapping to join tables with additional data.

Unfortunately mapping this type of model becomes more complicated in JPA because it requires a composite primary key. The association object’s Id is composed of the Employee and Project ids. The JPA 1.0 spec does not allow an Id to be used on a ManyToOne so the association class must have two duplicate attributes to also store the ids, and use an IdClass, these duplicate attributes must be kept in synch with the ManyToOne attributes. Some JPA providers may allow a ManyToOne to be part of an Id, so this may be simpler with some JPA providers. To make your life simpler, I would recommend adding a generated Id attribute to the association class. This will give the object a simpler Id and not require duplicating the Employee and Project ids.

This same pattern can be used no matter what the additional data in the join table is. Another usage is if you have a Map relationship between two objects, with a third unrelated object or data representing the Map key. The JPA spec requires that the Map key be an attribute of the Map value, so the association object pattern can be used to model the relationship.

If the additional data in the join table is only required on the database and not used in Java, such as auditing information, it may also be possible to use database triggers to automatically set the data.

Example join table association object database

EMPLOYEE (table)

ID FIRSTNAME LASTNAME
1 Bob Way
2 Sarah Smith

PROJ_EMP (table)

EMPLOYEEID PROJECTID IS_PROJECT_LEAD
1 1 true
1 2 false
2 1 false

PROJECT (table)

ID NAME
1 GIS
2 SIG

Example join table association object annotations

[java]@Entity
public class Employee {
@Id
private long id;

@OneToMany(mappedBy="employee")
private List<ProjectAssociation> projects;

}

@Entity
public class Employee {
@Id
private long id;

@OneToMany(mappedBy="employee")
private List<ProjectAssociation> projects;

}

@Entity
public class Project {
@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);

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
@PrimaryKeyJoinColumn(name="EMPLOYEEID", referencedColumnName="ID")
/* if this JPA model doesn’t create a table for the "PROJ_EMP" entity,
* please comment out the @PrimaryKeyJoinColumn, and use the ff:
* @JoinColumn(name = "employeeId", updatable = false, insertable = false)
* or @JoinColumn(name = "employeeId", updatable = false, insertable = false, referencedColumnName = "id")
*/
private Employee employee;
@ManyToOne
@PrimaryKeyJoinColumn(name="PROJECTID", referencedColumnName="ID")
/* the same goes here:
* if this JPA model doesn’t create a table for the "PROJ_EMP" entity,
* please comment out the @PrimaryKeyJoinColumn, and use the ff:
* @JoinColumn(name = "projectId", updatable = false, insertable = false)
* or @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;
}

}

[/java]

  • If the given examples won’t suit your expectations, try the solution indicated in this link:

http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/

2 Responses to Mapping a Join Table with Additional Columns
  1. reverse phone lookup free results I am no longer positive dagfkakedgkf

  2. you use disallowed a designer to make the style? Superb vocation! ecaekkcacbkg


[top]

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注