HibernateException: Errors in named query

mathematician picture mathematician · May 13, 2013 · Viewed 14k times · Source

When running a particular unit-test, I am getting the exception:

Caused by: org.hibernate.HibernateException: Errors in named queries: UPDATE_NEXT_FIRE_TIME
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:437)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1385)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:954)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:891)
... 44 more

for the named query defined here:

@Entity(name="fireTime")
@Table(name="qrtz_triggers")
@NamedQueries({
@NamedQuery(
        name="UPDATE_NEXT_FIRE_TIME",
        query= "update fireTime t set t.next_fire_time = :epochTime where t.trigger_name = 'CalculationTrigger'")
})
public class JpaFireTimeUpdaterImpl implements FireTimeUpdater {

@Id
@Column(name="next_fire_time", insertable=true, updatable=true)
private long epochTime;

public JpaFireTimeUpdaterImpl() {}

public JpaFireTimeUpdaterImpl(final long epochTime) {
    this.epochTime = epochTime;
}

@Override
public long getEpochTime() {
    return this.epochTime;
}

public void setEpochTime(final long epochTime) {
    this.epochTime = epochTime;
}

}

After debugging as deep as I could, I've found that the exception occurs in w.statement(hqlAst) in QueryTranslatorImpl:

    private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException {
    HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole );
    AST hqlAst = parser.getAST();

    // Transform the tree.
    w.statement( hqlAst );

    if ( AST_LOG.isDebugEnabled() ) {
        ASTPrinter printer = new ASTPrinter( SqlTokenTypes.class );
        AST_LOG.debug( printer.showAsString( w.getAST(), "--- SQL AST ---" ) );
    }

    w.getParseErrorHandler().throwQueryException();

    return w;
}

Is there something wrong with my query or annotations?

Answer

Mikko Maunu picture Mikko Maunu · May 13, 2013

NamedQuery should be written with JPQL, but query seems to mix both names of persistent attributes and names of database columns. Names of database columns cannot be used in JPQL.

In this case instead of next_fire_time name of the persistent attribute epochTime should be used. Also trigger_name looks more like name of the database column than name of the persistent attribute, but it seems not to be mapped in your current class at all. After it is mapped, query is as follows:

update fireTime t set t.epochTime = :epochTime 
where t.triggerName = 'CalculationTrigger'

If SQL query is preferred, then @NamedNativeQuery should be used instead.

As a side note, JPA 2.0 specification doesn't encourage changing primary key:

The application must not change the value of the primary key[10]. The behavior is undefined if this occurs.[11]

In general entities are not aware of changed made via JPQL queries. That gets especially interesting when trying to refresh entity that does not exist anymore (because primary key was changed).

Additionally naming is little bit confusing:

  1. Name of the class looks more like name of the service class than name of the entity.
  2. Starting name of the entity with lower case letter is rather rare style.
  3. Name of the entity, name of the table and name of the class do not match too well.