1

I have a project that uses SpringBoot 1.5.9 (can't change version).

I have these entities :

@Entity
@Table(name = "data")
public class DataEntity extends Timestampable {

    @Column(name = "value")
    private String value;

    @Column(name = "data_timestamp")
    private ZonedDateTime dataTimestamp;

    @ManyToOne
    @JoinColumn
    private DataTypeEntity type;

    @ManyToOne
    @JoinColumn
    private AssetEntity asset;
}

@Entity
@Table(name = "data_type")
public class DataTypeEntity extends Timestampable {

    @Column(name = "name", unique = true)
    private String name;

    ...
}

I have this working SQL query (under PostgreSQL), to retrieve the latest data per asset (source):

SELECT * FROM data d1
JOIN (
  SELECT max(data_timestamp) as newest, asset_id FROM data
  GROUP BY asset_id
) d2
ON d1.data_timestamp = d2.newest AND d1.asset_id = d2.asset_id
WHERE d1.type_id IN (
  SELECT id FROM data_type
  WHERE name = 'ELECTRICITY_CONSUMPTION'
);

I want to translate this query into a JPA CriteriaQuery. Is there a way to do so, or do I need to use a @SubSelect annotation on a specific entity ?

Thanks for reading this !

(UGLY) SOLUTION

I ended up using a database View, with a SubSelect. I've split my DataEntity into 2 entities :

  1. One to manipulate the datas
  2. Anoher that is a view and used only to retrieve the latest data

Base class :

@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractDataEntity extends Timestampable {

    @Column(name = "value")
    protected String value;

    ...

}

Manipulation class :

@Entity
@SequenceGenerator(name = "idgen", sequenceName = "data_seq")
@Table(name = "data")
@DiscriminatorValue("DataEntity")
public class DataEntity extends AbstractDataEntity {
    @Override
    public DataEntity setValue(String value) {
        super.setValue(value);
        return this;
    }

   ...
}

View class :

@Entity
@Immutable
@SequenceGenerator(name = "idgen", sequenceName = "view_data_last_seq")
@DiscriminatorValue("LastDataView")
@Subselect(
    "SELECT * FROM data d1 " +
    "JOIN ( " +
    "  SELECT max(d.data_timestamp) as newest, d.asset_id, d.type_id FROM data d " +
    "  WHERE d.parameter_id IS NULL " +
    "  GROUP BY d.asset_id, d.type_id" +
    ") d2 " +
    "ON d1.data_timestamp = d2.newest " +
    "  AND d1.asset_id = d2.asset_id " +
    "  AND d1.type_id = d2.type_id"
)
public class LastDataView extends AbstractDataEntity {
}

Even if I find this solution ugly, it may help others !

Wykiki
  • 88
  • 8

1 Answers1

1

JPQL does not support subqueries on FROM or JOIN. Only in WHERE or HAVING clauses. Eclipse Link, starting from 2.4, have support for subqueries on the FROM clause.

As every Criteria is converted to the JPQL, it's not possible to use Criteria to do what you want.

Dherik
  • 17,757
  • 11
  • 115
  • 164