让我们说我正在开发一个像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;
}
答案 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
只需要更新一个对象。