4
votes

Comment envoyer une liste vide à la clause IN

Je souhaite utiliser cette requête SQL:

String hql = "select e from " + Terminals.class.getName() + " e WHERE e.merchantId IN :merchant_ids";
        TypedQuery<Terminals> query = entityManager.createQuery(hql, Terminals.class).setParameter("merchant_ids", merchant_ids);
        List<Terminals> merchants = query.getResultList();

Mais j'obtiens une erreur: the right syntax to use near ') La liste des clauses IN (....) dans IN (....) ne peut donc pas être vide. Y a-t-il une solution à ce problème?


6 commentaires

Copie possible de la liste de clauses Adding IN à une requête JPA


Je ne trouve pas de solution dans le lien. Comme vous pouvez le voir, je n'ai pas (...) dans mon code.


Vous attendez-vous vraiment à obtenir un résultat lorsque vous avez une liste vide et que vous recherchez quelque chose qui figure dans cette liste? Une telle requête doit échouer. En fait, votre code vous oblige à rechercher des identifiants, s'il n'y en a pas dans la liste de recherche, il ne devrait y en avoir aucun dans le résultat. Qu'est-ce que tu fais mon gars?


Dans mon cas, je n'ai PAS besoin d'obtenir un résultat de la table Terminals lorsque la liste merchant_ids est vide. L'idée générale est que je recherche des terminaux qui correspondent aux identifiants de marchand attribués


Pensez-y, si vous recherchez quelque chose qui se trouve dans une liste vide, vous obtiendrez soit un résultat vide, soit tous les résultats et donc le comportement est indéfini et donc une erreur. La façon dont vous gérez la liste vide est un détail de mise en œuvre que vous devez comprendre et décider par vous-même.


En général, y a-t-il une solution?


4 Réponses :


0
votes

Je ne suis pas familier avec la mise en veille prolongée mais comme il s'agit d'une erreur SQL, ce qui suit devrait fonctionner:

TypedQuery<Terminals> query = entityManager
.createQuery(hql, Terminals.class)
.setParameter("merchant_ids",merchant_ids.size()==0?null:merchant_ids);

Mais comme @Richard Barker l'a mentionné, la meilleure solution est de ne même pas exécuter la requête lorsque la liste est vide. Vous économiserez même sur l'appel de base de données inutile, lorsque vous savez déjà que la requête ne retournera rien.


0 commentaires

1
votes

Très souvent, je collais ce genre d'affaire. Je n'ai pas trouvé de solution appropriée. Puisque vous utilisez Spring JPA, j'ai une solution de contournement à vous suggérer.

  1. Implémentez EntityManger et créez vos requêtes SQL au runtime. Ainsi, vous pouvez renseigner votre cause et tout. Comme ceci: entityManager.createNativeQuery(sql.toString())

  2. Implémentez if-else bloc if-else . Vérifiez si la liste est vide ou non, si false appelle la requête réelle (avec bloc IN) ou bien écrivez une autre requête sans bloc IN.

Encore une fois, je le dis, ce n'est peut-être pas une solution appropriée. Mais je vois que c'est une bonne solution de contournement.


0 commentaires

3
votes

Il est permis et même très bien de ne pas exécuter la requête:

if (merchant_ids.isEmpty()) {
    merchant_ids.add(-1);
    String hql = "select e from " + Terminals.class.getName() + ...

Je ne sais pas ce qui se passerait si l'on passait null au lieu d'une liste vide; SQL ... IN NULL pourrait faire. D'autre part, il peut effectuer une analyse complète de la table afin de renvoyer 0 résultat.

Si x IN() ne donnerait pas 0 enregistrement (quand il y a un OR ... ) alors:

if (merchant_ids.isEmpty()) {
    return new ArrayList<>();
} else {
    String hql = "select e from " + Terminals.class.getName()
            + " e WHERE e.merchantId IN :merchant_ids";
   return entityManager.createQuery(hql, Terminals.class)
        .setParameter("merchant_ids", merchant_ids)
        .getResultList();
}


2 commentaires

hm .... Que dois-je utiliser pour les paramètres vides? merchant_ids.add (0); ou merchant_ids.add (-1) ;?


Une valeur inexistante. Comme les numéros d'identification sont par convention non nuls positifs, 0 serait également possible, en raison de l'utilisation par java de -1 dans indexOf et des indices de base zéro, j'ai personnellement tendance à -1, mais la définition de la colonne de base de données pourrait utiliser des nombres non signés ou autre,



0
votes

J'ai suivi la suggestion de @ Rambler et créé une méthode pour renvoyer un null:

    public static <T> Collection<T> nullIfEmpty(Collection<T> collection) {
        return (collection == null || collection.isEmpty()) ? null : collection;
    }

C'était plus facile à mettre en place, mais je conviens qu'il vaut mieux ne pas faire l'appel à la base de données.


0 commentaires