@OnDelete Hibernate注解不会为MySql生成ON DELETE CASCADE。

3
我有两个实体,父亲和孩子,它们之间存在单向关系。
class Parent {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;
}

并且

class Child {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "parent_id")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Parent parent;
}

在application.properties文件中,我已经配置好了。
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.database-platform = org.hibernate.dialect.MySQL5InnoDBDialect

但是当我运行应用程序时,会创建以下语句

...
alter table child add constraint FKi62eg01ijyk2kya7eil2gafmx foreign key (parent_id) references parent (id)
...

因此,没有像应该有的ON CASCADE DELETE。每次运行应用程序时都会创建表,我检查了该方法。

org.hibernate.dialect.MySQL5InnoDBDialect#supportsCascadeDelete()

这真的叫做(就是这样)。 我正在使用spring-boot-parent版本1.4.3,它使用Hibernate 5.11。 有什么想法吗? 顺便说一下,我不想使用双向关系。

编辑 感谢@AlanHay,我发现我遗漏了一个重要部分。 实际上还涉及第三个类。

class Kindergarten {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @OneToMany(mappedBy = "kindergarten", fetch = FetchType.EAGER)
    @MapKeyJoinColumn(name = "parent_id") // parent_id causes the problem!
    private Map<Parent, Child> children;
}

幼儿园中的“Child with Kindergarten”实际上是这样的。
class Child {

    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "parent_id")
    @OnDelete(action = OnDeleteAction.CASCADE)
    private Parent parent;

    @ManyToOne
    @JoinColumn(name = "kindergarten_id")
    private Kindergarten kindergarten;
}

这就是问题发生的原因。如果你在MapKeyJoinColumn注释中将"parent_id"更改为Child中不存在的列,例如"map_id",则ON DELETE CASCADE将添加到Child中的外键parent_id。如果参数是Child的列"parent_id",那么ON DELETE CASCADE部分将不会被附加。不幸的是,我还不清楚其中的原因。更改参数不是一个选择,因为我想使用现有的链接来连接子对象的父对象。


你不能使用JPA Cascade.DELETE吗?https://dev59.com/RnjZa4cB1Zd3GeqPeHbt - Essex Boy
在父关联中,您定义一个 OneToMany 注释并添加 orphanRemoval = true。这应该确保通过 EntityManager.remove() 或 JPQL 查询执行的删除也会删除子实体。但是,如果您使用本机查询删除父实体,则不会删除子实体。 - coladict
1
刚刚检查了资料。MySQLDialect重写了supportsCascadeDelete以返回false,这告诉生成器不要将其添加到约束中。你可以向Hibernate团队提交一个pull-request,但他们添加这个可能有原因。有时候语法被列为支持,然后你得到一个“尚未实现”的错误。当我尝试在Oracle 11g数据库中使用数组时就发生了这种情况。谁知道从哪个版本开始它才真正起作用。 - coladict
1
除了检查方言属性之外,在 org.hibernate.tool.schema.internal.StandardForeignKeyExporter.getSqlCreateStrings(ForeignKey, Metadata) 中还有一个额外的检查,只有在第二个条件为真时才会附加 'on delete cascade'。您可以在此设置断点并跟踪以查看为什么未附加。查看源代码,它应该是正确的,但是如果设置了 @OnDelete(action = OnDeleteAction.CASCADE),则为真。请参见 org.hibernate.cfg.AnnotationBinder.processElementAnnotations(...) - Alan Hay
1
我已经测试过这个程序与MySQL5的兼容性,只有在单向@ManyToOne关系下才能正常工作,而你说你已经设置了这种关系。MySQL5InnoDBDialect是否被正确识别?你所设置的属性是Spring Boot特定的,这是一个Spring Boot项目吗?因为你的问题没有标记为Spring Boot。 - Alan Hay
显示剩余7条评论
2个回答

4

或许有点晚了,但由于这是搜索“hibernate ondelete generate cascade”时排名靠前的帖子之一:

出于某种原因,在Mysql中将@OnDelete放在ManyToOne方面对我没有起作用,但在OneToMany方面却有效。因此,如果你不幸运,请尝试在另一侧使用它。


2
哇,太神奇了。谢谢。这可能是一个错误,或者文档有误:https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#pc-cascade-on-delete - Scadge

0
在我的情况下,我还必须将@OnDelete放置在OneToMany一侧,此外,我还必须更改JpaVendorAdapter bean方法。它返回的适配器必须设置为org.hibernate.dialect.MySQL5InnoDBDialect,如下所示:

adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接