-->
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.  [ 8 posts ] 
Author Message
 Post subject: Dynamic Filtering of Collections (with Spring)
PostPosted: Tue Mar 13, 2007 11:04 am 
Newbie

Joined: Tue Dec 05, 2006 1:02 pm
Posts: 7
Hello,

We need to run this by the folks in this forum to see if there is something really obvious that we may be missing.

The Problem: Unable to get dynamic filters to filter down a collection. Simplified explanation: say we have a class Foo that contains a collection of objects of type Bar. Both types have a "deleted" property so that we don't actually remove them from our database, we simply mark them as deleted. We are then trying to fetch any non-deleted objects through our queries. We are able to filter down deleted Foo records but not Bar records. The generated SQL query shows that the filter is enabled for Foo, but not Bar.

Question: if you have the patience to take a quick look at the configurations below, can you please let us know if there is something obvious that we are missing? Also, since Spring is involved here, if you feel that this is a Spring issue, please let us know. We'll be happy to take this question to them.

Hibernate version: 3.1.3

Mapping documents:
Simplified for ease of reading:
Code:
<hibernate-mapping>
    <class table="foo" name="com.class.Foo">
        [...]
        <property name="deleted" column="deleted" type="boolean"/>
        [...]
        <set name="bar" cascade="save-update" lazy="true">
            <key column="foo_id" />
            <one-to-many class="com.class.Bar" />
            <filter name="nonDeletedRecord" condition=":deletedFlag != deleted" />
        </set>
        [...]
        <filter name="nonDeletedRecord" condition=":deletedFlag != deleted" />
    </class>
    [...]
    <class table="bar" name="com.class.Bar">
        [...]
        <property name="deleted" column="deleted" type="boolean"/>
        [...]
        <filter name="nonDeletedRecord" condition=":deletedFlag != deleted" />
    </class>
</hibernate-mapping>


The filter itself is defined in Spring's LocalSessionFactoryBean using a FilterDefinitionFactoryBean:

