为什么@Size验证注释会影响 DataNucleus JPA 数据库模式?



一个同时使用 JPA 和验证注释的有效实体,例如

@Entity
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
public static final int IMAGE_COUNT_MAX = 5;
@Id
@GeneratedValue
private Long id;
@Size(max = IMAGE_COUNT_MAX, message = "Maximal " + IMAGE_COUNT_MAX + " images are allowed")
@Basic
@Lob
private ArrayList<byte[]> imageData = new ArrayList<>();

导致@Sizemax值作为LONG VARCHAR FOR BIT DATA的长度属性传递,这在 Apache Derby 中是无效的 SQL,从而导致

SEVERE: Error thrown executing CREATE TABLE MYENTITY
(
ID BIGINT NOT NULL generated always as identity (start with 1),
IMAGEDATA LONG VARCHAR FOR BIT DATA(5)
) : Syntax error: Encountered "(" at line 4, column 40.
java.sql.SQLSyntaxErrorException: Syntax error: Encountered "(" at line 4, column 40.
at org.apache.derby.impl.jdbc.SQLExceptionFactory.getSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.Util.generateCsSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.TransactionResourceImpl.wrapInSQLException(Unknown Source)
at org.apache.derby.impl.jdbc.TransactionResourceImpl.handleException(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedConnection.handleException(Unknown Source)
at org.apache.derby.impl.jdbc.ConnectionChild.handleException(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
at org.apache.derby.impl.jdbc.EmbedStatement.execute(Unknown Source)
at org.datanucleus.store.rdbms.datasource.dbcp2.DelegatingStatement.execute(DelegatingStatement.java:291)
at org.datanucleus.store.rdbms.datasource.dbcp2.DelegatingStatement.execute(DelegatingStatement.java:291)
at org.datanucleus.store.rdbms.table.AbstractTable.executeDdlStatement(AbstractTable.java:849)
at org.datanucleus.store.rdbms.table.AbstractTable.executeDdlStatementList(AbstractTable.java:800)
at org.datanucleus.store.rdbms.table.AbstractTable.create(AbstractTable.java:522)
at org.datanucleus.store.rdbms.table.AbstractTable.exists(AbstractTable.java:580)
at org.datanucleus.store.rdbms.RDBMSStoreManager$ClassAdder.performTablesValidation(RDBMSStoreManager.java:3447)
at org.datanucleus.store.rdbms.RDBMSStoreManager$ClassAdder.run(RDBMSStoreManager.java:2969)
at org.datanucleus.store.rdbms.AbstractSchemaTransaction.execute(AbstractSchemaTransaction.java:118)
at org.datanucleus.store.rdbms.RDBMSStoreManager.manageClasses(RDBMSStoreManager.java:1672)
at org.datanucleus.store.rdbms.RDBMSStoreManager.getDatastoreClass(RDBMSStoreManager.java:648)
at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.getDatastoreClass(RDBMSPersistenceHandler.java:88)
at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.insertObject(RDBMSPersistenceHandler.java:123)
at org.datanucleus.state.StateManagerImpl.internalMakePersistent(StateManagerImpl.java:4535)
at org.datanucleus.state.StateManagerImpl.flush(StateManagerImpl.java:5735)
at org.datanucleus.flush.FlushOrdered.execute(FlushOrdered.java:106)
at org.datanucleus.ExecutionContextImpl.flushInternal(ExecutionContextImpl.java:4058)
at org.datanucleus.ExecutionContextImpl.flush(ExecutionContextImpl.java:4004)
at org.datanucleus.api.jpa.JPAEntityManager.flush(JPAEntityManager.java:946)
at richtercloud.datanucleus.validation.schema.confusion.NewMain.main(NewMain.java:33)
Caused by: ERROR 42X01: Syntax error: Encountered "(" at line 4, column 40.
at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
at org.apache.derby.iapi.error.StandardException.newException(Unknown Source)
at org.apache.derby.impl.sql.compile.ParserImpl.parseStatementOrSearchCondition(Unknown Source)
at org.apache.derby.impl.sql.compile.ParserImpl.parseStatement(Unknown Source)
at org.apache.derby.impl.sql.GenericStatement.prepMinion(Unknown Source)
at org.apache.derby.impl.sql.GenericStatement.prepare(Unknown Source)
at org.apache.derby.impl.sql.conn.GenericLanguageConnectionContext.prepareInternalStatement(Unknown Source)
... 22 more

这可能是 JPA 或 DataNucleus 中的一个难以理解的功能,如果是的话,我如何在 JPA 中映射字段并指定验证约束(如果可能不涉及 XML 配置文件)?或者这是DataNucleus中的一个错误?

我正在使用

richtercloud:datanucleus-validation-schema-confusion:jar:1.0-SNAPSHOT
+- org.datanucleus:javax.persistence:jar:2.2.0-release:compile
+- org.datanucleus:datanucleus-api-jpa:jar:5.1.4:compile
+- org.datanucleus:datanucleus-core:jar:5.1.4:compile
+- org.datanucleus:datanucleus-rdbms:jar:5.1.4:compile
+- org.apache.derby:derbyclient:jar:10.14.1.0:compile
+- org.apache.derby:derby:jar:10.14.1.0:compile
- org.hibernate:hibernate-validator:jar:4.3.2.Final:compile
+- javax.validation:validation-api:jar:1.0.0.GA:compile
- org.jboss.logging:jboss-logging:jar:3.1.0.CR2:compile

@Column中的columnDefinition被简单地忽略。应该不会是这样吧?

我指的是并使用DataNucleus JPA(而不是JDO)。

SSCCE可以在 https://gitlab.com/krichter/datanucleus-validation-schema-confusion 找到。

这是因为DataNucleus支持处理javax.validation@Size(max="...")注释,相当于@Column(length="..."),正如他们的文档所声明的那样。

至于问题背后的原因,这需要调试。

@Size应该只作为字符串类型字段/属性上的扩展名进行处理(我使用它的目的),所以也许没有检查,它只是应用它而不考虑你的字段?

也许 JDBC驱动程序没有将特定的 JDBC/SQL 类型报告为不允许大小?如果是这种情况,那么关于 JDBC 驱动程序的错误报告将是要走的路。

此外,虽然这个功能对许多人来说很有意义(我已经用过它),但对于那些想要"严格的 JPA"模式处理的人来说,它是有意义的(你认为显而易见的,主要用例对所有人都不一样,所以任何 JPA 提供者都只和它获得的请求和它提供的灵活性一样好)。最接近粗略地浏览代码会 https://github.com/datanucleus/datanucleus-core/blob/master/src/main/java/org/datanucleus/metadata/annotations/AnnotationManagerImpl.java#L101 作为启用它的位置,那么为什么不提供一种关闭它的方法呢?

最新更新