2

Under Hibernate < 5.2, it was possible to have generic SQL queries like

String sql = "select a, b, sum (c) csum from a group by a, b";
SQLQuery q = session.createSqlQuery (sql);
q
    .addScalar ("a", IntegerType.INSTANCE)
    .addScalar ("b", IntegerType.INSTANCE)
    .addScalar ("csum", IntegerType.INSTANCE);
q.setResultTransformer (new AliasToBeanResultTransformer (RankingModel.class));
List<RankingModel> results = q.list ();

Where RankingModel looks like:

public class RankingModel
{
    public int a, b, csum;
}

However, with 5.2, addScalar(), setResultTransformer() have all been deprecated, with the recommendation to use session.createNativeQuery() instead. The nearest equivalent to the above I have is:

String sql = "select a, b, sum (c) csum from a group by a, b";
NativeQuery<RankingModel> q = session.createNativeQuery (sql, RankingModel.class);
List<RankingModel> results = q.list ();

However, this code fails with:

org.hibernate.MappingException: Unknown entity: ... RankingModel] with root cause
org.hibernate.MappingException: Unknown entity: ... RankingModel
    at org.hibernate.metamodel.internal.MetamodelImpl.entityPersister(MetamodelImpl.java:620)
    at org.hibernate.engine.spi.SessionFactoryImplementor.getEntityPersister(SessionFactoryImplementor.java:335)
    at org.hibernate.loader.custom.sql.SQLQueryReturnProcessor.getSQLLoadable(SQLQueryReturnProcessor.java:358)
    at org.hibernate.loader.custom.sql.SQLQueryReturnProcessor.processRootReturn(SQLQueryReturnProcessor.java:411)
    at org.hibernate.loader.custom.sql.SQLQueryReturnProcessor.processReturn(SQLQueryReturnProcessor.java:378)
    at org.hibernate.loader.custom.sql.SQLQueryReturnProcessor.process(SQLQueryReturnProcessor.java:180)
    at org.hibernate.loader.custom.sql.SQLCustomQuery.<init>(SQLCustomQuery.java:71)
    at org.hibernate.engine.query.internal.NativeQueryInterpreterStandardImpl.createQueryPlan(NativeQueryInterpreterStandardImpl.java:70)
    at org.hibernate.engine.query.spi.QueryPlanCache.getNativeSQLQueryPlan(QueryPlanCache.java:213)
    at org.hibernate.internal.AbstractSharedSessionContract.getNativeQueryPlan(AbstractSharedSessionContract.java:550)
    at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:992)
    at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:148)

Anyone have any idea what I'm missing?

Jonathan
  • 859
  • 7
  • 15
  • Can you post your `RankingModel.java`? It seems like that object doesn't have `a`, `b`, and `sum` as instance variables. – lxcky May 10 '17 at 00:20
  • The in the javadoc, after the deprecation warning, there is this comment : `@todo develop a new approach to result transformers`... There might be no defined migration path for now. This nearest concept is `ResultSetMapping`, but i'm not sure it is as flexible as resultset transformers. – Thierry May 10 '17 at 11:38

3 Answers3

0

You can try to fix by using

String sql = "select a, b, sum (c) csum from a group by a, b";
NativeQuery<?> q = session.createNativeQuery (sql);
List<RankingModel> results = (List<RankingModel>)q.list ();

It will work but in IDE it will throw warning.

Or

String sql = "select a, b, sum (c) csum from a group by a, b";
    NativeQuery<?> q = session.createNativeQuery (sql).addSynchronizedEntityClass( RankingModel.class );
    List<RankingModel> results = (List<RankingModel>)q.list ();
rajadilipkolli
  • 3,475
  • 2
  • 26
  • 49
0
String sql = "SELECT a, b, sum(c) csum FROM a GROUP BY a, b";
NativeQuery<RankingModel> q = session.createNativeQuery(sql, RankingModel.class);
List<RankingModel> results = q.list();
teicionx
  • 9
  • 1
0

To tell Hibernate to use custom entity (data bean) classes like RankingModel.java, you have to annotate each such class with @Entity and each assignable column (field) with either @Id or @Column, as per JPA specification. In fact, Hibernate does its best to respect JPA 2.0 contract and supports all relevant Java annotations from javax.persistence package.

While doing so, make sure each entity class has a unique identifier field as mentioned in hibernate exception: org.hibernate.AnnotationException: No identifier specified for entity: com..domain.idea.MAE_MFEView

Here is what your entity class should look like:

@Entity
public class RankingModel
{
    @Id
    public int id;

    @Column
    public int a;

    @Column
    public int b;

    @Column
    public int csum;
}

If the entity is to be persisted in the database, then the class has to be annotated with @Table, as well. This explicitly tells Hibernate which database table to use for the entity persistence. For fetching the data only, annotation is not necessary, I believe.

Finally, tell Hibernate to actually look up all the (annotated) entity classes. This can be achieved by referencing them from hbm.xml, or, for Java purists like myself, by listing Java packages to scan as an argument to LocalSessionFactoryBean constructor, as nicely explained in How to scan packages for Hibernate entities instead of using hbm.xml?

leonidos79
  • 158
  • 2
  • 8