I currently have 3 tables Assessment, Question and QuestionOption. Each assessment has some questions and each question has some question options. Initially I started our with #OneToMany mappings for these but later one due to the fields that I have I had to had composite keys in Question so the entire mapping changed. I am not satisfied with the current state. Can someone help me in mapping the tables.
The main reason I had to do this was that while instering questions, I realised that question number can be the same across multiple assessments. So I made it a composite key with questionNumber+assessmentId. Also the same thought process with question option. where the same question options can exist along different questions. How can and avoid this and keep it simple.
Assessment
#Entity
#JsonIgnoreProperties({"questionList"})
public class Assessment {
#Id
private String assessmentId;
private String assessmentTopic;
private String assessmentSubTopic;
private String assessmentLevel;
private String createdBy;
private String rating;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "assessment", fetch = FetchType.LAZY)
private List<Question> questionList;
//Getters and setters
}
Question
#Entity
#Getter
#Setter
#JsonIgnoreProperties({"assessment"})
public class Question implements Serializable {
#EmbeddedId
private QuestionAssessmentKey questionAssessmentKey;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "assessmentId", insertable = false, updatable = false)
private Assessment assessment;
private String questionText;
private String questionURL;
private QuestionStatus questionStatus;
// private int questionNumber;
private QuestionTypes questionType;
//Getters and Setters
}
QuestionAssessmentKey- The composite key
#Embeddable
public class QuestionAssessmentKey implements Serializable {
private int questionNumber;
private String assessmentId;
//Getters and setters
}
QuestionOption
#Entity
public class QuestionOption {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int questionOptionId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="assessmentId", referencedColumnName = "assessmentId"),
#JoinColumn(name="questionNumber", referencedColumnName = "questionNumber")
})
private Question question;
private Character questionOption;
private String questionOptionText;
//Getters and Setters
}
Related
public class UserOUData {
#Id
private Long id;
private String UserEmail;
#OneToMany(mappedBy="usersId")
private Long orgUnitPathId;
}
#Entity
#Table(name="Ou")
public class OU {
#Id
private long id;
private String name;
private String path;
#ManyToOne
#JoinColumn(name="orgUnitPathId")
private Collection<UserOUData> usersId;
}
i have tried some of posible examples
but stil i am facing the issue
Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements: cloudcodes.schema.generator.model.UserOUData.orgUnitPathId
private Long orgUnitPathId;
#ManyToOne
#JoinColumn(name="orgUnitPathId")
private Collection<UserOUData> usersId;
can anyone help me out with this
thanks in advance.
You have one organizational unit which can have multiple users, so you need OneToMany relationship on the organization unit:
#Entity
#Table(name="Ou")
public class OU {
#Id
private long id;
private String name;
private String path;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "organizationalUnit")
private Collection<UserOUData> usersData;
}
For the UserOUData you need a ManyToOne, since multiple users can be part of the same OU:
#Entity
#Table(name="UserOUData")
public class UserOUData {
#Id
private Long id;
private String UserEmail;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ou_id")
private OU organizationalUnit;
}
This setup assumes that you would want to make the connection bidirectional between OU and UserOUData.
So I've been trying the solutions out there to map a ManyToMany relationship with extra columns but none of them is working for me and I don't know what am I doing wrong.
The Many to Many relationship is between Patient and Disease (a Patient can have multiple diseases and a Disease can be suffered by many Patients). The time attribute means "the type of the disease" (acute, chronic...)
My classes are:
#Entity
#Table(name="patient")
public class Patient{
#Id
#NotNull
#Column(name="nss")
private String NSS;
//Some attributes
#OneToMany(mappedBy = "patient")
private Set<PatientDisease> diseases = new HashSet<PatientDisease>();
//Empty constructor and constructor using fields omitted
//Getters and setters ommited
}
,
#Entity
#Table(name="disease")
public class Disease{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private Integer id;
#OneToMany(mappedBy = "disease")
private Set<PatientDisease> patients = new HashSet<PatientDisease>();
//Constructors and getters and setters ommited for brevity
}
Associated class
#Entity
#Table(name = "Patient_Disease")
#IdClass(PatientDiseaseID.class)
public class PatientDisease{
#Id
#ManyToOne(fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
#JoinColumn(name = "nssPatient", referencedColumnName = "id")
private Patient patient;
#Id
#ManyToOne(fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
#JoinColumn(name = "diseaseID", referencedColumnName = "id")
private Disease disease;
#Column(name="time")
private String time;
//GETTERS AND SETTERS OMMITED FOR BREVETY. Constructor NOT Needed following the example
}
The id class:
#Embeddable
public class PatientDiseaseId implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "nssPatient")
private String patient;
#Column(name = "diseaseID")
private Integer disease;
//getters and setters
//hashCode and equals
}
My main app:
...
List<Diseases> diseases = sesion.createQuery("from Disease").getResultList();
System.out.println("Diseases: ");
for(Disease d: diseases) {
System.out.println(d.getName());
for(PatientDisease pd: e.getPatientDisease()) {
System.out.println(pd.getPatient().toString());
}
}
...
When running the main App I get the exception on line 5 (2nd for loop):
Exception in thread "main" org.hibernate.PropertyAccessException: Could not set field value [1] value by reflection : [class entities.PatientDisease.diseases] setter of entities.PatientDisease.diseases
I have tried some solutions here in Stack Overflow an some others that I found on the Internet, but I can't get them to work and I don't know why
Because you are using #IdClass you don't need to annotate PatientDiseaseId with #Embedded and #Column. And you have to refer to the entities.
This is what it should look like:
public class PatientDiseaseId implements Serializable {
private static final long serialVersionUID = 1L;
private Patient patient;
private Disease disease;
//getters and setters
//hashCode and equals
}
I have 2 tables question and question option. Question has a composite key. When I query question by an id how do i get question options as well. How can I ensure that I getting the question options as well. As of now I'm only getting the questions. Should I change the mapping or should I add some properties
Question
#Entity
#Getter
#Setter
#JsonIgnoreProperties({"assessment"})
public class Question implements Serializable {
#EmbeddedId
private QuestionAssessmentKey questionAssessmentKey;
public QuestionAssessmentKey getQuestionAssessmentKey() {
return questionAssessmentKey;
}
public void setQuestionAssessmentKey(QuestionAssessmentKey questionAssessmentKey) {
this.questionAssessmentKey = questionAssessmentKey;
}
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "assessmentId", insertable = false, updatable = false)
private Assessment assessment;
private String questionText;
private String questionURL;
private QuestionStatus questionStatus;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name="assessmentId", referencedColumnName = "assessmentId"),
#JoinColumn(name="questionNumber", referencedColumnName = "questionNumber")
})
private List<QuestionOption> questionOptions;
public List<QuestionOption> getQuestionOptions() {
return questionOptions;
}
public void setQuestionOptions(List<QuestionOption> questionOptions) {
this.questionOptions = questionOptions;
}
public Assessment getAssessment() {
return assessment;
}
public void setAssessment(Assessment assessment) {
this.assessment = assessment;
}
// private int questionNumber;
private QuestionTypes questionType;
//Getters and setters
}
QuestionOptions
#Entity
public class QuestionOption {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int questionOptionId;
#ManyToOne
#JoinColumns({
#JoinColumn(name="assessmentId", referencedColumnName = "assessmentId"),
#JoinColumn(name="questionNumber", referencedColumnName = "questionNumber")
})
private Question question;
private Character questionOption;
//Getter and setter
}
QuestionAssessmentKey
#Embeddable
public class QuestionAssessmentKey implements Serializable {
private int questionNumber;
private String assessmentId;
}
AFAIK you cannot fetch all the data in a single query since it is a one-to-many relationship between questions and question options. However when you call getQuestionOptions on the fetched Question entity, it should load and return the corresponding set of options.
I have a quiz app in development under my belt, but I'm confused of getting schema design correct need help in this case please.
I've quiz, question, answer, and answerOptions Entities as following
quiz
#Entity
public class Quiz implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long quizId;
private String quizTitle;
#OneToMany(mappedBy = "quiz", fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
private Set<Question> questions = new HashSet<Question>();
#ManyToMany(mappedBy = "quizs", fetch = FetchType.EAGER, cascade = { CascadeType.REFRESH})
#JsonBackReference
private Set<History> histories = new HashSet<History>();
// omitting getters and setters
}
question
#Entity
public class Question implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long questionId;
private String questionText;
private Integer questionChoices;
private Integer questionNumbers;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "quizId")
private Quiz quiz;
#OneToMany(mappedBy = "question", cascade = { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.EAGER)
private Set<Option> options = new HashSet<Option>();
#OneToOne(cascade = {CascadeType.REFRESH, CascadeType.PERSIST})
#JoinColumn(name = "answerId")
private Answer answer;
// omitting getters and setters
}
answerOptions
#Entity
#Table(name="answerOptions")
public class Option implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long optionId;
private String optionText;
private static final long serialVersionUID = 1L;
#ManyToOne(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
#JoinColumn(name = "questionId")
private Question question;
// omitting getters and setters
}
, answer
#Entity
public class Answer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long answerId;
private String answerCorrect;
#OneToOne(mappedBy = "answer", cascade = CascadeType.ALL)
private Question question;
// omitting getters and setters
}
now every thing works good, but where should I save
Number of Correct Answers.
Number of Wrong Answers.
Result of quiz (Pass/Fail)
I have the following two classes, one ReqCandAssociation can have many Comments and it is mapped like so. I need to figure out a way that when I delete a ReqCandAssociation it deletes all of its associated comments. Thanks
#Entity
#Table(name = "candidate_jobReq")
public class ReqCandAssociation implements Serializable {
#Id
private Integer candidateId;
#Id
private Integer jobId;
#Column(name = "reqStatus")
private String reqStatus;
#ManyToOne
#PrimaryKeyJoinColumn(name="candidateId", referencedColumnName="id")
private Candidate candidate;
#ManyToOne
#PrimaryKeyJoinColumn(name="jobId", referencedColumnName="id")
private JobReq jobReq;
public ReqCandAssociation(){
}
Second class
#Entity
#Table(name="comment")
public class Comment {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="commentText")
private String commentText;
#Column(name="commentDate")
private Date commentDate;
#ManyToOne
#PrimaryKeyJoinColumn(name="reqCandAssociationId", referencedColumnName="id")
private ReqCandAssociation reqCandAssociation;
#ManyToOne
#PrimaryKeyJoinColumn(name="userId", referencedColumnName="id")
private User user;
Change this to the following, i'm making it bidirectional mapping.
#Entity
#Table(name = "candidate_jobReq")
public class ReqCandAssociation implements Serializable {
#Id
private Integer candidateId;
#Id
private Integer jobId;
#Column(name = "reqStatus")
private String reqStatus;
#OneToMany(cascade = { CascadeType.ALL }) //this is added here.
#JoinColumn(name ="reqCandAssociationId")
private Set<Comment> comments;
-----
Readup more on the cascade options. All cascade types are all|none|save-update|delete|all-delete-orphan|delete-orphan
The cascade all will delete all the comments associated to this class.