users@jpa-spec.java.net

[jpa-spec users] [jsr338-experts] Re: updated spec draft: unsynchronized persistence contexts

From: Emmanuel Bernard <emmanuel.bernard_at_jboss.com>
Date: Wed, 30 Nov 2011 15:28:43 +0100

On 29 nov. 2011, at 21:25, Linda DeMichiel wrote:

>> 7.4
>> EntityManagerFactory.addNamedQuery
>> As I raised initially, I'm still unclear how a user would properly use this feature. Where in his code would it add a new named query and make sure this has not been added before. To me it'd be preferable to have some initialization hook to set such queries. I'm happy to change my mind but I looked up my emails and I don't think anyone came up with a use case for the current proposed form.
>> Note that this also avoid a bunch of concurrent safe structures as well but that's impl details.
>>
>> See the thread named Re: named queries and my exchange with Gordon from April 28th forward.
>>
>
> OK. Unfortunately, we don't have a well-defined initialization sequence, and the EMF
> may be created by the container before application code gets to execute. However, a
> startup singleton EJB's postConstruct could be used for adding named queries, or a
> servlet init method. In the mean time, do you think addNamedQuery has so little
> value that we should remove it?

I don't think the feature should be removed but I'm still questioning the form.

Today to use it, you need the following nasty piece of code

    Query query = null;
    try {
        query = em.createNamedQuery("foo");
    }
    catch (IllegalArgumentException e) {
        Query namedQuery = buildQuery();
        em.getEntityManagerFactory().addNamedQuery("foo", namedQuery);
        query = em.createNamedQuery("foo");
    }
    doSomethingWithQuery(query);


That's a horrible code idiom for something that should be as trivial as

    Query query = em.createNamedQuery("foo");

I understand the lifecycle problem, that's a shame.
An alternative may be a named query request listener that has the option to build and enlist the query if it does not exist yet.

    /**
     * called if a given named query is not found and before raising an IllegalArgumentException
     */
    interface NamedQueryBuilder {
        /**
         * return null if the query name is unexpected
         * or return a query object that ought to be associated to the given name
         */
        Query onMissingQuery(String name);
    }