使用复合主键和注释映射 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:的主要内容,如果未能解决你的问题,请参考以下文章

hibernate复合主键

复合主键和外键 Code First

主键和外键的复合键不能建立关系

MySQL 死锁与复合主键和触发自动增量

具有复合主键和特定 VARCHAR 长度的 NodeJS MySQL ORM

使用实体的复合键作为另一个实体中的 ManyToMany 键