JPA + Hibernate:如何定义具有 ON DELETE CASCADE 的约束

Posted

技术标签:

【中文标题】JPA + Hibernate:如何定义具有 ON DELETE CASCADE 的约束【英文标题】:JPA + Hibernate: How to define a constraint having ON DELETE CASCADE 【发布时间】:2013-01-30 07:29:12 【问题描述】:

我只是想知道是否有这样一种方法可以构建我的 mysql

ALTER TABLE `USERINFO`
  ADD CONSTRAINT `FK_USER_ID` FOREIGN KEY (`USERID`) REFERENCES `USERACCOUNT` (`USERID`) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE;

但是,当 hibernate ++ jpa 开始构建具有“<property name="hibernate.hbm2ddl.auto" value="create" />”的表时,我才在我的 DDL 中得到了这个

ALTER TABLE `USERINFO` ADD CONSTRAINT `FK_USER_ID` FOREIGN KEY (`USERID`) REFERENCES `USERACCOUNT` (`USERID`);

在我的课程中,我有这些注释设置,

// UserAcc.java
@Entity
@Table(name = "USERACC")
public class UserAcc implements Serializable 

private static final long serialVersionUID = -5527566248002296042L;

@Id
@Column(name = "USERID")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer userId;


@OneToOne(mappedBy = "userAcc")
private UserInfo userInfo;
....


public UserInfo getUserInfo() 
    return userInfo;

public void setUserInfo(UserInfo userInfo) 
    this.userInfo = userInfo;

...

和,

// UserInfo.java
@Entity
@Table(name = "USERINFO")
public class UserInfo implements Serializable 

private static final long serialVersionUID = 5924361831551833717L;

@Id
@Column(name = "USERINFO_ID", nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer userInfoId;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="USERID", nullable=false)
@ForeignKey(name = "FK_USER_ID")
private UserAcc userAcc;


public Integer getUserInfoId() 
    return userInfoId;


public void setUserInfoId(Integer userInfoId) 
    this.userInfoId = userInfoId;

...

请注意,UserAccount 表是这里的父/主表,而 UserInfo 是规范化到另一个实体的扩展表。任何答案将不胜感激。我只是好奇它是如何完成的,因为我也喜欢在 MySQL 中工作。我只是习惯于从父表 (USERACOUNT) 中删除一条记录,这也将允许我根据父/主表中的特定记录级联删除到子记录。

谢谢!

【问题讨论】:

你找到解决这个问题的方法了吗?我遇到了同样的问题,我不想使用双向关系,在父级上创建延迟获取。 【参考方案1】:

JPA 确实为关联实体提供了cascade 操作(合并、持久化、刷新、删除)的可能性。逻辑在 JPA 中,不使用数据库级联。

@OneToMany(cascade=CascadeType.REMOVE)

没有符合 JPA 标准的方式来使用数据库级联进行级联。如果喜欢这样的级联,我们必须回退到 Hibernate 特定的构造:@OnDelete。它至少适用于@OneToMany,但过去在@OneToOne@OnDelete 上存在一些问题。

@OnDelete(action = OnDeleteAction.CASCADE)

请注意,将此注释添加到现有约束不会更新它。您可能必须先手动删除它才能正确更新架构。

【讨论】:

谢谢米科。我尝试在 JPA 注释中包含 OnDelete,但它确实不起作用。我有一个问题,当你想操作你的数据库,想添加ON DELETE CASCADE,尤其是MySQL,你是怎么处理的?【参考方案2】:

在 JPA 中没有明确的方法可以做到这一点。以下将为您提供您想要的... 您可以使用CascadeType.DELETE,但是此注释仅适用于EntityManager 中的对象,而不适用于数据库。您要确保将ON DELETE CASCADE 添加到数据库约束中。要进行验证,您可以配置 JPA 以生成 ddl 文件。查看ddl 文件,您会注意到ON DELETE CASCADE 不是约束的一部分。将ON DELETE CASCADE 添加到ddl 文件中的实际SQL,然后从ddl 更新您的数据库架构。这将解决您的问题。

这个link 展示了如何在 MySQL 中为CONSTRAINT 使用ON DELETE CASCADE。您在约束上执行此操作。您也可以在 CREATE TABLEALTER TABLE 语句中执行此操作。 JPA 很可能在 ALTER TABLE 语句中创建了约束。只需在该语句中添加ON DELETE CASCADE

请注意,一些 JPA 实现者确实提供了实现此功能的方法。

最后,Hibernate 确实使用 OnDelete(action = OnDeleteAction.CASCADE) 注释提供了此功能。

【讨论】:

【参考方案3】:

你可以在UserAcc.userInfo上使用Hibernate注解org.hibernate.annotations@OnDelete(action = OnDeleteAction.CASCADE)

public class UserAcc implements Serializable 

...

@OneToOne(mappedBy = "userAcc")
@OnDelete(action = OnDeleteAction.CASCADE)
private UserInfo userInfo;

...

这将在 UserInfo 表中的外键上生成 DDL ON DELETE CASCADE

【讨论】:

【参考方案4】:

您可以使用@JoinColumn(foreignKey = @ForeignKey(...)) 手动定义约束,如下所示:-

// UserInfo.java
@Entity
@Table(name = "USERINFO")
public class UserInfo implements Serializable 

private static final long serialVersionUID = 5924361831551833717L;

@Id
@Column(name = "USERINFO_ID", nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer userInfoId;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(
        name="USERID", 
        nullable=false,
        foreignKey = @ForeignKey(
                name="FK_USER_ID",
                foreignKeyDefinition = "FOREIGN KEY (USERID) REFERENCES USERACCOUNT(USERID) ON UPDATE CASCADE ON DELETE CASCADE"
        )
)
private UserAcc userAcc;


public Integer getUserInfoId() 
    return userInfoId;


public void setUserInfoId(Integer userInfoId) 
    this.userInfoId = userInfoId;

...

这将在生成 DDL 期间添加约束。

生成过程完成后,你可以查看USERINFO表的DDL,你会发现已经添加了约束,如下图所示:-

create table USERINFO(
    ....,
    ....,
    ....,
    ....,
    constraint FK_USER_ID foreign key (USERID) references USERACCOUNT(USERID) on update cascade on delete cascade
);

【讨论】:

以上是关于JPA + Hibernate:如何定义具有 ON DELETE CASCADE 的约束的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JPA 中获取外键引用以具有“ON UPDATE CASCADE ON DELETE CASCADE”功能?

如何在 JPA Hibernate 映射中将 GUID(不是 PK)添加到已经具有 PK(整数)的现有实体

JPA+Hibernate - 实体关系中的循环 - 级联策略

如何使用 JPA 和 Hibernate 映射 PostgreSQL 枚举

如何使用 JPA 和 Hibernate 通过自定义对象实体属性进行查询

具有 Oracle 标签安全性的 JPA/Hibernate