Hibernate Books

All times are UTC - 5 hours [ DST ]



Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: javax.persistence.NamedQuery annotation and query cache
PostPosted: Tue Aug 16, 2005 3:42 am 
Newbie

Joined: Wed Oct 06, 2004 4:15 am
Posts: 16
Hibernate version:
3.1 beta 1

Hi all,

I'm mapping entities with the new annotation classes, using javax.persistence ones (when possible). In order to activate the cache on the entities, I'm using the hibernate "@Cache" annotation, but, when looking at the query cache, I cannot mark a query as "cacheable", because there is no hibernate "NamedQuery" annotation extending the javax.persistence one and allowing me to set cacheable to true.

Any hints or guidelines would be greatly appreciated,

Kind regards,

Carlos


Top
 Profile  
 
 Post subject:
PostPosted: Tue Aug 16, 2005 4:24 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
use a hint:

From org.hibernate.ejb.QueryImpl

Code:
   public Query setHint(String hintName, Object value) {
      try {
         if ( "org.hibernate.timeout".equals( hintName ) ) {
            query.setTimeout( (Integer) value );
         }
         else if ( "org.hibernate.comment".equals( hintName ) ) {
            query.setComment( (String) value );
         }
         else if ( "org.hibernate.fetchSize".equals( hintName ) ) {
            query.setFetchSize( (Integer) value );
         }
         else if ( "org.hibernate.cacheRegion".equals( hintName ) ) {
            query.setCacheRegion( (String) value );
         }
         else if ( "org.hibernate.cacheable".equals( hintName ) ) {
            query.setCacheable( (Boolean) value );
         }
         else if ( "org.hibernate.readOnly".equals( hintName ) ) {
            query.setReadOnly( (Boolean) value );
         }
         else if ( "org.hibernate.cacheMode".equals( hintName ) ) {
            query.setCacheMode( (CacheMode) value );
         }
         else if ( "org.hibernate.flushMode".equals( hintName ) ) {
            query.setFlushMode( (FlushMode) value );
         }
         //TODO:
         /*else if ( "org.hibernate.lockMode".equals( hintName ) ) {
            query.setLockMode( alias, lockMode );
         }*/
      }
      catch (ClassCastException e) {
         throw new IllegalArgumentException( "Value for hint" );
      }
      return this;
   }


Top
 Profile  
 
 Post subject: non-programmatic solution
PostPosted: Wed Aug 17, 2005 7:08 am 
Newbie

Joined: Wed Oct 06, 2004 4:15 am
Posts: 16
Gavin,

Unfortunately, this solution does not apply for us, as we're hiding our query execution code using a DAO-style pattern, and this should force us to mark every query as cacheable (adding cacheable hints to every query executed with this code).

In fact, we know when we design the application, what queries are cacheable and what queries are not. Using the former .hbm.xml files, one can mark (at design time) the cacheable queries (among other properties)

<!-- The query element declares a named Hibernate query string -->

