0

Vlad's example for how to fix the MultipleBagsException will be our starting point: How to fix MultipleBagsException - Vlad Mihalcea

In it it does 2 subsequent HQL queries in order to load 2 lazy loaded relationships (bags).

When trying to apply this in our project, I've noticed that it only works if the 2 queries are within a transaction. So we have to create a transaction just to get it working and then rollback said transaction soon after.
Example:

utx.begin();
List<Post> posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.comments
    where p.id between :minId and :maxId""", Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
 
posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.tags t
    where p in :posts""", Post.class)
.setParameter("posts", posts)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();
utx.rollback();

For reference, this is a JavaEE project (not Spring) deployed to Wildfly 20. The persistence unit is defined as such in persistence.xml

<persistence-unit name="some-p-unit-name">
    <jta-data-source>java:/jdbc/someDB</jta-data-source>
</persistence-unit>  

And the EntityManager is defined as such:

    @PersistenceContext(type = PersistenceContextType.EXTENDED, unitName = "some-p-unit-name")
private EntityManager em;

@Produces
@RequestScoped
@SomeResource // this is an annotation to differentiate it from another entity manager that can also be injectable
public EntityManager getEm() {
    return em;
}

So why do we need to start a transaction in order for the PersistenceContext to be enabled, even though we're setting it to use the EXTENDED context?

fpezzini
  • 774
  • 1
  • 8
  • 17
  • 1
    Why have you included everything but the actual class that uses the entity manager? Might it not be important to know if you are inside of a EJB? – Smutje Nov 27 '20 at 10:47
  • It is called by an Asynchronous method in a Stateless EJB. – fpezzini Nov 27 '20 at 11:00
  • 1
    I'm sure there are hundreds of examples of asynchronous EJB methods using entity manager without manual transactions out there, so it might not be a fundamental JEE problem... – Smutje Nov 27 '20 at 12:30
  • Thanks for your input. Do you think the annotation @TransactionAttribute(value=TransactionAttributeType.NEVER) added to the EJB class could have something to do with this? I have set that one up to avoid conflicting with a transaction that is started by a module that we call to store information on the database. – fpezzini Nov 27 '20 at 13:00
  • 1
    So, after disabling transactions for an EJB you wonder that the same EJB does not start a transaction automatically? – Smutje Nov 27 '20 at 13:57
  • I'm not sure I follow. Are you stating that for the PersistenceContext to exist a transaction is required? Because from what I've seen in the documentation, it can be either Transactional or Extended (https://stackoverflow.com/a/2548617) – fpezzini Nov 27 '20 at 15:54
  • 1
    From the link you posted: „A container-managed extended persistence context can only be initiated within the scope of a stateful session bean.“ – Smutje Nov 27 '20 at 23:06
  • Thank you, that was very helpful! I'll give it a thought in turning that EJB into a Stateful EBJ. – fpezzini Nov 28 '20 at 10:26

1 Answers1

0

Thanks @Smutje for leading me to the right answer. The solution in our case was to annotate the class defining the EntityManager with @Stateful, as per the documentation the PersistenceContext is only available for Stateful EJBs in container managed scenarios.

Sample Code below. Note the Stateful annotation and also the persistence context type = EXTENDED.

@Stateful
public class Resources {
    @PersistenceContext(type = PersistenceContextType.EXTENDED, unitName = "some-p-unit-name")
    private EntityManager em;

    @Produces
    @RequestScoped
    public EntityManager getEm() {
        return em;
    }
}
fpezzini
  • 774
  • 1
  • 8
  • 17