jakartaee / persistence

https://jakartaee.github.io/persistence/
Other
187 stars 55 forks source link

parametrized 'in' predicate lists #570

Closed gavinking closed 4 months ago

gavinking commented 5 months ago

A very old and extremely widely-used feature of Hibernate that I had frankly just forgotten is not part of JPA is the ability to parameterize in arguments of the in predicate, for example:

s.createQuery("from Entity e where e.id in (:ids)")
        .setParameterList("ids", List.if(1, 2, 3))
        .getResultList(); 

The named parameter :ids gets expanded to multiple JDBC parameters ?, ?, ? when the "parameter list" is bound.

I think this is very much low-hanging fruit, and that we should add something similar to JPA. But I'm not sure that the way it's done in Hibernate is the most elegant option. How about something like this instead:

em.createQuery("select e from Entity e where e.id in (:id,...)")
        .setParameter("id", List.of(1, 2, 3))
        .getResultList(); 

Here it's the syntax of the query that identifies what's going on, instead of the method call.

Thoughts?

beikov commented 5 months ago

Am I missing something in your request or is this already covered by collection_valued_input_parameter?

gavinking commented 5 months ago

OMG that's crazy. So the BNF refers to an undefined rule named collection_valued_input_parameter, but:

Apparently, in Hibernate we interpret this as you may pass a List (but not an array) to setParameter().

But that's actually completely undefined, as far as I can tell.

gavinking commented 5 months ago

So we should at least clarify the spec to make clear that this is allowed:

em.createQuery("select e from Entity e where e.id in :ids")
        .setParameter("ids", List.of(1, 2, 3))
        .getResultList(); 
beikov commented 5 months ago

The spec does not directly refer to the BNF rule, but AFAICS it does specify this: https://jakarta.ee/specifications/persistence/3.1/jakarta-persistence-spec-3.1#input-parameters

gavinking commented 5 months ago

OK, but again, that doesn't actually specify anything.

In particular, it doesn't say how you bind multiple arguments to a "collection-valued input parameter", nor even say what a "collection-valued input parameter" actually is.

gavinking commented 5 months ago

"specify something" = explicitly state what the API user is allowed to do, and what the implementor must implement

gavinking commented 5 months ago

We should never have to guess what the authors of the spec intended.

And this is a perfect example of why we should always be explicit, and of why we should always write down clearly in words what our intention is: in this case I was myself one of the authors of the spec and that feature was almost certainly added at my explicit request. But because it's so unspecified, today I had to go and actually try it in Hibernate to figure out what the actual semantics were!

lukasj commented 5 months ago

100 may be related to this

gavinking commented 5 months ago

100 may be related to this

Yeah it's related. We would indeed as part of this need to specify explicitly whether empty list are allowed.