web-dev-qa-db-fra.com

Utilisation de la carte pour passer des paramètres de requête dans DAO

Il est très courant de voir une implémentation DAO générique comme ceci:

public List<E> getResultList(String namedQuery, Map<String, Object> parameters) {
    Query query = entityManager.createNamedQuery(namedQuery);
    parameters.entrySet().forEach(e -> query.setParameter(e.getKey(), e.getValue()));
    return query.getResultList();
}

J'ai quelques problèmes avec cette approche:

  1. Utiliser une structure complexe pour passer simplement une liste de données clés et de valeurs.
  2. La création de cartes est très détaillée.

Exemple:

public List<TransacaoTEF> getActiveTransactions1(TipoMensagem tipoMensagem, LocalDate date) {
    Map<String, Object> parameters = new HashMap<>();
    parameters.put("type", tipoMensagem);
    parameters.put("date", date);
    return getResultList("namedQueryXTPO", parameters);
}

Pour éviter cela, j'ai pensé à créer une classe de paramètres simple:

public List<E> getResultList(String namedQuery, Parameter... parameters) {
    Query query = entityManager.createNamedQuery(namedQuery);
    Arrays.stream(parameters).forEach(p -> query.setParameter(p.getName(), p.getValue()));
    return query.getResultList();
}

public List<E> getResultList(String namedQuery, List<Parameter> parameters) {
    Query query = entityManager.createNamedQuery(namedQuery);
    parameters.forEach(p -> query.setParameter(p.getName(), p.getValue()));
    return query.getResultList();
}   

En utilisant:

public List<TransacaoTEF> getActiveTransactions2(TipoMensagem tipoMensagem, LocalDate date) {
    return getResultList("namedQueryXTPO", 
            new Parameter("type", tipoMensagem), new Parameter("date", date));
}

public List<TransacaoTEF> getActiveTransactions3(TipoMensagem tipoMensagem, LocalDate date) {
    List<Parameter> parameters = Arrays.asList(
            new Parameter("type", tipoMensagem), 
            new Parameter("date", date));
    return getResultList("namedQueryXTPO", parameters);
}   

C'est de l'ingénierie ou juste de la paranoïa; p?

3
Rodrigo Menezes

C'est de l'ingénierie ou juste de la paranoïa; p?

Je ne pense pas que ce soit non plus. Oui, une carte est une structure de données générique, mais c'est aussi la première chose que vous recherchez lorsque vous avez besoin de paires clé-valeur ou param-valeur. Donc la plupart des gens le font comme ça et ensuite le reste du code est juste qu'ils sont responsables et ne font pas des choses comme ça:

Map<String, Object> parameters = new HashMap<>();
parameters.put(null, someValue);
parameters.put("%$@*^%", someOtherValue);

Si vous utilisez une classe Parameter, vous pouvez faire quelque chose de plus que ce qu'une carte vous donne. Vous pouvez affirmer ou valider certaines des choses que vous placez à l'intérieur comme ne pas spécifier un nom de paramètre nul comme ci-dessus, ou peut-être pas envoyer des valeurs null mais un JDBC NULL à la place, ou quoi que ce soit ...

Une carte n'est qu'un seau. Ce que vous mettez est ce que vous sortez. Rien d'extraordinaire. Si votre application est simple, peu de développeurs disciplinés, etc., une carte peut suffire.

Si vous construisez une bibliothèque ou si vous voulez vous assurer qu'il y a des sécurités en place, alors une classe Parameter est meilleure.

1
Bogdan

Pour alléger l'ennui de la création de la carte, j'écrirai souvent un petit utilitaire :. (code squelette)

Map addKeyValuePairs(Map m, Object...pairs) {
   // TODO test that pairs has an even number
  for (int i=0; i<pairs.length; i+=2) {
     // TODO Add null checks as desired
     m.put(pairs[i].toString(), pairs[I+1].toString());
  }
  return m;
}
1
user949300