带有额外列的JPA 2.0多对多

Ren*_*nan 18 orm hibernate java-ee jpa-2.0 jboss7.x

我试图在JPA 2.0(JBoss 7.1.1)中创建一个ManyToMany关系,并在关系中添加一个额外的列(粗体,下面),例如:

Employer           EmployerDeliveryAgent             DeliveryAgent
(id,...)   (employer_id, deliveryAgent_id, **ref**)  (id,...)
Run Code Online (Sandbox Code Playgroud)

我不希望有重复的属性,所以我想应用http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table中提供的第二个解决方案.-with-column-using-jpa /.但我不能让它工作,我得到几个错误,如:

  1. 嵌入式ID类不应包含关系映射(实际上规范是这样说的);
  2. 在属性'employerDeliveryAgent'中,"映射的"值'pk.deliveryAgent'无法解析为目标实体上的属性;
  3. 在属性'employerDeliveryAgent'中,"映射的"值'pk.employer'无法解析为目标实体上的属性;
  4. 持久类型的覆盖属性"pk.deliveryAgent"无法解析;
  5. 持久性类型的覆盖属性"pk.employer"无法解析;

该链接上的许多人说它工作正常,所以我想在我的环境中有些不同,可能是JPA或Hibernate版本.所以我的问题是:如何使用JPA 2.0(Jboss 7.1.1 /使用Hibernate作为JPA实现)实现这样的场景?并补充这个问题:我应该避免使用复合键,而是使用普通生成的id和唯一约束吗?

提前致谢.

Obs.:我没有在这里复制我的源代码,因为它本质上是上面链接中的一个副本,只是具有不同的类和属性名称,所以我想这没有必要.

Pau*_*tha 40

Eric LucioRenan的答案都有所帮助,但在关联表中使用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
}
Run Code Online (Sandbox Code Playgroud)

关联类

@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;
}
Run Code Online (Sandbox Code Playgroud)

还需要关联PK类.请注意,字段名称应与关联类中的字段名称完全对应,但类型应为关联类型中的id类型.

public class EmployerDeliveryAgentId implements Serializable {

    private int employer;
    private int deliveryAgent;

    // getters/setters and most importantly equals() and hashCode()
}
Run Code Online (Sandbox Code Playgroud)

  • 任何人都可以提供插入或删除示例。 (3认同)
  • 这是您可以获得的最干净的解决方案,做得很好。 (2认同)
  • 为什么需要 id 类? (2认同)

Eri*_*cio 36

首先你需要生成一个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;
}
Run Code Online (Sandbox Code Playgroud)

接下来,您需要创建一个EmployerDeliveryAgent类.这个类代表了多对多的表EmployerDeliveryAgent:

@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;    
}
Run Code Online (Sandbox Code Playgroud)

之后,在Employer课堂上你需要添加:

@OneToMany(mappedBy = "deliveryAgent")
    private Set<EmployerDeliveryAgent> employerDeliveryAgent = new HashSet<EmployerDeliveryAgent>();
Run Code Online (Sandbox Code Playgroud)

DeliveryAgent课堂上你需要添加:

@OneToMany(mappedBy = "employer")
        private Set<EmployerDeliveryAgent> employer = new HashSet<EmployerDeliveryAgent>();
Run Code Online (Sandbox Code Playgroud)

这是所有的了!祝好运!!


Ren*_*nan 10

好的,我根据可用的解决方案让它工作

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

此解决方案不会在数据库上生成重复的属性,但它确实在我的JPA实体中生成重复的属性(这是非常可接受的,因为您可以将额外的工作转发给构造函数或方法 - 它最终是透明的).数据库中生成的主键和外键是100%正确的.

如链接所述,我无法使用@PrimaryKeyJoinColumn而是使用@JoinColumn(name ="projectId",updatable = false,insertable = false,referencedColumnName ="id").另外值得一提的是:我必须使用EntityManager.persist(关联),这在链接上的示例中是缺失的.

所以我的最终解决方案是:

@Entity
public class Employee {
  @Id
  private long id;
  ...
  @OneToMany(mappedBy="employee")
  private List<ProjectAssociation> projects;
  ...
}
Run Code Online (Sandbox Code Playgroud)
@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);
  }
}
Run Code Online (Sandbox Code Playgroud)
@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;
  ...
}
Run Code Online (Sandbox Code Playgroud)
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;
  }

}
Run Code Online (Sandbox Code Playgroud)