【问题标题】:EclipseLink native query result into POJO - Missing descriptor for [Class]EclipseLink 本机查询结果到 POJO - [Class] 缺少描述符
【发布时间】:2013-02-10 20:56:58
【问题描述】:

我正在使用 EclipseLink 运行一些本机 SQL。我需要将数据返回到 POJO。我按照EclipseLink Docs 的说明进行操作,但收到错误Missing descriptor for [Class]

已命名查询列以匹配 POJO 的成员变量。我需要做一些额外的映射吗?

POJO:

public class AnnouncementRecipientsFlattenedDTO {

        private BigDecimal announcementId;
        private String recipientAddress;
        private String type;

        public AnnouncementRecipientsFlattenedDTO() {
            super();
        }

        public AnnouncementRecipientsFlattenedDTO(BigDecimal announcementId, String recipientAddress, String type) {
            super();
            this.announcementId = announcementId;
            this.recipientAddress = recipientAddress;
            this.type = type;
        }

    ... Getters/Setters

实体管理器调用:

public List<AnnouncementRecipientsFlattenedDTO> getNormalizedRecipientsForAnnouncement(int announcementId) {
    Query query = em.createNamedQuery(AnnouncementDeliveryLog.FIND_NORMALIZED_RECIPIENTS_FOR_ANNOUNCEMENT, AnnouncementRecipientsFlattenedDTO.class);
    query.setParameter(1, announcementId);
    return query.getResultList();
}

【问题讨论】:

    标签: jpa eclipselink


    【解决方案1】:

    遇到了同样的问题,我想返回一个 POJO 列表,实际上只是 POJO(如果你愿意,可以称之为 DTO)而不是 @Entity 注释对象。

    class PojoExample {
    
      String name;
    
      @Enumerated(EnumType.STRING)
      SomeEnum type;
    
      public PojoExample(String name, SomeEnum type) {
        this.name = name;
        this.type = type;
      }
    }
    

    使用以下查询:

    String query = "SELECT b.name, a.newtype as type FROM tablea a, tableb b where a.tableb_id = b_id";
    
    Query query = getEntityManager().createNativeQuery(query, "PojoExample");
    
    @SuppressWarnings("unchecked")
    List<PojoExample> data = query.getResultList();
    

    从数据库中创建 PojoExample,而不需要 PojoExample 上的实体注解。你可以在Oracle Docs here找到方法调用。

    编辑: 事实证明,您必须使用 @SqlResultSetMapping 才能使其工作,否则您的 query.getResultList() 将返回一个对象列表。

    @SqlResultSetMapping(name = "PojoExample", 
      classes = @ConstructorResult(columns = {
        @ColumnResult(name = "name", type = String.class), 
        @ColumnResult(name = "type", type = String.class)
      }, 
      targetClass = PojoExample.class)
     )
    

    只需将它放在@Entity 注释下的任何位置(因此在此示例中,在 tablea 或 tableb 中,因为 PojoExample 没有 @Entity 注释)

    【讨论】:

      【解决方案2】:

      另外,不要忘记在persistence.xml 中添加您的 POJO 类!如果您习惯于 IDE 为您管理该文件,这很容易被忽略。

      【讨论】:

        【解决方案3】:

        老问题,但可能会遵循解决方案将帮助其他人。

        假设您要返回 Oracle 中给定表的列、数据类型和数据长度的列表。我在下面写了一个本机示例查询:

          private static final String TABLE_COLUMNS = "select utc.COLUMN_NAME, utc.DATA_TYPE, utc.DATA_LENGTH "
                + "from user_tab_columns utc "
                + "where utc.table_name = ? "                
                + "order by utc.column_name asc";
        

        现在的需求是根据上面的查询结果构造一个POJO列表。

        定义TableColumn实体类如下:

        @Entity
        public class TableColumn implements Serializable {
        
