Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Hibernate + implémentation like pour champ de type Number

2 réponses
Avatar
fabien.perie
Bonjour,

dans une base oracle, j'ai un champ exercice o=F9 on stocke des ann=E9es
sous la forme de "Number(4)".
J'utilise Hibernate et je souhaite pouvoir effectuer une recherche en
disant "renvoie moi toutes les dates qui commencent par : 20 par
exemple", en gros un sorte de 'like' mais pour du num=E9rique.

Pour cela j'ai cr=E9e la classe suivante :

/**
* Classe permettant d'effectuer l'=E9quivalent d'un 'like' sur
* une propri=E9t=E9 num=E9rique (Number ou Integer)
*/
public class LikeIntegerExpression implements Criterion
{
private String propertyName;
private Integer value;

public LikeIntegerExpression(String propertyName, Integer value) {
this.propertyName =3D propertyName;
this.value =3D value;
}

public String toSqlString(Criteria criteria, CriteriaQuery
criteriaQuery) throws HibernateException {

String[] columns =3D criteriaQuery.getColumnsUsingProjection(criteria,
propertyName);
Type type =3D criteriaQuery.getTypeUsingProjection(criteria,
propertyName);
StringBuffer fragment =3D new StringBuffer();

if (columns.length > 1) {
fragment.append('(');
}

SessionFactoryImplementor factory =3D criteriaQuery.getFactory();
int[] sqlTypes =3D type.sqlTypes( factory );

for ( int i=3D0; i<columns.length; i++ ) {
fragment.append("to_char(" + columns[i] + ") like '" +
value.intValue() + "%'");

if ( i < columns.length-1 ) {
fragment.append(" and ");
}
}

if (columns.length>1) {
fragment.append(')');
}

return fragment.toString();
}

public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery
criteriaQuery) throws HibernateException {
//Object icvalue =3D value;
return new TypedValue[] { criteriaQuery.getTypedValue(criteria,
propertyName, value) };
}
}

Hibernate effectue bien la requete, mais il plante juste apr=E8s en
disant : =AB
[ERROR JDBCExceptionReporter] Index de colonne non valide

[11:33:45.588]
org.hibernate.util.JDBCExceptionReporter.logExceptions(JDBCExceptionReporte=
r=2Ejava:72)
Exception : Une erreur non typ=E9e a =E9t=E9 lev=E9 : could not execute
query =BB

Si j'effectue la requ=EAte g=E9n=E9r=E9e par Toad sous Toad, la requ=EAte
s'ex=E9cute bien...

Je pense que mon erreur vient de l'impl=E9mentation de la m=E9thode : =AB
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery
criteriaQuery) =BB car je n'ai pas tr=E8s bien compris ce que doit faire
cette m=E9thode ? Qu'en pensez-vous ?

HELP ME !!!
Merci d'avance.

Fabien

2 réponses

Avatar
simon.oualid
Perso je gérerais ça directement au niveau d'oracle. Soit en
utilisant directement un datatype VARCHAR2 (avec un TO_NUMBER dans les
WHERE si tu souhaites faire des comparaisons), soit en utilisant
TO_CHAR.

Pour l'intégration hibernate, tu peux utiliser une vue (en lecture
seule). Si tu as besoin de lecture / ecriture et que la volumétrie
reste raisonnable, crée 2 colonnes, alimente le champs en INTEGER, et
crée un trigger qui va stocker la même donnée en VARCHAR2 à chaque
insert/update (pour pouvoir faire ton LIKE simplement ensuite).

Je crois d'ailleurs, mais c'est à vérifier, que les dernière
versions d'oracle (>8i) supportent directement les LIKE sur les champs
NUMBER - et dérivés - par l'utilisation d'un TO_CHAR implicite.

J'espère que tout ça pourra t'aider.

Symon

wrote:
Bonjour,

dans une base oracle, j'ai un champ exercice où on stocke des années
sous la forme de "Number(4)".
J'utilise Hibernate et je souhaite pouvoir effectuer une recherche en
disant "renvoie moi toutes les dates qui commencent par : 20 par
exemple", en gros un sorte de 'like' mais pour du numérique.

Pour cela j'ai crée la classe suivante :

/**
* Classe permettant d'effectuer l'équivalent d'un 'like' sur
* une propriété numérique (Number ou Integer)
*/
public class LikeIntegerExpression implements Criterion
{
private String propertyName;
private Integer value;

public LikeIntegerExpression(String propertyName, Integer value) {
this.propertyName = propertyName;
this.value = value;
}

public String toSqlString(Criteria criteria, CriteriaQuery
criteriaQuery) throws HibernateException {

String[] columns = criteriaQuery.getColumnsUsingProjection(criteria,
propertyName);
Type type = criteriaQuery.getTypeUsingProjection(criteria,
propertyName);
StringBuffer fragment = new StringBuffer();

if (columns.length > 1) {
fragment.append('(');
}

SessionFactoryImplementor factory = criteriaQuery.getFactory();
int[] sqlTypes = type.sqlTypes( factory );

for ( int i=0; i<columns.length; i++ ) {
fragment.append("to_char(" + columns[i] + ") like '" +
value.intValue() + "%'");

if ( i < columns.length-1 ) {
fragment.append(" and ");
}
}

if (columns.length>1) {
fragment.append(')');
}

return fragment.toString();
}

public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery
criteriaQuery) throws HibernateException {
//Object icvalue = value;
return new TypedValue[] { criteriaQuery.getTypedValue(criteria,
propertyName, value) };
}
}

Hibernate effectue bien la requete, mais il plante juste après en
disant : «
[ERROR JDBCExceptionReporter] Index de colonne non valide

[11:33:45.588]
org.hibernate.util.JDBCExceptionReporter.logExceptions(JDBCExceptionRepor ter.java:72)
Exception : Une erreur non typée a été levé : could not execute
query »

Si j'effectue la requête générée par Toad sous Toad, la requête
s'exécute bien...

Je pense que mon erreur vient de l'implémentation de la méthode : «
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery
criteriaQuery) » car je n'ai pas très bien compris ce que doit faire
cette méthode ? Qu'en pensez-vous ?

HELP ME !!!
Merci d'avance.

Fabien


Avatar
chrtela
wrote:
dans une base oracle, j'ai un champ exercice où on stocke des années
sous la forme de "Number(4)".
J'utilise Hibernate et je souhaite pouvoir effectuer une recherche en
disant "renvoie moi toutes les dates qui commencent par : 20 par
exemple", en gros un sorte de 'like' mais pour du numérique.


En gros, tu veux faire un filtre sur les années 2000 à 2099 ? Pourquoi ne
pas générer un "WHERE year BETWEEN 2000 AND 2099", plutôt que de faire une
conversion vers du char/varchar/varchar2 ?

Car une conversion rend typiquement difficile voire impossible l'utilisation
d'un index.

Donc, crée plutôt un "BetweenIntegerExpression" (si ça n'existe pas, je ne
connais pas assez Hibernate pour l'affirmer/l'infirmer).