映射ManyToOne双向关系,其中一方具有复合主键

时间:2015-07-29 14:44:54

标签: java jpa orm

我有一个存储工作坊的实体,我正在使用复合主键。

我不喜欢自动生成密钥的概念,直到现在主要使用业务派生密钥,例如电子邮件ID等实体。然而,在这里,研讨会实体似乎没有主键的自然候选者,所以我选择了一个复合键。我创建了一个WorkshopIdType,这是一个包含将组织的三个可能的研讨会的枚举

public enum WorkshopIdType implements Serializable {

  FOUNDATION("FND"), INTERMEIDATE("IMT"), ADVANCED("ADV");

  private final String name;

  private WorkshopIdType(String name) {
    this.name = name;
  }

  @Override
  public String toString() {
    return this.name;
  }

  public boolean equals(String otherName) {
    return (otherName == null) ? false : name.equals(otherName);
  }
}

然后我有一个用于主键的Embeddable类;在这种情况下,工作室类型和日期的组合在我看来是最适合主键的

@Embeddable
@Access(AccessType.FIELD)
public class WorkshopId implements Serializable {

  private static final long serialVersionUID = -7287847106009163526L;

  private String workshopIdType;

  private Date date;

  @Column(name = "id", nullable = false)
  public String getWorkshopIdType() {
    return workshopIdType;
  }

  public void setWorkshopIdType(WorkshopIdType workshopIdType) {
    this.workshopIdType = workshopIdType.toString();
  }

  @Temporal(TemporalType.DATE)
  @Column(name = "date", nullable = false)
  public Date getDate() {
    return date;
  }

  public void setDate(Date date) {
    this.date = date;
  }
}

该实体与Venue之间也有一个ManyToOne关系,在这里,场地实际上是三个城市预先指定的中心中的5个

@Entity
public class Workshop implements Serializable {

  private static final long serialVersionUID = -5516160437873476233L;

  private WorkshopId id;

  private Venue venue;

  private Integer seatsAvailable;

  @EmbeddedId
  public WorkshopId getId() {
    return id;
  }

  public void setId(WorkshopId id) {
    this.id = id;
  }

  @ManyToOne
  @JoinTable(name = "workshop_venue", joinColumns = { @JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "venue_name", referencedColumnName = "name") })
  public Venue getVenue() {
    return venue;
  }

  public void setVenue(Venue venue) {
    this.venue = venue;
  }

  @Column(name = "seats_available", nullable = false)
  public Integer getSeatsAvailable() {
    return seatsAvailable;
  }

  public void setSeatsAvailable(Integer seatsAvailable) {
    this.seatsAvailable = seatsAvailable;
  }
}

问题是在复合键的情况下将此ManyToOne映射为JoinTable

@ManyToOne
  @JoinTable(name = "workshop_venue", joinColumns = { @JoinColumn(name = "workshop_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "venue_name", referencedColumnName = "name") })
  public Venue getVenue() {
    return venue;
  }

这不会像我所怀疑的那样工作,它找不到具有逻辑名称" id"的列。我将与JoinTable一起使用ManyToOne,因为可能存在用户应该知道是否有针对给定场地安排的培训的情况。在这种情况下如何指定referencedColumnName?

或者我在模拟它的方式上弄错了吗?

1 个答案:

答案 0 :(得分:0)

您有一个由嵌入式WorkshopId表示的复合主键  嵌入Workshop。主键的两个字段都需要连接到链接表中的目标实体 - 因此您需要2个joincolumns和一个inversejoin。您只需要添加缺少的连接;

  @ManyToOne
  @JoinTable(name = "workshop_venue", 
            joinColumns = 
                  { @JoinColumn(name = "workshop_id", referencedColumnName = "id"),
                    /* Add this joincolumn */ 
                    @JoinColumn(name = "date_id", referencedColumnName = "date") }, 
            inverseJoinColumns = 
                  { @JoinColumn(name = "venue_name", referencedColumnName = "name") })
  public Venue getVenue() {
    return venue;

当然,您需要确保链接表具有这三个字段。我猜你错过了date_id专栏。