【问题标题】:How to achieve Foreign key constraint in JPA + Hibernate如何在 JPA + Hibernate 中实现外键约束
【发布时间】:2021-11-20 08:28:45
【问题描述】:

现在是使用 Hibernate 的第 5 天。我正在学习JPA。我的问题非常类似于:

JPA + Hibernate: How to define a constraint having ON DELETE CASCADE

但问题是:

  1. 8 年前有人问过。所以今天的版本将不匹配。
  2. OP 没有提到 Hibernate 或 MySQL 或 Java 的版本。
  3. 没有可接受的答案。

我有两张桌子studentguide。它们与外键链接:

我没有创建这些表。 Hibernate 为我创建了它们,因为我在我的学生班级中使用了这些注释:

@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
@JoinColumn(name="guide_id")
private Guide guide;

很明显 RajTanzeel 有相同的指南,即 Joe。我想保持参照完整性约束。这意味着如果我删除 Raj,那么 Joe 也会被删除。这意味着 Tanzeel 将没有任何指南。那不应该发生吧?但这就是我所面临的。

这是我的代码:

Main.java

public class Main {
    public static void main(String[] args) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction txn = session.getTransaction();
        try {
            txn.begin();
            // deleting Student[id=2L] (using CascadeType.REMOVE)
            Student student = (Student) session.get(Student.class, 2L);
            session.delete(student);
            txn.commit();
        }   catch(Exception e) {
                ...
        }
    }
}

Student.java

@Entity
public class Student {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    
    @Column(name="enrollment_id", nullable=false)
    private String enrollmentId;    
    
    private String name;
    
    @ManyToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
    @JoinColumn(name="guide_id")
    private Guide guide;
    
    public Student() {}
    public Student(String enrollmentId, String name, Guide guide) {
        this.enrollmentId = enrollmentId;
        this.name = name;
        this.guide = guide;
    }
    ...
}

Guide.java

@Entity
public class Guide {
    
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    
    @Column(name = "staff_id", nullable = false)
    private String staffId;
    private String name;
    private Integer salary;

    public Guide() {}
    public Guide(String staffId, String name, Integer salary) {
        this.staffId = staffId;
        this.name = name;
        this.salary = salary;
    }
    
}

来自我的 hibernate.cfg.xml

的一些信息
<session-factory>
    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">true</property>
        
    <property name="hbm2ddl.auto">update</property>
        
    <!-- Use Annotation-based mapping metadata -->
    <mapping class="entity.Student"/>
    <mapping class="entity.Guide"/>
</session-factory>

问题是,当我删除 Raj 时,他的指南 Joe 也被删除了,并且没有看到关于外键违规的异常。 Guide 表现在只有 Mike 并且 Tanzeel 指的是现在甚至不存在的向导 Joe

我的版本:

  1. Java 11
  2. mysql-connector-java 8.0.26
  3. hibernate-core 5.5.6.Final

请加入。

【问题讨论】:

    标签: java mysql spring hibernate jpa


    【解决方案1】:

    在你的情况下,我会使用双向关联而不是单向关联。

    所以你是指导实体会看到这样的,

    @Entity
    public class Guide {
    
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;
        
        @OneToMany(mappedBy="guide")
        private List<Student> students;    
    
        @Column(name = "staff_id", nullable = false)
        private String staffId;
        private String name;
        private Integer salary;
    
        public Guide() {}
        public Guide(String staffId, String name, Integer salary) {
            this.staffId = staffId;
            this.name = name;
            this.salary = salary;
        }
    
    }
    

    我建议你看看this page 上的其他示例。

    希望对你有帮助。

    --已编辑--

    我建议你检查这个link,Thorben 澄清说,为什么你不应该将 CascadeType.REMOVE 用于 -ToMany 关联。最后,您应该使用 EntityManager 或 remove 方法自己删除实体。

    和我上面的实体变化无关。请忽略它。

    【讨论】:

    • 它没有用。指南仍然被删除。
    • 抱歉,在您的指南实体中,您的所有者应该是mappedBy,所以它是guide,我编辑了它。你重建你的数据库了吗?
    • 您能否在更改实体后证明您的表结构,因为应该有所更改。
    【解决方案2】:

    CascadeType.REMOVE:表示删除所属实体时,删除相关实体。

    如果您仅将其单向映射(学生到指南),并且您在级联中消除,那么您收到的行为是合乎逻辑的。

    不要使用 cascade.REMOVE 并添加其他关系(学生指南)我认为这是预期的行为。

    @Entity
    public class Student {
    
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        private Long id;
        
        @Column(name="enrollment_id", nullable=false)
        private String enrollmentId;    
        
        private String name;
        
        @ManyToOne()
        @JoinColumn(name="guide_id")
        private Guide guide;
    
    }
    
    
    @Entity
    public class Guide {
        
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;
        
        @Column(name = "staff_id", nullable = false)
        private String staffId;
        private String name;
        private Integer salary;
    
       @OneToMany(mappedBy="guide")
        private List<Student> students; 
        
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-09
      • 2016-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-28
      • 2011-04-09
      • 1970-01-01
      相关资源
      最近更新 更多