【问题标题】:Hibernate Criteria Query to get only specific columns休眠条件查询以仅获取特定列
【发布时间】:2016-08-25 14:16:52
【问题描述】:

我有两个表:ReportRows 和 DataRows

表格报告行:

@Id
@Column(name = "ID")
private Long id;

@ManyToOne
@JoinColumn(name = "T_REPORT_CODE")
  private Report report;

@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "T_DATA_ROWS_ID")
  private DataRow dataRow;

还有 getter 和 setter;

表数据行:

@Id
@Column(name = "ID")
    private Long id;

@Column(name = "VALUE_0")
    private String value0;

@Column(name = "VALUE_1")
    private String value1;

@Column(name = "VALUE_2")
    private String value2;

...

@Column(name = "VALUE_30")
    private String value30;

还有 getter 和 setter

Select from ReportRows 和 DataRows 在列出数据时从两个表中获取所有列。我只需要 DataRows 中的几列(我指定了它)。

选择我想要得到的看起来像这样:

SELECT 
dataRows.value0,
dataRows.value1
from
t_report_rows this_
inner join
t_reports report_ on report_.id = this_.report_id
inner join
t_data_rows dataRows_ on dataRows_.id = this_t_data_rows_id
where report_.id = 1

这只是我写的例子。关键是每个查询我需要不同的列。一次是 value0,value1,第二次是 value0,value2。

当我查询时,我知道我需要哪些列。 我创建这样的标准(列是我从中检索列名称的类):

public List<ReportRow> list(Criteria criteria, Long reportId) {
    criteria.add(Restrictions.eq("report.id", reportId));
    ProjectionList projectionList = Projections.projectionList();
    for (Column col : columnList) {
        String columnName = getColumnId(col);
        projectionList.add(Projections.property(columnName));
        //I also tried like this:
        // projectionList.add(Projections.property(columnName), columnName);
        //or like this:
        //projectionList.add(Projections.property(columnName), getColumnId2(col));
        //also added this line with each of above:
        //criteria.setResultTransformer(Transformers.aliasToBean(ReportRow.class));
    }
    criteria.setProjection(projectionList);

    return list(criteria);
}

方法getColumnId和getColumnId2:

protected String getColumnId(Column col) {
    StringBuilder b = new StringBuilder();
    b.append("dataRow.value");
    b.append(col.getRowIndex());
    return b.toString();
  }

  protected String getColumnId2(Column col) {
    StringBuilder b = new StringBuilder();
    b.append("value");
    b.append(col.getRowIndex());
    return b.toString();
  }

我得到错误: org.hibernate.QueryException:无法解析属性:dataRow.value0

甚至可以做我想做的事吗?根据Projection和存储列索引的表Column仅从表dataRows中获取特定列?

更新 1:
我添加了自定义变压器。一切正常。这样做是为了提高 sql 的速度。现在它正在使用少量列进行查询。真的很棒。我在hibernate中打开了show sql。在自定义转换器之后,它正在为每一行新查询的数据库执行以下操作:

where reportRowId = ?

你知道为什么吗?

自定义 Transformer 的 transformTuple 方法现在看起来像这样:

@Override
  public Object transformTuple(Object[] tuple, String[] aliases) {
    ReportRow row = new ReportRow();
    DataRow dataRow = new DataRow();
    row.setGridRow(dataRow);

    for (int i = 0 ; i < aliases.length; i++) {
      if ("id".equals(aliases[i])) {
        row.setId((Long) tuple[i]);
      } else if ("entityVersion".equals(aliases[i])) {
        row.setEntityVersion((Long) tuple[i]);
      } else if ("dataRowId".equals(aliases[i])) {
        dataRow.setId((Long) tuple[i]);
      } else if ("rowEntityVersion".equals(aliases[i])) {
        dataRow.setEntityVersion((Long) tuple[i]);
      } else if ("value0".equals(aliases[i])) {
        dataRow.setValue0((String) tuple[i]);
      } else if ("value1".equals(aliases[i])) {
        dataRow.setValue1((String) tuple[i]);
      }
    }

    return row;
  }

【问题讨论】:

  • 您的标准是如何创建的?不相关,但您的 getColumnId() 方法可以简化为 return "dataRow.value" + col.getRowIndex();,这将更具可读性并且效率更高。
  • Criteria criteria = getSession().createCriteria(getKind()); getKind 返回类。在此示例中:ReportRow.class
  • 因此,就像在您的 SQL 查询中一样,您需要一个连接:criteria.createAlias("dataRow", "dataRow");
  • 是的,它奏效了。谢谢。我还有一个问题。如果我想在这个查询实体 Report 和列 value0、value1 中也返回我必须做什么?
  • AFAIK,这是不可能的。您可以返回一个实体或列,但不能同时返回。

标签: hibernate criteria projection


【解决方案1】:

我有问题,因为当我 setResultTransformer 它返回对象 带有空变量。例子。 getId() 为空(我添加了 projectionList.add(Projections.property("id"));)

您需要指定投影的别名

projectionList.add(Projections.property("id").as("id"));

是的,它奏效了。谢谢。我还有一个问题。如果我想退货 也在这个查询实体报告和列 value0, value1 什么我 必须做什么?

您可以通过指定其列的投影来获得Report 的一部分。您需要使用嵌套投影将ReportRows 作为根和ReportDataRow 的属性。

对于嵌套投影,您可以使用自定义转换器

How to transform a flat result set using Hibernate

【讨论】:

    【解决方案2】:
    session = sessionFactory.openSession();
    Criteria criteria = session.createCriteria(DlrStatus.class);
    criteria.add(Restrictions.eq("userId",userId)).add(Restrictions.eq("jobId",jobId))
            .add(Restrictions.eq("status", status)).setFirstResult(start).setMaxResults(max).addOrder(Order.desc("id"));
    ProjectionList projectionList = Projections.projectionList();
    projectionList.add(Projections.property("mobile").as("mobile"));
    projectionList.add(Projections.property("Sender").as("sender"));
    projectionList.add(Projections.property("message").as("message"));
    projectionList.add(Projections.property("loggedAt").as("loggedAt"));
    projectionList.add(Projections.property("dlrTime").as("dlrTime"));
    criteria.setProjection(projectionList);
    criteria.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
    List<DlrStatus> list = criteria.list();
    

    【讨论】:

    • 能否请您对此代码添加一些解释 - 尤其是让未来的读者了解问题所在。
    猜你喜欢
    • 2012-07-22
    • 1970-01-01
    • 2017-07-12
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 2011-06-08
    相关资源
    最近更新 更多