开发者问题收集

jOOQ:允许的字符限制?

2015-09-21
2370

我正在考虑从 Hibernate 迁移到 jOOQ,但我找不到如何在 Hibernate 中像这样对 String 设置 Pattern-Constraints:

@NotEmpty(message = "Firstname cannot be empty")
@Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;

如何在 jOOQ 中做到这一点?

2个回答

“jOOQ 方式”

执行此类验证的“jOOQ 方式”是创建以下任一方式:

  • 数据库中的 CHECK 约束。
  • 数据库中的触发器。
  • 数据库中的域。

毕竟,如果您想确保数据完整性,那么数据库就是此类约束和完整性检查的归属地(可能除了功能等效的客户端验证之外)。想象一下批处理作业、Perl 脚本,甚至是绕过 JSR-303 验证的 JDBC 语句。您很快就会发现自己的数据已损坏。

如果您确实想实现客户端验证,您仍然可以在与您的 UI 交互的 DTO 上使用 JSR-303。但是,在将数据传递到 jOOQ 进行存储之前,您必须执行验证( artbristol 解释道 )。

使用 Converter

但是,您可以通过在各个列上声明 Converter 并使用 向源代码生成器注册此类 Converter 来使用自己的自定义类型。

本质上, Converter 是:

public interface Converter<T, U> extends Serializable {
    U from(T databaseObject);
    T to(U userObject);
    Class<T> fromType();
    Class<U> toType();
}

对于您的情况,您可以将注释实现为例如:

public class NotEmptyAlphaNumericValidator implements Converter<String, String> {

    // Validation
    public String to(String userObject) {
        assertNotEmpty(userObject);
        assertMatches(userObject, "^[a-zA-Z0-9_]*$");
        return userObject;
    }

    // Boilerplate
    public String from(String databaseObject) { return databaseObject; }
    public Class<String> fromType() { return String.class; }
    public Class<String> toType() { return String.class; }
}

请注意,这更像是一种解决方法,因为 Converter 并非为这种用例而设计,即使它可以完美实现它。

使用正式的客户端验证

还有一个待处理的功能请求 #4543 ,以增加对客户端验证的更多支持。截至 jOOQ 3.7,此功能尚未实现。

Lukas Eder
2015-09-21

我建议您不要尝试以“hibernate/JPA”方式使用 jOOQ。保留 jOOQ 生成的类,并手动映射到您自己的域类,您可以随意注释这些类。然后,您可以在尝试持久化它们之前调用 JSR 验证器。

例如,jOOQ 可能会生成以下类

public class BookRecord extends UpdatableRecordImpl<BookRecord> {

    private String firstname;

    public void setId(Integer value) { /* ... */ }

    public Integer getId() { /* ... */ }

}

您可以创建自己的域对象

public class Book {

    @NotEmpty(message = "Firstname cannot be empty")
    @Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
    private String firstname;

    public void setId(Integer value) { /* ... */ }

    public Integer getId() { /* ... */ }

}

并在检索到 BookRecord 后在 DAO 层中手动映射

Book book = new Book();
book.setId(bookRecord.getId());
book.setFirstname(bookRecord.getFirstname());

这似乎很乏味(ORM 试图让您免于这种乏味),但实际上,在我看来,它可以很好地扩展到复杂的域对象,并且始终很容易弄清楚应用程序中的数据流。

artbristol
2015-09-21