2

Currently, the JPA entities that comprise my application have an @NamedQueries block that contains many @NamedQuery annotations. This works well but some of my entities have over 80 @NamedQuery annotations and are getting difficult to maintain. I now need to add sorting to my queries and do not want to create additional @NamedQuery annotations.

During my research, I discover the JPA 2.1 EntityManagerFactory.addNamedQuery method. This seems to be the answer to my prayers. I could create an initializer that runs at startup to create all my named queries using my established naming conventions and eliminate the large @NamedQueries block at the top of my entities.

I could even use the following EclipseLink specific code to add a new NamedQuery based on an existing NamedQuery.

TypedQuery<Portrait> tq = em.createNamedQuery("Portraits.read", Portrait.class);

String jpql = tq.unwrap(EJBQueryImpl.class).getDatabaseQuery().getJPQLString();

Query q = this.em.createQuery(jpql + " ORDER BY p.id DESC");

em.getEntityManagerFactory().addNamedQuery("Portraits.read.Id-D", q);

TypedQuery<Portrait> tq2 = em.createNamedQuery("Portraits.read.Id-D", Portrait.class);

Are there reasons, I should not use the addNamedQuery method instead of or in addition to the @NamedQuery annotation?

Reed Elliott
  • 223
  • 2
  • 15
  • 1
    What you "should" do depends on your project and use-case. There is no "answer". It's your project, decide for yourself. Oh, and "JPQL" is not "sql" in your example, so don't do call the variable that or you'll confuse the hell out of whoever maintains your project –  Nov 22 '17 at 11:07
  • I'm looking to see if anyone will say something like "don't use addNamedQuery because ..." I didn't find much about this approach on the web so am worried that I am missing an obvious reason not to use it. Your comment gives me more confidence that the method approach is valid. I changed sql to jpql based on your recommendation. Thanks! – Reed Elliott Nov 22 '17 at 11:26
  • You may find your named queries easier to manage in an `orm.xml` file. – Steve C Nov 22 '17 at 11:36
  • I know there are many who think that jpql-statements are somewhat so special, that they should be maintained at a very special central place. I am not so convinced of this approach. ImO it is much better to see in the java-source-code itself, what query is used to provide the data. Your problem supports my opinion somewhat more. – aschoerk Nov 22 '17 at 14:27

1 Answers1

4

Named queries are used to organizequery definition and improve application performance, because the query string is defined in an annotation and can not be changed at runtime and also prevent security issues like sql injection.

  • The name of the NamedQuery is scoped to the entire persistence unit and must be unique within that scope. So maybe is better to define it to every class as you said. Because it is undefined what should happen if two queries in the same persistence unit have the same name, but it is likely that either deployment of the application will fail or one will overwrite the other, leading to unpredictable results at runtime.
  • Dynamic Named Queries (addNamedQuery) is a hybrid approach to dynamically create a query and then save it as a named query in the entity manager factory. At that point it becomes just like any other named query that may have been declared statically in metadata.

    This is useful in only a few specific cases:

    • The main advantage it offers is if there are queries that are not known until runtime, but then reissued repeatedly.

    • Once the dynamic query becomes a named query it will only bear the cost of processing once. It is implementation-specific whether that cost is paid when the query is registered as a named query, or deferred until the first time it is executed.

To summarise it is better to define the namedqueries on the entity class that most directly corresponds to the query result. But dynamic queries also have their place at some specific points.

ddarellis
  • 3,912
  • 3
  • 25
  • 53
  • 1
    Thanks! I am going to move forward with a hybrid approach. My JPA entity classes will have the core named queries defined at the top of the class but I am going to use dynamic name queries to append sorting information to the core query. For example, user selects a sort on a PrimeFaces datatable; client requests sorted data, server uses existing named query or builds a new named query by appending the sort information to an existing named query. – Reed Elliott Dec 06 '17 at 21:48