代码之家  ›  专栏  ›  技术社区  ›  Siddharth Trikha

EclipseLink:PostgreSQL返回空列表作为文本的defualt值[]?

  •  0
  • Siddharth Trikha  · 技术社区  · 7 年前

    我在用 postgresql 因为我的数据库在应用服务器(as)端使用Java,使用JPA(Java persistence API)实现 eclipselink .

    我有一些专栏使用 text[] 作为postgres中映射到的数据类型 List 在jpa中,对象位于AS侧。

    日本航空公司

        @Struct(name="label,.....")
        @Entity
        @Table(name="\"XYZ\"", schema="\"XYZ\"")
        @NamedQuery(name="XYZ.findAll", query="SELECT r FROM XYZ r")
        public class XYZ implements  Serializable {
            private static final long serialVersionUID = 1L;
    
            @Id
            @Column(name="\"resourceID\"")
            private String resourceID;
    
            @Array(databaseType = "text")
            @Column(name="\"label\"")
            private List<String> label;
    
    .........
            // getter/setters 
    
    }
    

    所以在这里, label 存储为 文本[] 在postgres中映射到 List<String> 在JPA对象中。

    当我用 列表 值为 null ,关于检索我得到的JPA 空列表 作为价值,但从来没有 无效的 .

    为什么Postgres会回来 empty list 作为默认值,即使在保存时,我也将其设置为 无效的 . 对于我的用例 空列表 无效的 有不同的语义。

    这不是因为 String 类型,它不提供空字符串。

    文本[] 默认为空列表?

    我找不到关于这个问题的任何具体信息??

    **编辑1:** 我试着把场地设置成 String[] JPA格式如下:

        @Struct(name="label,.....")
        @Entity
        @Table(name="\"XYZ\"", schema="\"XYZ\"")
        @NamedQuery(name="XYZ.findAll", query="SELECT r FROM XYZ r")
        public class XYZ implements  Serializable {
            private static final long serialVersionUID = 1L;
    
            @Id
            @Column(name="\"resourceID\"")
            private String resourceID;
    
    
            @Column(name="\"label\"")
            private String[] label;
    
    .........
            // getter/setters 
    
    }
    

    运行时出现异常:

    堆栈跟踪:

    Caused by: org.postgresql.util.PSQLException: ERROR: column "label" is of type text[] but expression is of type bytea
      Hint: You will need to rewrite or cast the expression.
      Position: 413
        at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2182)
        at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1911)
        at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:173)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:615)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:465)
        at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:411)
        at org.jboss.jca.adapters.jdbc.CachedPreparedStatement.executeUpdate(CachedPreparedStatement.java:119)
        at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:493)
    

    编辑2:

    在尝试 ListToArrayConverter 正如你在回答中提到的,我在坚持的时候遇到了一个例外:

    Internal Exception: org.postgresql.util.PSQLException: ERROR: column "label" is of type text[] but expression is of type character varying
      Hint: You will need to rewrite or cast the expression.
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Simon Martinelli    7 年前

    EclipseLink处理列表的方式与处理任何关系类似,因此它总是用空列表初始化。源代码可以在以下位置找到: https://github.com/eclipse-ee4j/eclipselink

    如果您不喜欢空列表并希望使用空值,则可以创建自己的转换器,如下所示:

    @Converter(autoApply = true)
    public class ListToArrayConveter implements AttributeConverter<List<String>, Object> {
    
        @Override
        public PostgreSQLTextArray convertToDatabaseColumn(List<String> attribute) {
            if (attribute == null || attribute.isEmpty()) {
                return null;
            }
            String[] rst = new String[attribute.size()];
            return new PostgreSQLTextArray(attribute.toArray(rst));
        }
    
        @Override
        public List<String> convertToEntityAttribute(Object dbData) {
                List<String> rst = new ArrayList<>();
            String[] elements = ((String[]) dbData);
            for (String element : elements) {
                rst.add(element);
            }
            if (list.isEmpty()) {
                return null;
            } else {
                return rst;
            }
        }
    }