Sprawdź poprawność składni wyrażenia IN z parametrem wejściowym o wartości w postaci kolekcji

Specyfikacja interfejsu JPA (Java Persistence API) dla wyrażeń IN definiuje, że parametr wejściowy o wartości w postaci kolekcji nie jest ujmowany w nawiasy. Produkt OpenJPA zezwala na obecność nawiasów, podczas gdy produkt EclipseLink zgłasza wyjątek w przypadku wywołania metody Query.setParameter z obiektem kolekcji odpowiadającym parametrowi wejściowemu o wartości w postaci kolekcji IN ujętym w nawiasy.

Ta reguła wykrywa łańcuchy zawierające instrukcje języka JPQL (Java Persistence Query Language) z wyrażeniami IN o jednym parametrze ujętym w nawiasy. Z uwagi na to, że łańcuch zapytania i odpowiadające mu wywołanie setParameter mogą znajdować się w różnych klasach, reguła nie może zagwarantować, że parametr będzie kolekcją. Jeśli parametr jest typu kolekcji, należy usunąć nawiasy z łańcucha zapytania. Należy zwrócić uwagę, że nawiasy są poprawne dla literałów lub parametrów wejściowych o pojedynczej wartości, dlatego należy zachować ostrożność podczas usuwania.

W celu rozwiązania tego problemu należy usunąć nawiasy z wyrażenia IN z parametrem wejściowym o wartości w postaci kolekcji.

Produkt OpenJPA na przykład zezwala na nawiasy w następujących łańcuchach zapytań, ale produkt EclipseLink zgłasza wyjątek po wywołaniu metody setParameter i próbie ustawienia ids na wartość będącą kolekcją.

  List<String> idList = getIdsToQuery();
  Query query = em.createQuery("SELECT p FROM Person p WHERE p.id IN (:ids)");
  query.setParameter("ids", idList);
  
  final String ENTITY_NAME = "Person";
  final String PRIMARY_KEY = "id";
  List<String> idList2 = getIdsToQuery();
  Query query = em.createQuery("SELECT p FROM " + ENTITY_NAME + " p " +" WHERE p." + PRIMARY_KEY + " IN (:ids)");
  query.setParameter("ids", idList2);

Aby rozwiązać ten problem, należy usunąć nawiasy, gdy ids reprezentuje kolekcję.

  List<String> idList = getIdsToQuery();
  Query query = em.createQuery("SELECT p FROM Person p WHERE p.id IN :ids");
  query.setParameter("ids", idList);
  
  final String ENTITY_NAME = "Person";
  final String PRIMARY_KEY = "id";
  List<String> idList2 = getIdsToQuery();
  Query query = em.createQuery("SELECT p FROM " + ENTITY_NAME + " p " +" WHERE p." + PRIMARY_KEY + " IN :ids");
  query.setParameter("ids", idList2);

Poniżej został przedstawiony przykład, który został oznaczony flagą, ale nie powinien zostać zmieniony, ponieważ id jest parametrem o pojedynczej wartości.


  String idMatch = getIdToQuery();
  Query query = em.createQuery(SELECT p FROM Person p WHERE p.id IN (:id));
  query.setParameter("id", idMatch);
  

Informacje o tym problemie i innych problemach dotyczących migracji środowiska OpenJPA do środowiska EclipseLink zawierają następujące dokumenty: