我正在尝试在JPA 2.0(JBoss 7.1.1)中创建一个ManyToMany关系,并在关系中添加一个额外的列(粗体,下面),例如:
Employer EmployerDeliveryAgent DeliveryAgent
(id,...) (employer_id, deliveryAgent_id, **ref**) (id,...)
我不希望有重复的属性,所以我想应用http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/中提供的第二个解决方案。但我无法让它工作,我得到了几个错误,如:
该链接上的许多人说它工作正常,所以我想我的环境中有些不同,可能是JPA或Hibernate版本。所以我的问题是:如何使用JPA 2.0(Jboss 7.1.1 /使用Hibernate作为JPA实现)实现这样的场景?并补充这个问题:我应该避免使用复合键,而是使用普通生成的id和唯一约束吗?
提前致谢。
Obs。:我没有在这里复制我的源代码,因为它本质上是上面链接中的一个副本,只是有不同的类和属性名称,所以我想这是没有必要的。
答案 0 :(得分:36)
来自https://youtu.be/2B4992fh-pA和Eric Lucio的答案都有帮助,但关联表中使用的ID是多余的。您在类中拥有关联的实体和。这不是必需的。您可以使用关联实体字段上的@Id
简单地映射关联类中的关联实体。
@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
}
关联类
@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;
}
还需要关联PK类。请注意,字段名称应与关联类中的字段名称完全对应,但类型应该是关联类型中id的类型。
public class EmployerDeliveryAgentId implements Serializable {
private int employer;
private int deliveryAgent;
// getters/setters and most importantly equals() and hashCode()
}
答案 1 :(得分:34)
首先你需要生成一个EmployerDeliveryAgentPK
类,因为它有一个多PK:
@Embeddable
public class EmployerDeliveryAgentPK implements Serializable {
@Column(name = "EMPLOYER_ID")
private Long employer_id;
@Column(name = "DELIVERY_AGENT_ID")
private Long deliveryAgent_id;
}
接下来,您需要创建一个EmployerDeliveryAgent
类。此类代表Employer
和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;
}
之后,在Employer
课程中您需要添加:
@OneToMany(mappedBy = "deliveryAgent")
private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();
在DeliveryAgent
课程中您需要添加:
@OneToMany(mappedBy = "employer")
private Set<EmployerDeliveryAgent> employer = new HashSet<EmployerDeliveryAgent>();
这就是全部!祝你好运!!
答案 2 :(得分:10)
好的,我根据
提供的解决方案让它运转起来此解决方案不会在数据库上生成重复的属性,但它确实在我的JPA实体中生成重复的属性(这是非常可接受的,因为您可以将额外的工作转发给构造函数或方法 - 它最终是透明的)。数据库中生成的主键和外键是100%正确的。
如链接所述,我无法使用@PrimaryKeyJoinColumn而是使用@JoinColumn(name =&#34; projectId&#34;,updatable = false,insertable = false,referencedColumnName =&#34; id& #34)。另外值得一提的是:我不得不使用EntityManager.persist(association),这在链接上的示例中是缺失的。
所以我的最终解决方案是:
@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;
}
}