【问题标题】:Creating PostgreSQL array types like "text[]" using JPA (EclipseLink)使用 JPA (EclipseLink) 创建 PostgreSQL 数组类型,如“text []”
【发布时间】:2014-06-29 05:38:22
【问题描述】:

我在创建 JPA 模型类时遇到问题,EclipseLink 将从该模型类中创建 以下 PostgreSQL DDL:

CREATE TABLE array_example (
  id serial not null, 
  params text[] not null
);

据我了解,PostgreSQL 的数组类型不是 SQL 标准,因此不属于 JPA 标准。不过,EclipseLink 似乎对非标准扩展有某种支持。到目前为止,我想出了以下课程:

....
import org.eclipse.persistence.annotations.Array;
import org.eclipse.persistence.annotations.Struct;

@Entity
@Table(name = "array_example")
@Struct(name = "params") // Else: [EclipseLink-157] "Normal descriptors do not support non-relational extensions."
@XmlRootElement
public class ArrayExamplePostgres implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private int id;

    @NotNull
    @Array(databaseType = "TEXT[]") // Needs @Struct on class!
    @Column(name = "params")
    private List<String> params;
    ....

运行我的测试脚本时出现以下错误:

Mai 12, 2014 1:35:13 AM org.eclipse.persistence.default
WARNING: The default table generator currently only supports generating default table schema from a relational project.
Mai 12, 2014 1:35:13 AM org.eclipse.persistence.session.file:/srv/home/james/workspace/java_test/java_test_ee6_jpa/target/classes/_postgresJavaTestJpaPU
WARNING: 
Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: Unable to find server array type for provided name TEXT[].
Error Code: 0
Query: InsertObjectQuery(de.lathspell.java_test_ee6_jpa.model.ArrayExamplePostgres@3c77af84)
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:326)
    at org.eclipse.persistence.mappings.structures.ObjectRelationalDataTypeDescriptor.buildFieldValueFromDirectValues(ObjectRelationalDataTypeDescriptor.java:102)
    at org.eclipse.persistence.mappings.foundation.AbstractCompositeDirectCollectionMapping.writeFromObjectIntoRow(AbstractCompositeDirectCollectionMapping.java:617)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildRow(ObjectBuilder.java:1394)
    at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildRow(ObjectBuilder.java:1382)
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:450)
    at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80)
    at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90)
    at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:300)
    at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
    at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:798)
    at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
    at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2894)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1797)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1779)
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1730)
    at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:226)
    at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:125)
    at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4200)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1439)
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithPreBuiltChangeSet(UnitOfWorkImpl.java:1585)
    at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.writeChanges(RepeatableWriteUnitOfWork.java:452)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:846)
    at de.lathspell.java_test_ee6_jpa.model.ArrayExamplePostgresTest.testArrays(ArrayExamplePostgresTest.java:31)
...

PostgreSQL 日志文件包含两个可疑的 SELECT(对于 _text 返回 1009,然后 typedelim=NULL),因为缺少表而失败前不久:

2014-05-12 01:34:32 CEST postgres@java_test_ee6_jpa [17555] LOG:  execute <unnamed>: SELECT oid FROM pg_catalog.pg_type WHERE typname = $1
2014-05-12 01:34:32 CEST postgres@java_test_ee6_jpa [17555] DETAIL:  parameters: $1 = '_text

2014-05-12 01:34:32 CEST postgres@java_test_ee6_jpa [17555] LOG:  execute <unnamed>: SELECT e.typdelim FROM pg_catalog.pg_type t, pg_catalog.pg_type e WHERE t.oid = $1 and t.typelem = e.oid
2014-05-12 01:34:32 CEST postgres@java_test_ee6_jpa [17555] DETAIL:  parameters: $1 = '1009'

2014-05-12 01:34:32 CEST postgres@java_test_ee6_jpa [17555] LOG:  execute S_1: BEGIN
2014-05-12 01:34:32 CEST postgres@java_test_ee6_jpa [17555] ERROR:  relation "array_example" does not exist at character 13
2014-05-12 01:34:32 CEST postgres@java_test_ee6_jpa [17555] STATEMENT:  INSERT INTO array_example (params) VALUES ($1)

持久化配置的相关部分是:

<persistence-unit name="postgresJavaTestJpaPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>de.lathspell.java_test_ee6_jpa.model.ArrayExamplePostgres</class>
    ...
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
        <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
        <property name="javax.persistence.jdbc.url" value="jdbc:postgresql:java_test_ee6_jpa"/>
        <property name="javax.persistence.jdbc.user" value="postgres"/>
        <property name="javax.persistence.jdbc.password" value="secret"/>
        <property name="eclipselink.ddl-generation.output-mode" value="both"/>
        <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
        <property name="eclipselink.drop-ddl-jdbc-file-name" value="src/main/sql/eclipselink-postgres-drop.sql"/>
        <property name="eclipselink.create-ddl-jdbc-file-name" value="src/main/sql/eclipselink-postgres-create.sql"/>
        <property name="eclipselink.jdbc.native-sql" value="true"/>
    </properties>
