Question

J'utilise Hibernate comme fournisseur JPA pour me connecter à une base de données Progress. Lorsqu'une valeur NaN est persistée, cela cause beaucoup de problèmes - cela empêche la lecture de la ligne dans certaines circonstances. Existe-t-il un moyen de s’adapter à la persistance de type double standard pour convertir NaN (et probablement + et - infini) en une valeur différente? Peu importe si l’information NaN ou l’infini est perdue, je veux juste une ligne lisible!

Je sais que je pourrais faire quelque chose comme ceci:

@Column(name = "doubleColumn")
public double getDoubleColumn() {
    return PersistedDouble.convert(doubleColumn);
}

Mais je suis inquiet pour la maintenance car il faudra l’ajouter manuellement pour tous les doublons mappés à la base de données.

Était-ce utile?

La solution

Ma première impression serait de rechercher le type de persistance de Hibernate double . Vous pouvez donc refactoriser la méthode set (...) dans DoubleType . Cela signifierait toutefois que vous auriez besoin d'annoter chaque type Double avec @ org.hibernate.annotations.type (type = "quot>") après avoir défini " monDouble " en utilisant @ org.hibernate.annotations.TypeDef dans package-info - Je pense que vous voulez éviter tout cela pour la maintenance (au-delà, il vous faudrait aller au cœur d'Hibernate).

Autres conseils

Vous pouvez modifier le mode hibernation lui-même. Tout ce que vous avez à faire est de changer la classe DoubleType.

Bien sûr, vous devrez alors conserver ce correctif au fur et à mesure de l'évolution de l'hibernation, mais dans une classe unique et plutôt stable, cela pourrait être plus facile que de spécifier un type d'utilisateur pour chaque double dans votre modèle de domaine.

À la suite de cette discussion , j'ai le sentiment que l'hibernation n'offre pas un moyen de convertir NaN en quelque chose d'autre. Je pense que vous devez empêcher les valeurs NaN plus tôt, avant même qu'elles ne soient écrites dans les variables de membre de bean (comme l'ajout d'un code de protection / conversion aux setters).

MODIFIER

Je crains que la meilleure solution désagréable consiste à utiliser un code de garde et, ce qui est encore pire, une colonne supplémentaire sur la table, pour indiquer si la valeur est un nombre ou non. Ce qui va certainement compliquer la requête et les opérations d'insertion. Mais vous avez besoin de NaN dans la base de données et vous ne pouvez pas vous opposer au comportement correct du pilote / base de données jdbc (et accepter NaN comme entrées valides pour les champs NUMBER).

J'ai utilisé la solution UserType à la fin mais j'ai résolu le problème de maintenance avec un test unitaire. La classe de type est la suivante:

public class ParsedDoubleType extends DoubleType {
    private static final long serialVersionUID = 1L;

    @Override
    public void set(PreparedStatement st, Object value, int index) throws SQLException {
        Double doubleValue = (Double) value;
        if (doubleValue.isInfinite() || doubleValue.isNaN()) {
            Logger.getLogger(ParsedDoubleType.class).warn("Attempted to send a NaN or infinity value to the database " 
                + "- this is not supported.\nStatement=" + st + " valueIndex=" + index);
            doubleValue = Double.valueOf(0);
        }
        super.set(st, doubleValue, index);
    }
}

Le test unitaire est approximativement (certains détails ont été supprimés pour des raisons de brièveté):

Ejb3Configuration hibernateConfig = new Ejb3Configuration().configure("InMemoryDatabasePersistenceUnit", null);
for (Iterator<?> iterator = hibernateConfig.getClassMappings(); iterator.hasNext();) {
    PersistentClass clazz = (PersistentClass) iterator.next();
    Iterator<?> propertyIterator = clazz.getPropertyIterator();
    while (propertyIterator.hasNext()) {
        if (property.getType().equals(Hibernate.DOUBLE)) {
            Assert.fail("Raw double type found. Annotate with @Type(type = \"package.ParsedDoubleType\")\n" 
                + "Class " + clazz + " property " + property);
        }
    }
}

J'ai eu exactement le même problème et, avec l'aide de ces solutions, j'ai également préparé une classe de type personnalisée étendant DoubleType. À l'intérieur de cette classe, j'ai converti les valeurs NaN en null pour la fonction set et inversement pour la fonction get, puisque null est OK pour les colonnes de ma base de données. J'ai également modifié le mappage des colonnes possibles NaN vers la classe de type personnalisé. Cette solution a parfaitement fonctionné pour Hibernate 3.3.2.

Malheureusement, après avoir mis à niveau Hibernate vers la version 3.6.10, il a cessé de fonctionner. Afin de le faire fonctionner à nouveau, j'ai remplacé le type personnalisé d'extension DoubleType pour implémenter UserType.

Les implémentations importantes des fonctions de type de données doivent être les suivantes:

private int[] types = { Types.DOUBLE };

public int[] sqlTypes()
{
    return types;
}

@SuppressWarnings("rawtypes")
public Class returnedClass()
{
    return Double.class;
}

Et voici les fonctions get et set:

public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException
{
    Double value = rs.getDouble(names[0]);
    if (rs.wasNull())
        return Double.NaN;
    else
        return value;
}

public void nullSafeSet(PreparedStatement ps, Object value, int index) throws HibernateException, SQLException
{
    Double dbl = (Double) value;
    if ((dbl == null) || (Double.isNaN(dbl)))
        ps.setNull(index, Types.DOUBLE);
    else
        ps.setDouble(index, dbl);
}

désolé mais à en juger par vos exemples et votre question, vous avez du mal à comprendre la persistance de Java. Les entités de base de données sont auto-gérées via des accesseurs et des installateurs - ceux-ci peuvent effectuer toutes les validations souhaitées. Si vous définissez réellement des attributs sans eux, il vous manque les concepts de base du développement orienté objet ET de la persistance - des entités gérées en particulier. Il me semble que vous devez repenser votre projet. Des problèmes de ce type sont un signe certain de défauts de conception fondamentaux ... il suffit de donner quelques conseils - et voilà la solution:

@Column(name="doubleColumn"}
private Double doubleColumn = Double.NaN  //yes, this is intentional. Verily.

public void setDouble(Double d)
{
    if(d.isNan || d.isInfinite()
    {
       //do something nice here
    }
    else
       this.doubleColumn = d;
}
public Double getDouble()
{
   return !this.doubleColumn.isNaN() && !this.doubleColumn.isInfinite() ? this.doubleColumn : new Double();
}

.... c'est aussi simple que cela.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top