Her is a simple HQL example that shows the relevant thing that you are trying to do:
select p
from Product p
join fetch p.ents pe1
join p.ents pe2
where pe1.initiator = '1'
and pe2.module = 'DCC'
You are inner joining a *-to-many collection two times and try to filter the collection contents and the result that you get is not what you expect.
This is the reason why JPA does not allow to specify aliases for join fetch paths, because you’re going to shoot your foot.
Never ever use the alias of a joined fetched association except for further join fetching. Hibernate ORM allows you to do this to allow you to do nested join fetch, but that’s it. The need to cast from Fetch to Join should have already raised a red flag since that means you’re entering unknown territory.
If you want to filter i.e. decide if a ProductEntity is in the result or not based on ProductEntityEntity, then you should use a so called semi join which can be implemented with an exists subquery i.e.
select p
from Product p
join fetch p.ents
where exists (
select 1
from p.ents pe
where pe.initiator = '1'
and pe.module = 'DCC'
)
If you really need to filter the contents of a collection, I would advise you to use a DTO instead of an entity or if that is too much trouble, at least use Hibernate ORM Filters, since that concept is known to collections. Filtering a collection by using the join fetch alias in a predicate will lead to trouble, because Hibernate ORM believes that the state of the collection is in sync with the database. When you alter the collection in memory and auto-flushing kicks in, Hibernate ORM might delete data that you have filtered out with your query. With filters, you don’t have this problem, because filters are respected during auto-flushing.