jOOQ:允许字符约束?
jOOQ: Allowed-Character constraints?
我正在考虑从 Hibernate 迁移到 jOOQ,但我找不到例如
如何在 Hibernate 中像这样在 String
上设置模式约束:
@NotEmpty(message = "Firstname cannot be empty")
@Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;
我如何在 jOOQ 中做到这一点?
"jOOQ way"
执行此类验证的 "jOOQ way" 将创建:
- 数据库中有一个
CHECK
约束。
- 数据库中的触发器。
- 数据库中的域。
毕竟,如果要确保数据完整性,数据库就是此类约束和完整性检查所在的地方(可能除了功能等效的客户端验证之外)。想象一下绕过 JSR-303 验证的批处理作业、Perl 脚本,甚至 JDBC 语句。您很快就会发现自己的数据已损坏。
如果您确实想要实现客户端验证,您仍然可以在 DTO 上使用 JSR-303,例如,它与您的 UI 交互。但是在将数据传递给 jOOQ 进行存储 ().
之前,您必须 执行验证
使用 Converter
但是,您可以通过在各个列上声明 Converter
和 registering such Converter
with the source code generator.
来使用您自己的自定义类型
本质上,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 开始,这还没有实现。
我建议您不要尝试以 'hibernate/JPA' 的方式使用 jOOQ。保留 jOOQ 生成的 classes 并手动映射到您自己的域 classes,您可以随意对其进行注释。然后,您可以在尝试保留它们之前调用 JSR 验证器。
例如,jOOQ 可能会生成以下 class
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() { /* ... */ }
}
并在您的 DAO 层
中检索到 BookRecord
后手动映射
Book book = new Book();
book.setId(bookRecord.getId());
book.setFirstname(bookRecord.getFirstname());
这看起来很乏味(并且 ORM 试图让您免于这种乏味)但实际上它可以很好地扩展到复杂的域对象,在我看来,并且总是很容易弄清楚应用程序中的数据流。
我正在考虑从 Hibernate 迁移到 jOOQ,但我找不到例如
如何在 Hibernate 中像这样在 String
上设置模式约束:
@NotEmpty(message = "Firstname cannot be empty")
@Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;
我如何在 jOOQ 中做到这一点?
"jOOQ way"
执行此类验证的 "jOOQ way" 将创建:
- 数据库中有一个
CHECK
约束。 - 数据库中的触发器。
- 数据库中的域。
毕竟,如果要确保数据完整性,数据库就是此类约束和完整性检查所在的地方(可能除了功能等效的客户端验证之外)。想象一下绕过 JSR-303 验证的批处理作业、Perl 脚本,甚至 JDBC 语句。您很快就会发现自己的数据已损坏。
如果您确实想要实现客户端验证,您仍然可以在 DTO 上使用 JSR-303,例如,它与您的 UI 交互。但是在将数据传递给 jOOQ 进行存储 (
使用 Converter
但是,您可以通过在各个列上声明 Converter
和 registering such Converter
with the source code generator.
本质上,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 开始,这还没有实现。
我建议您不要尝试以 'hibernate/JPA' 的方式使用 jOOQ。保留 jOOQ 生成的 classes 并手动映射到您自己的域 classes,您可以随意对其进行注释。然后,您可以在尝试保留它们之前调用 JSR 验证器。
例如,jOOQ 可能会生成以下 class
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() { /* ... */ }
}
并在您的 DAO 层
中检索到BookRecord
后手动映射
Book book = new Book();
book.setId(bookRecord.getId());
book.setFirstname(bookRecord.getFirstname());
这看起来很乏味(并且 ORM 试图让您免于这种乏味)但实际上它可以很好地扩展到复杂的域对象,在我看来,并且总是很容易弄清楚应用程序中的数据流。