【问题标题】:Issue with JPA 2.0 EnityManger.createNativeQueryJPA 2.0 EnityManger.createNativeQuery 的问题
【发布时间】:2017-10-03 12:31:06
【问题描述】:

我正在运行以下语句

List<TableA> tableAList = (List<TableA>) entityManager.
                          createNativeQuery(
                          "select colA, colB from tableA", 
                          TableA.class)
                          .getResultList();

TableA 实体

@Enitity
@Column(name = "tableA")
public class TableA {
   @Id
   private Integer id;

   @Column(name = "colA")
   private Integer colA;

   @Column(name = "colB")
   private Integer colB;

   @Column(name = "colC")
   private Integer colC;

   @Column(name = "colD")
   private Integer colD;

   /*
     Corresponding getters and setters. Excluding them for brevity.
   */
}

上面的查询抛出 SQLException that "colC" is not found。如果我在选择列表中添加 colC,它会显示“colD”未找到。本质上,它期望表的所有列都包含在选择查询中。如果我不添加 resultClass 而只是得到List&lt;Object[]&gt; 的响应,则不会发生相同的错误。谁能解释为什么会发生这种行为?

有没有办法以 List 的形式获取响应,将其余字段设置为 null(或默认原语,如果有任何原始字段)?

堆栈跟踪:

java.sql.SQLException: Column 'colC' not found.
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:963)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
    at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1077)
    at com.mysql.jdbc.ResultSetImpl.getLong(ResultSetImpl.java:2759)
    at org.hibernate.type.descriptor.sql.BigIntTypeDescriptor$2.doExtract(BigIntTypeDescriptor.java:63)
    at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:260)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:256)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:246)
    at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:332)
    at org.hibernate.loader.Loader.extractKeysFromResultSet(Loader.java:802)
    at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:727)
    at org.hibernate.loader.Loader.processResultSet(Loader.java:985)
    at org.hibernate.loader.Loader.doQuery(Loader.java:943)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349)
    at org.hibernate.loader.Loader.doList(Loader.java:2615)
    at org.hibernate.loader.Loader.doList(Loader.java:2598)
    at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2430)
    at org.hibernate.loader.Loader.list(Loader.java:2425)
    at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:335)
    at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2153)
    at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:991)
    at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:147)
    at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1410)
    at org.hibernate.query.Query.getResultList(Query.java:146)

注意:我使用的是 JPA 2.0。

【问题讨论】:

  • 您为什么不使用您实际从数据库中选择的字段来定义一个实体?如果您告诉 JPA 结果属于某个类,它将确保从结果集中提取所有属性。结果集中的值可能为空,但结果集中的列必须存在。
  • 如果选择组合是静态的,我会创建一个实体。我正在使用查询生成器,我们可以选择列的任意组合。我还有其他方法可以使选择列动态化吗?
  • 如果您选择动态数量的列,那么将其映射到实体是一件奇怪的事情;当然,您可以重写 SQL 查询以选择其他列作为空值。也就是说,您不想从表中检索的每一列,您在查询中包含为“null AS ”。在您上面的例子中,“选择 a.colA 作为 colA,a.colB 作为 colB,null 作为 colC,null 作为 colD from tableA a”

标签: java mysql hibernate jpa jdbc


【解决方案1】:

当您不指定resultClass 时,JPA 无法知道要给您什么类型的结果,因此它返回一个包含所有列值的数组。每个Object[] 是一个返回行。

如果你不想获取 colC 和 colD,但仍然使用结果类,则必须放入对应名称和数据类型的假字段。

List<TableA> tableAList = (List<TableA>) entityManager.createNativeQuery(
                  "select colA, colB, null as colC, null as colD from tableA", 
                  TableA.class).getResultList();

如果您的字段恰好是原始字段,请使用 0 而不是 null。

【讨论】:

  • 是否有配置或类似 ResultHandler 的东西可以为我做这件事?因为我不想在每个查询中都包含虚拟 null 和默认原始值。
  • 没有。但是,您可以创建一个不同的、更小的实体类来用于此目的。
  • 我做不到。我的实体类通常包含最多 15 个字段,我可以选择它们的任意组合。
  • 那么过滤输出给用户可能会更容易,而不是从数据库中提取。考虑到您说它们最多有 15 个字段,除非其中许多是大型二进制或文本 blob,否则不应消耗性能。我有一个 72 列的表,它的增长速度终于放缓了。
  • 我同意我们可以做到。我很好奇,如果我按照您的建议进行多次数据库调用并每次都执行一次 select *,即使这样也不会导致性能下降?选择多个列不会改变数据库性能。网络开销是最重要的。执行 select * 可能只是网络上的几个字节。但是如果我们有多个数据库调用,那不会降低性能吗?如果未选择,我期待某种填充默认值的东西。比如说 ResultSetHandler。
猜你喜欢
  • 2011-04-05
  • 2013-12-24
  • 2011-12-09
  • 2012-06-01
  • 2011-10-09
  • 2021-03-19
  • 1970-01-01
  • 1970-01-01
  • 2021-09-07
相关资源
最近更新 更多