</persistence-unit>

(完整课程在https://svn.code.sf.net/p/lathspellsphp/code/java_test/java_test_ee7_jpa/src/main/java/de/lathspell/java_test_ee7_jpa/model/ArrayExamplePostgres.java

编辑:

当使用 @Array(databaseType="TEXT") 我得到一个 SQL 查询但没有生成架构:

2014-05-12 23:03:08 CEST postgres@java_test_ee7_jpa [4183] LOG:  execute <unnamed>: SELECT pg_type.oid   FROM pg_catalog.pg_type   LEFT   JOIN (select ns.oid as nspoid, ns.nspname, r.r           from pg_namespace as ns           join ( select s.r, (current_schemas(false))[s.r] as nspname                    from generate_series(1, array_upper(current_schemas(false), 1)) as s(r) ) as r          using ( nspname )        ) as sp     ON sp.nspoid = typnamespace  WHERE typname = $1  ORDER BY sp.r, pg_type.oid DESC LIMIT 1
2014-05-12 23:03:08 CEST postgres@java_test_ee7_jpa [4183] DETAIL:  parameters: $1 = '_TEXT'
-> 0 rows

当使用 @Array(databaseType="text[]" 我得到一个 SQL 查询但没有生成架构:

2014-05-12 23:12:21 CEST postgres@java_test_ee7_jpa [4435] LOG:  execute <unnamed>: SELECT pg_type.oid   FROM pg_catalog.pg_type   LEFT   JOIN (select ns.oid as nspoid, ns.nspname, r.r           from pg_namespace as ns           join ( select s.r, (current_schemas(false))[s.r] as nspname                    from generate_series(1, array_upper(current_schemas(false), 1)) as s(r) ) as r          using ( nspname )        ) as sp     ON sp.nspoid = typnamespace  WHERE typname = $1  ORDER BY sp.r, pg_type.oid DESC LIMIT 1
2014-05-12 23:12:21 CEST postgres@java_test_ee7_jpa [4435] DETAIL:  parameters: $1 = '_text[]'
-> 0 rows

使用@Array(databaseType="text" 时,我得到两个实际产生结果的SQL 查询,但仍然没有创建表,EclipseLink 也没有创​​建schema.sql:

2014-05-12 23:04:46 CEST postgres@java_test_ee7_jpa [4266] LOG:  execute <unnamed>: SELECT pg_type.oid   FROM pg_catalog.pg_type   LEFT   JOIN (select ns.oid as nspoid, ns.nspname, r.r           from pg_namespace as ns           join ( select s.r, (current_schemas(false))[s.r] as nspname                    from generate_series(1, array_upper(current_schemas(false), 1)) as s(r) ) as r          using ( nspname )        ) as sp     ON sp.nspoid = typnamespace  WHERE typname = $1  ORDER BY sp.r, pg_type.oid DESC LIMIT 1
2014-05-12 23:04:46 CEST postgres@java_test_ee7_jpa [4266] DETAIL:  parameters: $1 = '_text'
--> 1009
2014-05-12 23:04:46 CEST postgres@java_test_ee7_jpa [4266] LOG:  execute <unnamed>: SELECT e.typdelim FROM pg_catalog.pg_type t, pg_catalog.pg_type e WHERE t.oid = $1 and t.typelem = e.oid
2014-05-12 23:04:46 CEST postgres@java_test_ee7_jpa [4266] DETAIL:  parameters: $1 = '1009'
--> ','

在最后一个示例中,打印了一个新警告。如果我从 persistence.xml 中删除 ArrayExample 模型类,它就会消失,所以它看起来很相关:

org.eclipse.persistence.default
WARNING: The default table generator currently only supports generating default table schema from a relational project.

【问题讨论】:

  • 我在一个已删除的答案中建议它似乎正在寻找text[] 的数组类型,即文本数组的数组,不支持,所以你应该尝试text .这似乎解决了眼前的问题,但根据上面的编辑创建了不同的问题。
  • 恐怕很多 Java ORM 除了关系数据库最基本的最低公分母特性外,什么都不擅长。在这种情况下,我认为它试图生成该字段,就好像它是 EclipseLink 的“NoSQL”支持的非关系对象一样。最后一个查询肯定为文本类型的内置数组找到了正确的 oid (1009)。
  • 架构生成,如警告所述,仅支持关系数据库类。一旦添加了 Struct 或 Array 扩展类型,就不能使用模式生成,因为不存在对所有各种 DB 类型的支持,而且实际上,无论如何都可以使用 - 这些类型适用于自定义数据库类型遗留系统。在大多数情况下,最好使用现有的可移植类型,或者使用脚本来创建数据库。

标签: postgresql jpa eclipselink


【解决方案1】:

也许这个示例项目会有所帮助:

https://github.com/phstudy/jpa-array-converter-sample

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    • 2019-10-28
    • 1970-01-01
    相关资源
    最近更新 更多