I am writing a simple web application where I have a User entity and set of pre-defined questions to be answered by the User. The answers provided by the users for these questions would need to be stored against the userId and questionId. After a bit of googling and with the help of stackoverflow, I have designed the tables in the following way.
UserDetails(userId, userName)
QuestionMaster(questionId, question)
QuestionAnswer(userId, questionId, answer, date) PK(userId, questionId)
The Hibernate Entity classes:
UserDetails.class
@Entity
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "user")
public class UserDetails {
private int userId;
private String userName;
private Collection<QuestionAnswer> listOfAnswers = new HashSet<QuestionAnswer>();
@XmlElement (name = "answer", type=QuestionAnswer.class)
@OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.userDetails", cascade=CascadeType.ALL)
public Collection<QuestionAnswer> getListOfAnswers() {
return listOfAnswers;
}
public void setListOfAnswers(Collection<QuestionAnswer> listOfAnswers) {
this.listOfAnswers = listOfAnswers;
}
@XmlElement (name = "userId")
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
@XmlElement (name = "userName")
@Column(nullable=false)
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
QuestionMaster.class
@Entity
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name="question")
public class QuestionMaster {
private int questionId;
private String question;
private Collection<QuestionAnswer> listOfAnswers = new HashSet<QuestionAnswer>();
@OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.questionMaster", cascade=CascadeType.ALL)
public Collection<QuestionAnswer> getListOfAnswers() {
return listOfAnswers;
}
public void setListOfAnswers(Collection<QuestionAnswer> listOfAnswers) {
this.listOfAnswers = listOfAnswers;
}
@XmlElement(name="quesId")
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public int getQuestionId() {
return questionId;
}
public void setQuestionId(int questionId) {
this.questionId = questionId;
}
@XmlElement(name="ques")
@Column(unique=true, nullable=false)
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
}
QuestionAnswer.class (fixed the typo)
@Entity
@AssociationOverrides({
@AssociationOverride(name = "pk.questionMaster",
joinColumns = @JoinColumn(name = "QUESTIONID", nullable = false)),
@AssociationOverride(name = "pk.userDetails",
joinColumns = @JoinColumn(name = "USERID", nullable = false)) })
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "answer")
public class QuestionAnswer {
private String answer;
private Date date;
private QuestionAnswerId pk = new QuestionAnswerId();
@EmbeddedId
public QuestionAnswerId getPk() {
return pk;
}
@XmlElement (name = "question", type=QuestionMaster.class)
@Transient
public QuestionMaster getQuestionMaster(){
return getPk().getQuestionMaster();
}
public void setQuestionMaster(QuestionMaster questionMaster){
getPk().setQuestionMaster(questionMaster);
}
@Transient
public UserDetails getUserDetails(){
return getPk().getUserDetails();
}
public void setUserDetails(UserDetails userDetails){
getPk().setUserDetails(userDetails);
}
public void setPk(QuestionAnswerId pk) {
this.pk = pk;
}
@XmlElement(name="ans")
@Column(nullable=false)
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
@XmlElement(name="date")
@Temporal(TemporalType.DATE)
@Column(name = "DATE", nullable = false, length = 10)
public Date getDate() {
return date;
}
public void setDate(Date date){
this.date = date;
}
}
QuestionAnswerId.class
@Embeddable
public class QuestionAnswerId implements Serializable {
private QuestionMaster questionMaster;
private UserDetails userDetails;
@ManyToOne (cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public QuestionMaster getQuestionMaster() {
return questionMaster;
}
public void setQuestionMaster(QuestionMaster questionMaster) {
this.questionMaster = questionMaster;
}
@ManyToOne (cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public UserDetails getUserDetails() {
return userDetails;
}
public void setUserDetails(UserDetails userDetails) {
this.userDetails = userDetails;
}
}
Sample REST API output for: /rest/users/5
<user>
<userName>xyz</userName>
<userId>5</userId>
<answer>
<ans>xyz</ans>
<date>2013-12-18T00:00:00+05:30</date>
<question>
<ques>What is your name</quesId>
<quesId>5</quesId>
</question>
</answer>
<answer>
<ans>25</ans>
<date>2013-12-18T00:00:00+05:30</date>
<question>
<ques>What is your age</ques>
<quesId>6</quesId>
</question>
</answer>
</user>
You comments/suggestions on this database design will be highly appreciated. I am new to Hibernate and in the process the learning it. Please suggest whether there is a better way to design the user-question-answer relationship, so that the response XML looks more elegant.