使用复合主键和注释映射 ManyToMany:
Posted
技术标签:
【中文标题】使用复合主键和注释映射 ManyToMany:【英文标题】:Mapping ManyToMany with composite Primary key and Annotation: 【发布时间】:2011-09-18 08:15:12 【问题描述】:我正在尝试使用复合主键在学生和教学课程之间创建多对多关系:
我的课程:
@Entity
@Table(name="Student_mtm_cId")
public class Student
private String id;
private Set<StudentTClass> teachingClasses = new HashSet<StudentTClass>();
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.student")
public Set<StudentTClass> getTeachingClasses()
return teachingClasses;
public void setTeachingClasses(Set<StudentTClass> teachingClasses)
this.teachingClasses = teachingClasses;
public void addStudentToClass(TeachingClass teachingClass)
StudentTClass studentTClass = new StudentTClass();
studentTClass.setStudent(this);
studentTClass.setTeachingClass(teachingClass);
teachingClasses.add(studentTClass);
public void setLastName(String lastName)
this.lastName = lastName;
@Id @GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
@Column(name = "student_id", nullable = false)
public String getId()
return id;
public void setId(String id)
this.id = id;
//all other setters and getters and isequal/hashCode omitted.
教学班:
@Entity
@Table(name="TechingClass_MTM")
public class TeachingClass
private String id;
private String name;
private String description;
private Set<StudentTClass> teachingClasses = new HashSet<StudentTClass>();
public TeachingClass()
public TeachingClass(String name, String description)
super();
this.name = name;
this.description = description;
public void addStudentToClass(Student student)
StudentTClass studentTClass = new StudentTClass();
studentTClass.setStudent(student);
studentTClass.setTeachingClass(this);
teachingClasses.add(studentTClass);
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.teachingClass")
public Set<StudentTClass> getTeachingClasses()
return teachingClasses;
public void setTeachingClasses(Set<StudentTClass> teachingClasses)
this.teachingClasses = teachingClasses;
public void setDescription(String description)
this.description = description;
@Id @GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
@Column(name = "teachingClass_id", nullable = false)
public String getId()
return id;
public void setId(String id)
this.id = id;
集合对象:
@Entity
@Table(name = "student_TClass_MTM")
@AssociationOverrides(
@AssociationOverride(name = "pk.student", joinColumns = @JoinColumn(name = "student_id")),
@AssociationOverride(name = "pk.teachingClass", joinColumns = @JoinColumn(name = "teachingClass_id"))
)
public class StudentTClass
@EmbeddedId
private StudentTClassPK pk = new StudentTClassPK();
public StudentTClassPK getPk()
return pk;
public void setPk(StudentTClassPK pk)
this.pk = pk;
public StudentTClass()
@Transient
public Student getStudent()
return this.pk.getStudent();
@Transient
public TeachingClass getTeachingClass()
return this.pk.getTeachingClass();
public void setStudent(Student student)
this.pk.setStudent(student);
public void setTeachingClass(TeachingClass teachingClass)
this.pk.setTeachingClass(teachingClass);
现在是主键:
@Embeddable
public class StudentTClassPK implements Serializable
private static final long serialVersionUID = -7261887879839337877L;
private Student student;
private TeachingClass teachingClass;
@ManyToOne
public Student getStudent()
return student;
public void setStudent(Student student)
this.student = student;
@ManyToOne
public TeachingClass getTeachingClass()
return teachingClass;
public void setTeachingClass(TeachingClass teachingClass)
this.teachingClass = teachingClass;
public StudentTClassPK(Student student, TeachingClass teachingClass)
this.student = student;
this.teachingClass = teachingClass;
public StudentTClassPK()
当我尝试 Persist Student 时,出现以下错误:
Caused by: org.hibernate.MappingException: Could not determine type for: com.vanilla.objects.Student, at table: student_TClass_MTM, for columns: [org.hibernate.mapping.Column(student)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:306)
at org.hibernate.tuple.PropertyFactory.buildStandardProperty(PropertyFactory.java:143)
at org.hibernate.tuple.component.ComponentMetamodel.<init>(ComponentMetamodel.java:68)
at org.hibernate.mapping.Component.buildType(Component.java:184)
at org.hibernate.mapping.Component.getType(Component.java:177)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:290)
at org.hibernate.mapping.RootClass.validate(RootClass.java:236)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1362)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1865)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:855)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:774)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 51 more
我做错了什么?
【问题讨论】:
【参考方案1】:我解决了这个问题。我映射了 Getter 而不是字段。
public class StudentTClass
//@EmbeddedId
private StudentTClassPK pk = new StudentTClassPK();
@EmbeddedId
public StudentTClassPK getPk()
return pk;
【讨论】:
这成功了!我必须在带有 EmbeddedId 标记的类以及标记为 Embedabble 的类中执行此操作。【参考方案2】:如果可以,我会认真建议删除复合键。值得使用简单的主键既可以解决很多问题,又可以简化您的代码。过去我在数据库中使用过复合键,因为我无法修改数据库。不幸的是,我没有代码。但我确实记得需要一些工作才能使其正常工作。抱歉,帮不上忙。
【讨论】:
我已经解决了这个问题,我的代码现在可以完美运行了。虽然让 Hibernate 与复合主键一起工作很棘手,但我认为它在特殊情况下很有用,我们需要保证在多对多关系中每个组合只有一行。 我同意,在某些情况下复合键是合法有用的。 @danny.lesnik 组合唯一性可以通过唯一索引来保证。 JPA 2.1 提供与实现无关的语法。 仅仅因为我们不知道如何使用 ORM 框架做事而使 ORM 变得更简单并不是一种方法。我喜欢 DB 提供的所有可能性,我也喜欢将它们保存在后端代码中。另一件事是设置 ORM 有点复杂,它确实可以按照我们的意愿工作。以上是关于使用复合主键和注释映射 ManyToMany:的主要内容,如果未能解决你的问题,请参考以下文章