【问题标题】:How to set the name of a class level jpa check constraint如何设置类级别 jpa 检查约束的名称
【发布时间】:2019-06-18 09:37:19
【问题描述】:

我想在 JPA 中对实体定义一个约束,以确保将两个属性“text”或“title”之一设置为非空值。

对于本例,假设以下 Question 实体类:

@Entity
@Table
public class Question {

@Id
private Long id;

@Column(nullable = true)
private String text;

@Column(nullable = true)
private String title;

}

对于这个类,JPA会生成如下SQL语句(我们需要使用oracle方言):

    create table question (
        id number(19,0) not null,
        text varchar2(50 char) null,
        title varchar2(10,0) null,
        primary key (id)
    );


为了检查是否设置了任一属性,我可以添加一个检查约束:

@Entity
@Table
@Check(constraints = "TEXT IS NOT NULL OR TITLE IS NOT NULL")    
public class Question {
...
}

现在 JPA 会生成这个:

    create table question (
        id number(19,0) not null,
        text varchar2(50 char) null,
        title varchar2(10,0) null,
        primary key (id),
        check (TEXT IS NOT NULL OR TITLE IS NOT NULL)
    );

在数据库端,这将生成一个带有随机名称的检查约束,例如“SYS_C00127157”。

为了给约束分配一个有意义的名称(例如:check_title),我可以使用这个 DDL:

    create table question (
        id number(19,0) not null,
        text varchar2(50 char) null,
        title varchar2(10,0) null,
        primary key (id),
        constraint check_title check(TEXT IS NOT NULL OR TITLE IS NOT NULL)
    );

我正在寻找的是这样的:

@Entity
@Table
@Check(name = "check_title" constraints = "TEXT IS NOT NULL OR TITLE IS NOT NULL")    
public class Question {
...
}

很遗憾,这是不可能的。 Java 中的@Check 注释没有为约束提供这样的 name 属性。

有没有其他方法可以设置名称,以便生成的 DDL 匹配预期结果?

【问题讨论】:

  • 我知道的唯一替代方法是在 @Column 注释中定义它,如下所示:@Column(columnDefinition = "VARCHAR(60) CHECK (status IN ('ACTIVE', 'PENDING', 'INACTIVE'))) private String status; 但我认为您不能为其添加特定名称。

标签: java oracle hibernate jpa


【解决方案1】:

很遗憾,这是不可能的。如果你看一下表生成脚本是如何构建的:

https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/mapping/Table.java#L604

你会看到你在@Check注解中指定的字符串是这样包装的:

buf.append( ", check (" )
    .append( checkConstraint )
    .append( ')' );

并将约束名称的生成提供给数据库。

相比之下,a few lines above,您会发现可能会影响唯一约束的名称。 Here你可以找到它的一个例子。

【讨论】:

    【解决方案2】:

    这是不可能的。

    在我看来,从 JPA 注释生成生产数据库也不是一个好主意。 数据模型的寿命通常比应用程序长,因此最好控制 DDL。

    您应该考虑使用FlyWay 或Liquibase 进行数据库迁移。

    【讨论】:

    • 你说得对,我们确实使用 Flyway 进行数据库迁移。但是,我想使生成的模式尽可能接近生产模式。定义 FK 约束时,可以设置名称。乍一看,为检查约束设置一个名称似乎是相似的。事实证明,事情并没有那么简单。
    • 但是为什么要做这种不会产生任何价值的多余工作呢?
    • 我们从 java 代码生成完整的模式。然后,开发人员可以轻松地从生成的模式创建 Flyway 增量脚本。如果 DDL 生成正确,开发人员不必修改它或记住在这种特殊情况下需要添加约束名称。与其将其视为不会产生任何价值的工作,我更愿意将其视为自动化流程的一部分。
    • 但是您将无法创建所有数据库对象,因为其中一些对象(例如约束名称)无法使用 JPA 配置。
    猜你喜欢
    • 1970-01-01
    • 2015-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    相关资源
    最近更新 更多