-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Global filters
PostPosted: Tue Oct 19, 2010 2:37 am 
Newbie

Joined: Tue Oct 19, 2010 2:20 am
Posts: 3
Hi,

I've seen this question asked a number of times but nobody seems to have got the answer that they or I am looking for :-)

Is there a way to define a filter that is applied to ALL queries on ALL tables?

Our use case is that we are storing historical data in the same tables as current data and using this pattern across all entity tables in our database. So I want to apply a filter like:

:when >= from and :when < to

to all queries.

I am able to get this working (rather verbosely) by specifying the filter on all of my entities and all of my joins except for many-to-one scenarios as these do not support a filter. I read an earlier discussion where some people claimed that it wouldn't make sense on a many-to-one association but it does make sense if the referenced table contains historical data and the id defined in the hibernate mapping isn't actually the primary key of the table but would be unique if the effective date filter were applied.

So...I'd like to know if

a) there is a way to define a filter on many-to-one, and
b) can I define the filter ONCE and have it apply automatically to EVERY table in EVERY select statement that gets created. i.e. in a join scenario, the filter would be applied multiple times within the one select.

Another option (which probably makes more sense actually) is that I define the filter on each entity but it gets applied whenever that entity is queried, not just when it is the base class being fetched. i.e. it also applies to joins to that table via one-to-many, many-to-one etc. Currently it doesn't do this and you have to specify them explicitly on every assocation as well as the entities themselves (except as mentioned, for many-to-one as it isn't available there).

Yet another option would be to provide a method (perhaps on the Interceptor or a listener class) where I can inject a custom where clause fragment into all queries on a per table basis.

Any suggestions?

Thanks in advance, Damon


Top
 Profile  
 
 Post subject: Re: Global filters
PostPosted: Tue Oct 19, 2010 4:45 am 
Newbie

Joined: Tue Oct 19, 2010 2:20 am
Posts: 3
I've just realised that I should be able to do this using a custom persister class which overrides either filterFragment or getSQLWhereString.


Top
 Profile  
 
 Post subject: Re: Global filters
PostPosted: Tue Oct 19, 2010 9:03 pm 
Newbie

Joined: Tue Oct 19, 2010 2:20 am
Posts: 3
I got this working using the following custom classes:

Code:
package com.mycompany.myapp;

import static com.mycompany.myapp.EffectiveFilterHelper.effectiveFilterCondition;

import org.hibernate.HibernateException;
import org.hibernate.cache.access.EntityRegionAccessStrategy;
import org.hibernate.engine.Mapping;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.persister.entity.SingleTableEntityPersister;

public class VersionedSingleTableEntityPersister extends SingleTableEntityPersister {

  private String fromTableAlias;

  public VersionedSingleTableEntityPersister(PersistentClass persistentClass,
      EntityRegionAccessStrategy cacheAccessStrategy, SessionFactoryImplementor factory, Mapping mapping)
      throws HibernateException {
    super(persistentClass, cacheAccessStrategy, factory, mapping);
  }

  public String fromTableFragment(String name) {
    this.fromTableAlias = name;
    return super.fromTableFragment(name);
  }

  public String fromJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
    String sql = super.fromJoinFragment(alias, innerJoin, includeSubclasses);
    if (!alias.equals(this.fromTableAlias)) {
      sql += effectiveFilterCondition(alias);
    }
    return sql;
  }

  public String whereJoinFragment(String alias, boolean innerJoin, boolean includeSubclasses) {
    return super.whereJoinFragment(alias, innerJoin, includeSubclasses) + effectiveFilterCondition(alias);
  }

}


Code:
package com.mycompany.myapp;

import static com.mycompany.myapp.EffectiveFilterHelper.effectiveFilterCondition;

import org.hibernate.MappingException;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
import org.hibernate.cfg.Configuration;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.mapping.Collection;
import org.hibernate.persister.collection.BasicCollectionPersister;

public class VersionedBasicCollectionPersister extends BasicCollectionPersister {

  public VersionedBasicCollectionPersister(Collection collection, CollectionRegionAccessStrategy cacheAccessStrategy,
      Configuration cfg, SessionFactoryImplementor factory) throws MappingException, CacheException {
    super(collection, cacheAccessStrategy, cfg, factory);
  }

  protected String filterFragment(String alias) throws MappingException {
    return super.filterFragment(alias) + effectiveFilterCondition(alias);
  }

}


Code:
package com.mycompany.myapp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EffectiveFilterHelper {

  private static final Logger logger = LoggerFactory.getLogger(EffectiveFilterHelper.class);

  public static String effectiveFilterCondition(String alias) {
    if (logger.isDebugEnabled()) {
      logger.debug("adding effective filter condition for " + alias);
    }
    return " and :effective.when >= " + alias + ".from_ts and :effective.when < " + alias + ".to_ts";
  }

}


Add persister="com.mycompany.myapp.VersionedSingleTableEntityPersister" to every <class> mapping and add persister="com.mycompany.myapp.VersionedBasicCollectionPersister" to every <set> mapping which contains a <many-to-many> association.

The above is equivalent to explicitly defining a <filter> on every class and association (and it also works for many-to-one which is not possible to do manually).

The filter-def itself is:
Code:
<filter-def name="effective">
  <filter-param name="when" type="org.joda.time.contrib.hibernate.PersistentDateTime" />
</filter-def>


and is enabled using:

Code:
session.enableFilter("effective").setParameter("when", when);


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 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.