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で提示されている2番目のソリューションを適用したいと思います。 -join-table-with-extra-column-using-jpa / 。しかし、私はそれを動作させることができません、私は次のようないくつかのエラーを受け取ります:
そのリンク上の多くの人々はそれがうまく働いたと言ったので、私はおそらく環境、JPAまたはHibernateバージョンで何かが違うと思います。私の質問は次のとおりです:JPA 2.0(Jboss 7.1.1/JPA実装としてHibernateを使用)でこのようなシナリオを達成するにはどうすればよいですか?そして、その質問を補完するために:複合キーの使用を避け、代わりに単純に生成されたIDと一意の制約を使用する必要がありますか?
前もって感謝します。
Obs .:私はここでソースコードをコピーしませんでした。なぜなら、それは本質的に上記のリンクにあるもののコピーであり、異なるクラスと属性名を持っているからです。
まず、複数のPKがあるため、EmployerDeliveryAgentPK
クラスを生成する必要があります。
@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>();
これですべてです!幸運を!!
Eric Lucio および Renan の両方の回答が役立ちましたが、アソシエーションテーブルでのIDの使用は冗長です。関連するエンティティとの両方の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()
}
OK、利用可能なソリューションに基づいて動作しました
このソリューションは、データベースに重複属性を生成しませんが、JPAエンティティに重複属性を生成します(余分な作業をコンストラクターまたはメソッドに中継できるため、これは非常に受け入れられます-透過的になります)。データベースで生成される主キーと外部キーは100%正しいです。
リンクに記載されているように、@ PrimaryKeyJoinColumnを使用できず、代わりに@JoinColumn(name = "projectId"、updatable = false、insertable = false、referencedColumnName = "id")を使用しました。言及する価値のある別のこと: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;
}
}