<!ELEMENT query (#PCDATA|representation)*>
<!ATTLIST query name CDATA #REQUIRED>
<!ATTLIST query flush-mode (auto|never|always) #IMPLIED>
<!ATTLIST query cacheable (true|false) "false">
<!ATTLIST query cache-region CDATA #IMPLIED>
<!ATTLIST query fetch-size CDATA #IMPLIED>
<!ATTLIST query timeout CDATA #IMPLIED>

As you're doing with other annotations, one possible solution is to create an hibernate annotation (extending the javax.persistence one) allowing to mark this at design time, thus providing similar capabilities when using annotations or .hbm.xml mapping style.

If this feature is not implemented yet, I can help implementing it with some guidelines from you.

TIA,

Best regards,

Carlos


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 17, 2005 8:24 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7179
Location: Atlanta, USA
Create a org.hibernate.annotations.NamedQuery
with all these params and the ones of @javax.persistence.NamedQuery
Then check in the annotations projects where NamedQuery are used, it should be straightworward.

_________________
Emmanuel
Check Hibernate Search in Action out


Top
 Profile  
 
 Post subject: NamedQuery class
PostPosted: Wed Aug 17, 2005 11:13 am 
Newbie

Joined: Wed Oct 06, 2004 4:15 am
Posts: 16
Emmanuel,

Some comments about the code attached below:

*I have added not only the EJB3 attributes and attributes found in the old .hbm.xml, but also added, after reviewing the hints, the "cacheMode", "comment" and "readOnly" attributes, therefore allowing to expose the full functionality under annotations.

*I have created a CacheModeType enum including the CacheModes in the 3.0 documentation (PUT, GET, REFRESH,...)

*The fetchSize attribute is very similar to the BatchSize you have created, and maybe it's okay not to put a bare int, but replace with a @BatchSize

*The FlushModeType is the one from javax.persistence, is this okay or do we have to duplicate the class under the org.hibernate.annotations branch? (it depends on your policy to solve this issue)

*Check the defaults for coherence with other defaults (i.e. flushmode, fetchsize, timeout, ...)

If you want me to upload the code in any specific way (i.e. through jira or cvs), please let me know the details.

Now having the annotation, maybe the binder (or some other component of the hibernate core) has to be modified?. Is this ok?. If so, I can help with that....

Kind regards,

Carlos



package org.hibernate.annotations;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.persistence.FlushModeType;

/**
* Extends {@link javax.persistence.NamedQuery} with Hibernate features
* @author Emmanuel Bernard
* @author Carlos González-Cadenas
*/
@Target(TYPE) @Retention(RUNTIME)
public @interface NamedQuery {

/** the name of the NamedQuery */
String name();
/** the Query String for the NamedQuery */
String queryString();
/** the flush mode for the query */
FlushModeType flushMode() default FlushModeType.AUTO;
/** mark the query as cacheable or not */
boolean cacheable() default false;
/** the cache region to use */
String cacheRegion() default "";
//maybe batchsize??. Check defaults for hibernate.
/**the number of rows fetched by the JDBC Driver per roundtrip*/
int fetchSize() default 50;
/**the query timeout in seconds*/
int timeout() default 10;
//following these from the hints, review them
/**comment added to the SQL query, useful for the DBA */
String comment() default "";
/**the cache mode used for this query*/
CacheModeType cacheMode() default CacheModeType.NORMAL;
/**marks whether the results are fetched in read-only mode or not*/
boolean readOnly() default false;

}


package org.hibernate.annotations;

/**
* Enumeration for the different interaction modes between the session and the Level 2 Cache.
* @author Emmanuel Bernard
* @author Carlos González-Cadenas
*/

public enum CacheModeType {
GET,
IGNORE,
NORMAL,
PUT,
REFRESH
}


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 17, 2005 12:03 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7179
Location: Atlanta, USA
FetchSize is fine with a int
Let's use a specific FlushMode, there is the ALWAYS mode in Hibernate.

I'd be cool if you update AnnotationBinder and co and provide the result as a patch in CVS.
Be sure to create it from the HEAD

You will not have to update the core.

<target name="patch" depends="checkstyle"
description="Create a patch">
<cvs command="-q diff -u -N" output="patch.txt"/>
</target>

Thank's man

_________________
Emmanuel
Check Hibernate Search in Action out


Top
 Profile  
 
 Post subject: done!
PostPosted: Wed Aug 17, 2005 4:03 pm 
Newbie

Joined: Wed Oct 06, 2004 4:15 am
Posts: 16
Hi Emmanuel,

The modifications you requested are implemented and tested successfully,

I have tested an anotation like this:

@NamedQuery(name="findTargetByName", queryString="...", cacheable=true, cacheRegion="core:model")

and hibernate is working as expected (obtaining the cached results from the correspondent region).

There are three properties (obtained from the hint definition), "comment", "cacheModeType" and "readOnly" that cannot be integrated with the core, because the NamedQueryDefinition doesn't allow them, and the only way now would be to do a "setHint" on a query (runtime, not design time). I appreciate that these properties are interesting enough to be included also under annotations (but these require modifications in the NamedQueryDefinition).

Unfortunately, due to corporative firewall restrictions, I cannot access to the CVS to obtain the latest HEAD, so I cannot make the patch for you. I will paste the code and the modifications needed. Sorry for the inconvenience.

Please give me a reply to this message as an ACK.

Do you see any factible solution for these three attributes cited above (the ones related with the hints)?

TIA,

Kind Regards,

Carlos González-Cadenas


-------------------------------------------------------------------

package org.hibernate.annotations;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
* Extends {@link javax.persistence.NamedQueries} to hold hibernate NamedQuery
* objects
* @author Emmanuel Bernard
* @author Carlos González-Cadenas
*/
@Target(TYPE) @Retention(RUNTIME)
public @interface NamedQueries {
NamedQuery[] value();
}


----------------------------------------------------

package org.hibernate.annotations;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
* Extends {@link javax.persistence.NamedQuery} with Hibernate features
* @author Emmanuel Bernard
* @author Carlos González-Cadenas
*/
@Target(TYPE) @Retention(RUNTIME)
public @interface NamedQuery {

/** the name of the NamedQuery */
String name();
/** the Query String for the NamedQuery */
String queryString();
/** the flush mode for the query */
FlushModeType flushMode() default FlushModeType.AUTO;
/** mark the query as cacheable or not */
boolean cacheable() default false;
/** the cache region to use */
String cacheRegion() default "";
/**the number of rows fetched by the JDBC Driver per roundtrip*/
int fetchSize() default 50;
/**the query timeout in seconds*/
int timeout() default 10;

//TODO: For the moment parameters associated to hints (see below) cannot be
//bound to the NamedQueryDefinition using the QueryBinder
/**comment added to the SQL query, useful for the DBA */
//String comment() default "";
/**the cache mode used for this query*/
//CacheModeType cacheMode() default CacheModeType.NORMAL;
/**marks whether the results are fetched in read-only mode or not*/
//boolean readOnly() default false;

}

----------------------------------------------------------------------

package org.hibernate.annotations;

/**
* Enumeration extending javax.persistence flush modes.
* @author Emmanuel Bernard
* @author Carlos González-Cadenas
*/

public enum FlushModeType {
ALWAYS,
AUTO,
COMMIT,
NEVER,
}

-------------------------------------------------------------------------

package org.hibernate.annotations;

/**
* Enumeration for the different interaction modes between the session and
* the Level 2 Cache.
* @author Emmanuel Bernard
* @author Carlos González-Cadenas
*/

public enum CacheModeType {
GET,
IGNORE,
NORMAL,
PUT,
REFRESH
}

--------------------------------------------------------------------------

Modifications for AnnotationBinder: replace method bindQueries by the one pasted below

private static void bindQueries(AnnotatedElement annotatedElement, ExtendedMappings mappings) {
{
SqlResultSetMapping ann = annotatedElement.getAnnotation(SqlResultSetMapping.class);
QueryBinder.bindSqlResultsetMapping(ann, mappings);
}
{
NamedQuery ann = annotatedElement.getAnnotation(NamedQuery.class);
QueryBinder.bindQuery(ann, mappings);
}
{
org.hibernate.annotations.NamedQuery ann = annotatedElement.getAnnotation(org.hibernate.annotations.NamedQuery.class);
QueryBinder.bindQuery(ann, mappings);
}

{
NamedQueries ann = annotatedElement.getAnnotation(NamedQueries.class);
QueryBinder.bindQueries(ann, mappings);
}
{
org.hibernate.annotations.NamedQueries ann = annotatedElement.getAnnotation(org.hibernate.annotations.NamedQueries.class);
QueryBinder.bindQueries(ann, mappings);
}
{
NamedNativeQuery ann = annotatedElement.getAnnotation(NamedNativeQuery.class);
QueryBinder.bindNativeQuery(ann, mappings);
}
{
NamedNativeQueries ann = annotatedElement.getAnnotation(NamedNativeQueries.class);
QueryBinder.bindNativeQueries(ann, mappings);
}
}

-------------------------------------------------------------

Modifications for QueryBinder: Add these two methods

public static void bindQuery(org.hibernate.annotations.NamedQuery queryAnn, ExtendedMappings mappings){
if (queryAnn == null) return;
if ( AnnotationBinder.isDefault( queryAnn.name() ) ) {
throw new AnnotationException("A named query must have a name when used in class or package level");
}

FlushMode flushMode;

if (queryAnn.flushMode() == FlushModeType.ALWAYS) flushMode = FlushMode.ALWAYS;
else if (queryAnn.flushMode() == FlushModeType.AUTO) flushMode = FlushMode.AUTO;
else if (queryAnn.flushMode() == FlushModeType.COMMIT) flushMode = FlushMode.COMMIT;
else if (queryAnn.flushMode() == FlushModeType.NEVER) flushMode = FlushMode.NEVER;
else throw new AnnotationException("Unknown flushModeType: "+queryAnn.flushMode());


NamedQueryDefinition query = new NamedQueryDefinition(
queryAnn.queryString(),
queryAnn.cacheable(),
queryAnn.cacheRegion(),
queryAnn.timeout(),
queryAnn.fetchSize(),
flushMode,
null);

mappings.addQuery(queryAnn.name(), query);
log.debug( "Named query " + queryAnn.name() + " => " + queryAnn.queryString() );
}



public static void bindQueries(org.hibernate.annotations.NamedQueries queriesAnn, ExtendedMappings mappings) {
if (queriesAnn == null) return;
for ( org.hibernate.annotations.NamedQuery q : queriesAnn.value() ) {
bindQuery(q, mappings);
}
}


Top
 Profile  
 
 Post subject:
PostPosted: Thu Aug 18, 2005 10:07 am 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7179
Location: Atlanta, USA
OK I'll look at your patch.
But I won't bind the extra hint attributes until the next Hibernate3 core milestone.

PS: CVSGrab, goes beyond FW

_________________
Emmanuel
Check Hibernate Search in Action out


Top
 Profile  
 
 Post subject: thanks
PostPosted: Thu Aug 18, 2005 10:10 am 
Newbie

Joined: Wed Oct 06, 2004 4:15 am
Posts: 16
Emmanuel,

Many thanks for your kindly attention,

Best regards,

Carlos González-Cadenas


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 19, 2005 2:14 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7179
Location: Atlanta, USA
Thanks,
I've integrated the first part (ie wo core changes), added support for parameters in @NamedNativeQuery, and added a test suite.
Don't forget the test suite, it's not a feature otherwise :-)

_________________
Emmanuel
Check Hibernate Search in Action out


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.