Java JPA:从实体到实体的hashmap在联接表中获取错误的主键
我正在尝试建立以下模型:Java JPA:从实体到实体的hashmap在联接表中获取错误的主键,java,sql,jpa,dictionary,eclipselink,Java,Sql,Jpa,Dictionary,Eclipselink,我正在尝试建立以下模型: 学生可以参加考试并获得分数。 应该可以将同一年级实体分配给多个学生。 成绩存储在地图(在“考试”类中)中,该地图的注释如下: @ManyToMany @MapKeyClass(value = Person.class) @JoinTable(name = "t1") private Map<Person, Grade> grades; 然而,我所期望的表将有一个主键,包括学生和考试。 我现在面临的问题是当我尝试以下方法时: grades.put(stude
学生可以参加考试并获得分数。
应该可以将同一年级实体分配给多个学生。
成绩存储在地图(在“考试”类中)中,该地图的注释如下:
@ManyToMany
@MapKeyClass(value = Person.class)
@JoinTable(name = "t1")
private Map<Person, Grade> grades;
然而,我所期望的表将有一个主键,包括学生和考试。我现在面临的问题是当我尝试以下方法时:
grades.put(student1, grade1);
grades.put(student2, grade1);
。。。我将收到一个异常,告诉我我违反了数据库约束。如何正确地持久化此映射 我使用eclipselink 2.6.0作为JPA提供者。应用程序运行在带有derby数据库的glassfish服务器上 感谢您的阅读,祝您度过愉快的一天:) 更新:
以下是用于创建数据库的SQL查询、eclipselink调用:
...
CREATE TABLE EXAM_GRADE (Exam_ID BIGINT NOT NULL, grades_ID BIGINT NOT NULL, grades_KEY BIGINT, PRIMARY KEY (Exam_ID, grades_ID))
...
ALTER TABLE EXAM_GRADE ADD CONSTRAINT EXAMGRADEgrades_ID FOREIGN KEY (grades_ID) REFERENCES GRADE (ID)
ALTER TABLE EXAM_GRADE ADD CONSTRAINT EXAMGRADEgradesKEY FOREIGN KEY (grades_KEY) REFERENCES PERSON (ID)
ALTER TABLE EXAM_GRADE ADD CONSTRAINT EXAM_GRADE_Exam_ID FOREIGN KEY (Exam_ID) REFERENCES EXAM (ID)
...
好吧,我们这里有几个问题:我在Hibernate上试过了,得到了不同的结果。我认为Hibernate做得很正确,因此我的第一个答案是更新 首先,你展示的代码不应该产生你正在得到的结果。当您声称
GRADES\u ID
是联接表中主键的一部分时,这不应该是真的。当我运行这个示例时,我得到了主键(考试id、成绩\u键)
其次,在你的成绩
字段中,你应该有OneToMany
关系,而不是ManyToMany
关系。当您为两名学生插入相同的分数时,拥有manytomy
关系不应导致违反约束。当您有一个OneToMany
关系时,将为unique(grades\u id)
创建一个约束,这确实会阻止您为两个学生插入相同的分数:
grades.put(student1, grade1);
grades.put(student2, grade1);
最好使用约束
,因为这样可以防止一个学生的成绩同时分配给另一个学生时出现编码错误
在考虑关系时,请考虑实体之间的关系。在这种情况下,您有一个考试
和许多学生
,因此您应该有一个一个域
最后,MapKeyClass
是多余的,没有很好的理由自己命名join表,尤其是t1
你们的关系应该很简单:
@OneToMany(fetch=FetchType.EAGER)
private Map<Student, Grade> grades;
并确保您首先坚持每个学生
和年级
(或制定适当的逻辑):
在我做了这些更改之后,我能够为不同的学生写和读相同的成绩
。这些模式脚本现在正是Hibernate生成它们的方式。我认为在Eclipselink上发生了一些有趣的事情,提交一个bug是个好主意。另外,请注意,虽然你可能想给不同的学生分配相同的分数,但这在问题领域没有意义,但这当然是我的拙见。我意识到一个JavaMap
可以有不同的键
引用相同的值
,因此对于一些Ecpliselink
似乎无法处理的问题来说,这当然是一个可以想象的要求。我希望能够为多个学生分配相同的分数,这就是为什么我用了很多。这就是为什么奇怪的主键约束会导致问题。我可以问一下您使用了哪个JPA提供商和哪个版本吗?我使用的是wildfly 9,这就是Hibernate核心{4.3.10.Final}。请参阅我的更新。我调低了我的第一个答案,在EclipseLink上尝试了一切,所以我明白了为什么你会遇到麻烦。你是如何让它在EclipseLink上工作的?我与OP有相同的问题。我还手动修改了我的模式,虽然我在插入时没有收到问题,但在获取或更新数据时仍然存在问题(基本上,获取时地图总是空的,更新时只添加新记录)。您是否解决过您的问题?我在地图/主键等方面遇到了完全相同的问题……嗨,托马斯,我记不起具体是如何解决的,但我通过重组数据解决了这个问题。嗨,尼科,谢谢你的回复,但不是我想听的:)
@OneToMany(fetch=FetchType.EAGER)
private Map<Student, Grade> grades;
public void testCreateExam() {
Student student1 = new Student("Karl");
Grade grade1 = new Grade(85);
Student student2 = new Student("Debbie");
Grade grade2 = new Grade(90);
Map<Student, Grade> grades = new HashMap<Student, Grade>();
grades.put(student1, grade1);
grades.put(student2, grade2);
examService.createExam("Biology", grades);
}
public Exam createExam(String name, Map<Student, Grade> grades) {
for(Student student: grades.keySet()) {
em.persist(student);
Grade grade = grades.get(student);
em.persist(grade);
}
Exam exam = new Exam(name);
exam.setGrades(grades);
em.persist(exam);
return exam;
}
// Change the primary key to be the Exam_Id and the grades_KEY
CREATE TABLE EXAM_GRADE (Exam_ID BIGINT NOT NULL, grades_ID BIGINT NOT NULL, grades_KEY BIGINT, PRIMARY KEY (Exam_ID, grades_KEY))
// removed the constraint for grades_ID references GRADE (ID)
ALTER TABLE EXAM_GRADE ADD CONSTRAINT EXAMGRADEgradesKEY FOREIGN KEY (grades_KEY) REFERENCES PERSON (ID)
ALTER TABLE EXAM_GRADE ADD CONSTRAINT EXAM_GRADE_Exam_ID FOREIGN KEY (Exam_ID) REFERENCES EXAM (ID)