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

时间:2013-02-14 13:19:43

标签: java mysql hibernate jpa cascade

我只是想知道是否有这样一种方法可以将我的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),这也可以让我通过父/主表的表格依赖于特定记录的子记录级联。

谢谢!

4 个答案:

答案 0 :(得分:6)

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

@OneToMany(cascade=CascadeType.REMOVE)

没有符合JPA标准的方法来进行数据库级联的级联。如果首选这样的级联,我们必须回退到Hibernate特定的构造:@OnDelete。它至少与@OneToMany一起使用,但过去曾经存在@OneToOne和@OnDelete的一些问题。

@OnDelete(action = OnDeleteAction.CASCADE)

答案 1 :(得分:5)

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

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

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

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

答案 2 :(得分:2)

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

public class UserAcc implements Serializable {

...

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

...

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

答案 3 :(得分:0)

您可以使用@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
);