何时在JPA中使用一对多或多对一

时间:2015-11-17 02:35:18

标签: java jpa

让我们说我正在开发一个像strawpoll.me这样的民意调查应用。是否最好创建我的poll bean以包含一个选项或选项列表,以便与单个轮询具有多对一关系?此外,在提交表单以创建轮询时,数据库是否知道将OPTION表中的外键自动分配给它们所属的轮询的POLL_ID?我知道JPA使数据库交互变得简单,但是我找不到任何同时添加一对多/多对一关系的对象的例子。:

@Entity
@Table(name="POLL")
public class Poll implements Serializable{

  @Id
  @Column(name="POLL_ID")
  @GeneratedValue
  private int id;

  @Column(name="QUESTION_TEXT")
  private String question;

  @Column(name="CREATED_ON")
  private Timestamp dateCreated;

  @OneToMany
  @JoinColumn(name="OPTION_ID")
  private List<Option> options = new ArrayList<Option>();
}

@Entity
@Table(name="OPTION")
public class Option implements Serializable{

  @Id
  @Column(name="OPTION_ID")
  @GeneratedValue
  private int id;

  @Column(name="OPTION_TEXT")
  private String optionText;

  @Column(name="NUM_OF_VOTES")
  private int numOfVotes;
}

或设置如下:

@Entity
@Table(name="POLL")
public class Poll implements Serializable{

  @Id
  @Column(name="POLL_ID")
  @GeneratedValue
  private int id;

  @Column(name="QUESTION_TEXT")
  private String question;

  @Column(name="CREATED_ON")
  private Timestamp dateCreated;
}

@Entity
@Table(name="OPTION")
public class Option implements Serializable{

  @Id
  @Column(name="OPTION_ID")
  @GeneratedValue
  private int id;

  @ManyToOne
  @Column(name="POLL_ID")
  private Poll poll;

  @Column(name="OPTION_TEXT")
  private String optionText;

  @Column(name="NUM_OF_VOTES")
  private int numOfVotes;
}

3 个答案:

答案 0 :(得分:2)

(我认为其他2个答案还有改进空间,我正在给我的答案)

你要做的事实上很常见。它通常被称为双向一对多关系。在你的情况下,它应该看起来像:

class Poll {
    //....
    @OneToMany(mappedBy="poll")
    private Set<Option> options;
}

class Option {
    //...
    @ManyToOne
    @JoinColumn("poll_id")  // I always like to be explicit on naming :P
    private Poll poll;
}

这为您提供了更直观的模型。它允许您从两侧导航(例如在HQL中)。

一个混乱通常是:Hibernate将用于维护DB中的关系的哪一方?在Hibernate中,应该有一方“拥有”一种关系(我们上面展示的是一种关系,虽然是双向的)。如果双方都有@JoinColumn,Hibernate会抱怨。在上面的例子中,通过使用mappedBy,Hibernate知道它是拥有这种关系的Option方。如果Poll侧和Option侧不一致,您可以看到差异(例如,您的Poll-1包含Option-1,但Option-1指向Poll-2,而Poll-2不是包含Option-1。结果是,Option表将引用Poll-2

你应该注意一些陷阱。以上关于“拥有关系”的描述仅仅是在ORM方面。如果您未在模型中正确维护关系,则模型可能会变得不一致,如果您在同一会话中更改它们,则会出现问题。您有义务确保关系一致。

答案 1 :(得分:0)

必须是:

@Entity
@Table(name="POLL")
public class Poll implements Serializable{

  @Id
  @Column(name="POLL_ID")
  @GeneratedValue
  private int id;

  @Column(name="QUESTION_TEXT")
  private String question;

  @Column(name="CREATED_ON")
  private Timestamp dateCreated;

  @OneToMany(mappedBy="poll")
  private List<Option> options;
}

@Entity
@Table(name="OPTION")
public class Option implements Serializable{

  @Id
  @Column(name="OPTION_ID")
  @GeneratedValue
  private int id;

  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="POLL_ID")
  private Poll poll;

  @Column(name="OPTION_TEXT")
  private String optionText;

  @Column(name="NUM_OF_VOTES")
  private int numOfVotes;
}

答案 2 :(得分:0)

JPA知道哪个表通过实体名称与它挂钩。如果您有一个Option实体,并且您的Poll实体包含List<Option>,则JPA知道如何将一个实体映射到另一个实体。

你不必管理双方的关系;如果您向Option添加Poll并保留Poll,则Option也会更新。您无需进入Option设置其Poll,只要您在再次使用数据源之前刷新Option即可。

我更喜欢管理多对一方,因为在逐个案例的基础上告诉子实体它属于哪个父级是不那么复杂。否则,例如,向Set<Option>添加新条目将需要从数据源检索整个Set(用于比较集合是否已包含它),同时告诉{ {1}}它所属的Option只需要更新一个对象。