Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate Criteria Query to get only specific columns

I have two tables: ReportRows and DataRows

Table ReportRows:

@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;

additionally getters and setters;

Table DataRows:

@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;

additionally getters and setters

Select from ReportRows and DataRows gets all columns from both tables when listing data. I need only a few columns from DataRows (i specify it).

Select which I want to get looks like this:

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

It is only example which I wrote. The point is I need different columns each query. One time it will be value0, value1, second time it would be value0, value2.

When I do query I know which columns I need. I create criteria like this (Columns is class from which I retrive names of columns):

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);
}

Methods getColumnId and 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();
  }

I get error: org.hibernate.QueryException: could not resolve property: dataRow.value0

Is it even possible to do what I want? Get only specific columns from table dataRows based on Projection and table Column which store columns indexes?

Update 1:
I added custom transformer. Everything works fine. It was done to increase speed of sql. Now it is doing query with small amount of columns. It's really good. I turned on show sql in hibernate. After custom transformer it is doing to database for each row new query with:

where reportRowId = ?

Do you know why?

Custom Transformer transformTuple method looks like this for now:

@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;
  }
like image 318
Caroline Avatar asked Apr 30 '16 12:04

Caroline


2 Answers

I have problem because when I setResultTransformer it returns objects with null variables. Example. getId() is null (I added projectionList.add(Projections.property("id"));)

You need to specify an alias of the projection

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

Yes, it worked. Thanks. I have one more question. If I want return also in this query entity Report and columns value0, value1 what I have to do?

You can get a part of Report by specifying projections for columns of it. You need to get ReportRows as root and properties of Report and DataRow using nested projections.

For nested projections you can use a custom transformer

How to transform a flat result set using Hibernate

like image 151
v.ladynev Avatar answered Jan 04 '23 02:01

v.ladynev


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();
like image 40
Pramod Verma Avatar answered Jan 04 '23 02:01

Pramod Verma