两个 类 之间存在多重关联的 Hibernate 问题
Hibernate problems with multiple associations between two classes
我在 Playframework 1.2.4 中使用 Hibernate。
我有两个 classes:Examination 和 Question。 Question 总是有一个指向 Examination 的属性。 Examination 总是有一个引用名为 specialQuestion 的问题的属性和一个引用问题集合的属性。
我的目标是创建一个对每个人都有影响的特殊问题的考试。当我创建考试时,我创建了这个特殊问题。问题创建好并保存在数据库中,考试也保存了但没有引用特殊问题,匹配列为空。
我不确定注释。有什么问题?
这个静态方法returns一个默认的特殊问题
public static Question specialQuestion(Examination examination) {
Question question = new Question();
question.examination = examination;
/* Other attributes affectations */
return question;
}
这里它创建了 Examination,影响了 specialQuestion 属性并持久化了对象:
Examination examination = new Examination();
examination.specialQuestion = Question.specialQuestion(examination);
examination.save();
Class考试包含那些属性:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "examination", fetch = FetchType.LAZY)
public Set<Question> questions = new HashSet<Question>();
@OneToOne(cascade= CascadeType.ALL, mappedBy = "examination")
public Question specialQuestion;
Class 问题包含:
@ManyToOne
@OneToOne
public Examination examination;
编辑:
如果删除 specialQuestion @OneToOne
注释中的 mappedBy
和问题 class 中检查的 @OneToOne
注释,我得到错误:我无法加载实体检查不再。
以下是 DDL 的重要部分:
CREATE TABLE `question` (
`questionId` bigint(20) NOT NULL AUTO_INCREMENT,
`examination_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`questionId`),
KEY `FKBE5CA006E00B1456` (`examination_id`)
) ENGINE=MyISAM AUTO_INCREMENT=204 DEFAULT CHARSET=latin1;
CREATE TABLE `examination` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`specialQuestion` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
您不能将 @ManyToOne
和 @OneToOne
添加到同一个 属性,因为 Hibernate 需要知道哪个是真的。
并且由于拥有方是 Question
Hibernate 应该如何知道哪些问题是特殊问题?从数据库的角度考虑:将关系存储在问题 table 中,您最终会得到多个引用同一考试的问题。如果这些是无序的(一组),you 如何根据可用数据确定特殊问题?
因为你不能这样做,Hibernate 也不会这样做。
要解决此问题,您需要使 Examination
成为 specialQuestion
的拥有方,并且可能也只是一个单向关系,即您不将其映射到 Question
(删除mappedBy
并添加一列作为对考试的参考 table).
您可以通过创建一个额外的实体来做到这一点,该实体本质上将充当考试和问题之间的 'join' 实体。这将使您可以灵活地将同一问题分配给多个考试,并为每个考试独立设置特殊问题。
因此,对于包含相同问题但具有不同特殊问题的两门考试,table 将如下所示:
╔════════════════════════════════╗
║ exam_id question_id is_special ║
╠════════════════════════════════╣
║ 1 1 0 ║
║ 1 2 0 ║
║ 1 3 1 ║
║ 1 4 0 ║
║ 1 5 0 ║
║ 2 1 1 ║
║ 2 2 0 ║
║ 2 3 0 ║
║ 2 4 0 ║
║ 2 5 0 ║
╚════════════════════════════════╝
三个实体的基本映射如下:
@Entity
public class Examination{
@Id
private int id;
@OneToMany(mappedBy = "examination")
private Set<ExaminationQuestion> examQuestions;
public Set<Question> getNormalQuestions(){
Set<Question> questions = new HashSet<>();
for(ExaminationQuestion eq: examQuestions){
if(! eq.getQuestion.isSpecialQuestion()){
questions.add(eq.getQuestion());
}
}
return questions;
}
public Question getSpecialQuestion(){
Question specialQuestion = null;
for(ExaminationQuestion eq: examQuestions){
if(eq.getQuestion.isSpecialQuestion()){
specialQuestion = eq.getQuestion();
break;
}
}
return specialQuestion;
}
}
@Entity
public class ExaminationQuestion{
@Id
private int id;
@ManyToOne
private Examination examination;
@ManyToOne
private Questions question;
private boolean specialQuestion;
}
@Entity
public class Question{
@Id
private int id;
@OneToMany(mappedBy = "question")
private Set<ExaminationQuestion> examQuestions;
}
我根据 Thomas 的回答找到了解决方案:
不修改架构,类 变成
Class 问题:
@OneToOne
@JoinColumn(name = "examination_id")
public Examination examination;
Class考试:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "examination", fetch = FetchType.LAZY)
public Set<Question> questions = new HashSet<Question>();
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "specialQuestion")
public Question specialQuestion;
我在 Playframework 1.2.4 中使用 Hibernate。
我有两个 classes:Examination 和 Question。 Question 总是有一个指向 Examination 的属性。 Examination 总是有一个引用名为 specialQuestion 的问题的属性和一个引用问题集合的属性。
我的目标是创建一个对每个人都有影响的特殊问题的考试。当我创建考试时,我创建了这个特殊问题。问题创建好并保存在数据库中,考试也保存了但没有引用特殊问题,匹配列为空。
我不确定注释。有什么问题?
这个静态方法returns一个默认的特殊问题
public static Question specialQuestion(Examination examination) {
Question question = new Question();
question.examination = examination;
/* Other attributes affectations */
return question;
}
这里它创建了 Examination,影响了 specialQuestion 属性并持久化了对象:
Examination examination = new Examination();
examination.specialQuestion = Question.specialQuestion(examination);
examination.save();
Class考试包含那些属性:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "examination", fetch = FetchType.LAZY)
public Set<Question> questions = new HashSet<Question>();
@OneToOne(cascade= CascadeType.ALL, mappedBy = "examination")
public Question specialQuestion;
Class 问题包含:
@ManyToOne
@OneToOne
public Examination examination;
编辑:
如果删除 specialQuestion @OneToOne
注释中的 mappedBy
和问题 class 中检查的 @OneToOne
注释,我得到错误:我无法加载实体检查不再。
以下是 DDL 的重要部分:
CREATE TABLE `question` (
`questionId` bigint(20) NOT NULL AUTO_INCREMENT,
`examination_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`questionId`),
KEY `FKBE5CA006E00B1456` (`examination_id`)
) ENGINE=MyISAM AUTO_INCREMENT=204 DEFAULT CHARSET=latin1;
CREATE TABLE `examination` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`specialQuestion` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
您不能将 @ManyToOne
和 @OneToOne
添加到同一个 属性,因为 Hibernate 需要知道哪个是真的。
并且由于拥有方是 Question
Hibernate 应该如何知道哪些问题是特殊问题?从数据库的角度考虑:将关系存储在问题 table 中,您最终会得到多个引用同一考试的问题。如果这些是无序的(一组),you 如何根据可用数据确定特殊问题?
因为你不能这样做,Hibernate 也不会这样做。
要解决此问题,您需要使 Examination
成为 specialQuestion
的拥有方,并且可能也只是一个单向关系,即您不将其映射到 Question
(删除mappedBy
并添加一列作为对考试的参考 table).
您可以通过创建一个额外的实体来做到这一点,该实体本质上将充当考试和问题之间的 'join' 实体。这将使您可以灵活地将同一问题分配给多个考试,并为每个考试独立设置特殊问题。
因此,对于包含相同问题但具有不同特殊问题的两门考试,table 将如下所示:
╔════════════════════════════════╗
║ exam_id question_id is_special ║
╠════════════════════════════════╣
║ 1 1 0 ║
║ 1 2 0 ║
║ 1 3 1 ║
║ 1 4 0 ║
║ 1 5 0 ║
║ 2 1 1 ║
║ 2 2 0 ║
║ 2 3 0 ║
║ 2 4 0 ║
║ 2 5 0 ║
╚════════════════════════════════╝
三个实体的基本映射如下:
@Entity
public class Examination{
@Id
private int id;
@OneToMany(mappedBy = "examination")
private Set<ExaminationQuestion> examQuestions;
public Set<Question> getNormalQuestions(){
Set<Question> questions = new HashSet<>();
for(ExaminationQuestion eq: examQuestions){
if(! eq.getQuestion.isSpecialQuestion()){
questions.add(eq.getQuestion());
}
}
return questions;
}
public Question getSpecialQuestion(){
Question specialQuestion = null;
for(ExaminationQuestion eq: examQuestions){
if(eq.getQuestion.isSpecialQuestion()){
specialQuestion = eq.getQuestion();
break;
}
}
return specialQuestion;
}
}
@Entity
public class ExaminationQuestion{
@Id
private int id;
@ManyToOne
private Examination examination;
@ManyToOne
private Questions question;
private boolean specialQuestion;
}
@Entity
public class Question{
@Id
private int id;
@OneToMany(mappedBy = "question")
private Set<ExaminationQuestion> examQuestions;
}
我根据 Thomas 的回答找到了解决方案:
不修改架构,类 变成
Class 问题:
@OneToOne
@JoinColumn(name = "examination_id")
public Examination examination;
Class考试:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "examination", fetch = FetchType.LAZY)
public Set<Question> questions = new HashSet<Question>();
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "specialQuestion")
public Question specialQuestion;