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);