【问题标题】:Mapping ManyToMany with composite Primary key and Annotation:使用复合主键和注释映射 ManyToMany:
【发布时间】: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

我做错了什么?

【问题讨论】:

    标签: java hibernate spring jakarta-ee


    【解决方案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 有点复杂,它确实可以按照我们的意愿工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 2014-01-19
    • 1970-01-01
    • 2019-04-22
    • 2018-11-28
    相关资源
    最近更新 更多