        @Id
        @Column(name = "COLUMN_NAME")
        private String columnName;
        @Column(name = "DATA_TYPE")
        private String dataType;
        @Column(name = "DATA_LENGTH")
        private int dataLength;
        
        public String getColumnName() {
            return columnName;
        }
        
        public void setColumnName(String columnName) {
            this.columnName = columnName;
        }
        
        public String getDataType() {
            return dataType;
        }
        
        public void setDataType(String dataType) {
            this.dataType = dataType;
        }
        
        public int getDataLength() {
            return dataLength;
        }
        
        public void setDataLength(int dataLength) {
            this.dataLength = dataLength;
        }
        
        public TableColumn(String columnName, String dataType, int dataLength) {
            this.columnName = columnName;
            this.dataType = dataType;
            this.dataLength = dataLength;
        }
        
        public TableColumn(String columnName) {
            this.columnName = columnName;
        }
        
        public TableColumn() {
        }
        
        @Override
        public int hashCode() {
            int hash = 0;
            hash += (columnName != null ? columnName.hashCode() : 0);
            return hash;
        }
        
        @Override
        public boolean equals(Object object) {
        
            if (!(object instanceof TableColumn)) {
                return false;
            }
            TableColumn other = (TableColumn) object;
            if ((this.columnName == null && other.columnName != null) || (this.columnName != null && !this.columnName.equals(other.columnName))) {
                return false;
            }
            return true;
        }
        
        @Override
        public String toString() {
            return getColumnName();
        }
        
        }
        

        现在我们准备构建一个 POJO 列表。使用下面的示例代码构建获取结果作为 POJO 列表。

        public List<TableColumn> findTableColumns(String table) {
            List<TableColumn> listTables = new ArrayList<>();
            EntityManager em = emf.createEntityManager();
            Query q = em.createNativeQuery(TABLE_COLUMNS, TableColumn.class).setParameter(1, table);
            listTables = q.getResultList();
            em.close();
            return listTables;
        }
        

        【讨论】:

        • 这会在数据库中创建一个名为 TableColumn 的新表。还有其他解决方案吗?
        • @scarface 您似乎将javax.persistence.schema-generation.database.action 设置为none 以外的其他值。避免使用 JPA 生成表的原因有很多:您的应用程序可能没有更改布局的权限。 JPA 的功能也受到限制(例如,不支持部分索引 afaik)。我建议关闭 JPA 创建表,使用 SQL 脚本创建表并为应用程序使用权限较低的帐户。
        【解决方案4】:

        我发现您可以将本机查询执行的结果放入包含对象的数组列表中。然后可以遍历列表和数组元素并构建所需的实体对象。

        List<Object[]> rawResultList;
        
            Query query =
                em.createNamedQuery(AnnouncementDeliveryLog.FIND_NORMALIZED_RECIPIENTS_FOR_ANNOUNCEMENT);
            rawResultList = query.getResultList();
        
            for (Object[] resultElement : rawResultList) {
                AnnouncementDeliveryLog adl = new AnnouncementDeliveryLog(getAnnouncementById(announcementId), (String)resultElement[1], (String)resultElement[2], "TO_SEND");
                persistAnnouncementDeliveryLog(adl);
            }
        

        【讨论】:

          【解决方案5】:

          如果类已映射,则只能对类使用本机 SQL 查询。您需要将 AnnouncementRecipientsFlattenedDTO 类定义为 @Entity。

          否则,只需使用 SQL 创建本机查询并获​​取数据数组,然后使用数据自己构建 DTO。

          【讨论】:

          • 实体必须与表关联还是可以独立存在?
          • 这绝对是解决问题的答案。万一您想映射到 DTO,那么您可以使用 @SqlResultSetMapping
          猜你喜欢
          • 2012-02-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-31
          • 1970-01-01
          • 2015-05-12
          • 1970-01-01
          • 2018-07-07
          相关资源
          最近更新 更多