Code:
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
   <property name="dataSource" ref="dataSource"/>
   <property name="mappingDirectoryLocations">
      <list>
         <value>classpath:</value>
      </list>
   </property>
   <property name="mappingJarLocations">
      <list>
         <value>WEB-INF/lib/*.jar</value>
      </list>
   </property>
   <property name="hibernateProperties">
      <props>
         <prop key="hibernate.dialect">${hibernate.dialect}</prop>
         <prop key="hibernate.show_sql">${hibernate.show.sql}</prop>
         <prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
         <prop key="hbm2ddl.auto">${hbm2ddl.auto}</prop>
      </props>
   </property>
   <property name="entityInterceptor"><ref bean="auditInterceptor"/></property>
   <property name="eventListeners">
      <map>
         <entry key="merge">
            <bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
         </entry>
      </map>
   </property>
    <property name="filterDefinitions">
     <list>
       <bean class="org.springframework.orm.hibernate3.FilterDefinitionFactoryBean">
         <property name="filterName" value="nonDeletedRecord"/>
         <property name="parameterTypes">
           <props>
             <prop key="deletedFlag">boolean</prop>
           </props>
         </property>
       </bean>
     </list>
    </property>
</bean>



Code between sessionFactory.openSession() and session.close():
In this case, we are using Spring's HibernateDaoSupport to fetch our data:
Code:
public class FooDAOHibernateImpl extends HibernateDaoSupport {
[...]
    public Foo find(String fooId) {
        // Enable non-deleted records filter
        getSessionFactory().getCurrentSession().enableFilter("nonDeletedRecord").setParameter("deletedFlag", Boolean.TRUE);

        List res = getHibernateTemplate().find("from Foo f where f.id=?",fooId);
        if(res.size()>0)
            return (Foo)res.get(0);
        else
            return null;
    }   
[...]
}


Full stack trace of any exception that occurs:
No errors

Name and version of the database you are using:
Postgres 8.2

The generated SQL (show_sql=true):
Hibernate: select foo0_.foo_id as foo1_127_, foo0_.deleted as deleted127_ from foo foo0_ where ? != foo0_.deleted and foo0_.foo_id=?

We thank you in advance for your time and consideration.

Best Regards,

-GS


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 13, 2007 11:10 am 
Newbie

Joined: Tue Dec 05, 2006 1:02 pm
Posts: 7
Forgot the Spring version:

Spring version: 2.0.2


Top
 Profile  
 
 Post subject: Re: Dynamic Filtering of Collections (with Spring)
PostPosted: Tue Mar 13, 2007 12:46 pm 
Newbie

Joined: Tue Mar 13, 2007 9:59 am
Posts: 6
Hello,

actually I have no clue of filters, just droped in attracted by my interest in spring. However, is it ok to write
<filter name="nonDeletedRecord" condition=":deletedFlag != deleted" />

if you have defined
<prop key="deletedFlag">boolean</prop>
as "deleted" doesn't look like a boolean?

(If complete nonsense, please excuse and ignore.)


Top
 Profile  
 
 Post subject: Re: Dynamic Filtering of Collections (with Spring)
PostPosted: Tue Mar 13, 2007 2:12 pm 
Newbie

Joined: Tue Dec 05, 2006 1:02 pm
Posts: 7
tom4321 wrote:
Hello,

actually I have no clue of filters, just droped in attracted by my interest in spring. However, is it ok to write
<filter name="nonDeletedRecord" condition=":deletedFlag != deleted" />

if you have defined
<prop key="deletedFlag">boolean</prop>
as "deleted" doesn't look like a boolean?

(If complete nonsense, please excuse and ignore.)


In this case "deleted" refers to the column name:

Code:
[...]
<property name="deleted" column="deleted" type="boolean"/>
[...]


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 13, 2007 4:41 pm 
Newbie

Joined: Tue Dec 05, 2006 1:02 pm
Posts: 7
Some extra information here as an FYI:

Changing the Bar set mapping to lazy="false" does not make any different in the HQL log output which is very odd.

Also, changing the fetch strategy to "join" does not alter the HQL either where the expected behavior would be to force the fetching of the collection in the same SELECT statement.

What are these symptoms of?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 13, 2007 4:55 pm 
Newbie

Joined: Wed Nov 02, 2005 5:20 pm
Posts: 9
You can try "from Foo f fetch join f.bar where f.id=?" in order to see where clause that filters f.bar.

Foo.bar Collection is lazy loaded. It won't be loaded without 'fetch join'. It can be loaded when you execute Java code:
foo.getBar().size().


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 13, 2007 5:43 pm 
Newbie

Joined: Tue Dec 05, 2006 1:02 pm
Posts: 7
jifengl wrote:
You can try "from Foo f fetch join f.bar where f.id=?" in order to see where clause that filters f.bar.

Foo.bar Collection is lazy loaded. It won't be loaded without 'fetch join'. It can be loaded when you execute Java code:
foo.getBar().size().


So we specified the join in the HQL query as suggested and we now see the Bar table accessed:

Code:
Hibernate: select foo0_.foo_id as foo1_127_, foo0_.deleted as deleted127_ from foo foo0_ join bar bar1_ on foo0_.foo_id=bar1_.foo_id and ? != bar1_.deleted where ? != foo0_.deleted and foo0_.foo_id=?


Shouldn't specifying fetch="join" in the mapping file for the collection do that though?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 13, 2007 7:38 pm 
Newbie

Joined: Tue Dec 05, 2006 1:02 pm
Posts: 7
This issue has been resolved: we were testing filters in a transactional unit test case (AbstractTransactionalDataSourceSpringContextTests) that was setting up the data in the onSetUpInTransaction() method. Moving the data set up in onSetUpBeforeTransaction() forced the commit to the database. The filters subsequently started working in the test methods. We now clean up our data in the onTearDownAfterTransaction().

While the problem is resolved, we don't really understand why we were seeing this behavior. If anyone has any theories, feel free to share them. My guess would be it's because filter conditions are done against database columns and since transactional unit tests do not directly hit the database layer, there are no columns to run the comparisons against? But even then, that would not explain why they work for the class and not the set. Hope I'm not out to lunch on this.

-Cheers


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