Unexpected behaviour when using Hibernate Filter and Batching

We have 2 entities: Entity A and Entity B and we have a Hibernate Filter on Entity A.
EntityA.xml

<set name="EntityBSet" inverse="true"  access="property" batch-size="100">
        	<key column="A_FK" />
        	<one-to-many class="B" />
        	<filter name="TEST_FILTER" condition=" A_COUNTRY=:country "/>
</set>

Now if we try to load the EntityBSet when Filter is applied, because of Hibernate Batching it add the condition A_COUNTRY in where clause, because of which all EntityB are not loaded. This is leading to data mismatch issues.

Example:
Suppose we fetch 2 instances of Entity A, a1 and a2. And then we enable Hibernate Filter and then we do a1.getEntityBSet, this fires a query:

/* load one-to-many EntityBSet */ select * from EntityB where A_COUNTRY=country1 and A_FK in (?, ?);

But if a1 and a2 are of different country, it won’t load EntityBSet for a2 and instead will say that it has 0 EntityB.

And even later if I change my Hibernate Filter to country2, it will still give 0 results.

You are setting the filter parameter :country to a specific value. When the associations are retrieved, the parameter value currently set is the one that’s used in the query.

If you don’t want your filter applied when retrieving associations, but only when querying EntityA instances, then you should remove it from the EntityBSet mapping.

I want to use it while retrieving associations also. But it should initialise the EntityB objects properly.
For example:

Suppose we have 2 Entity A and Entity B records:
Entity A:
A1
A2

Entity B:
B1, A1, Country1
B2, A2, Country2

  1. Get all entity A
    This will return both A1, A2
  2. Set Country Filter to Country1
  3. Load EntityBSet for A1
    Here this query is fired
/* load one-to-many EntityBSet */ select * from EntityB where A_COUNTRY=country1 and A_FK in (A1, A2);
  1. Set Country Filter to Country2
  2. Load EntityBSet for A2
    Here, no query is fired and it says A2.EntityBSet is empty even though it has 1 record.

Looks like you have batch fetching enabled. As you can see, Hibernate lods the EntityB for both the EntityA that were previously fetched. If you want to execute a single query for each association, each time respecting the filter parameter you’ve set, you should disable batch fetching for that association.

@mbladel Is it possible to disable batching at a session level?

In Hibernate 6.3.0 we have introduced a Session#setFetchBatchSize that, when passed 0 as batch size, will effectively disable batching for the specific session.

I would still suggest always disabling batch-fetching for you association though, and not only in a specific session, as long as you’re using a parameter to filter its values.