Pregunta

Estoy usando Hibernate como mi proveedor de JPA para que se conecte a una base de datos de Progress. Cuando un valor de NaN persiste, está causando muchos problemas: evita que se lea la fila en ciertas circunstancias. ¿Hay alguna manera de engancharse a la persistencia de tipo doble estándar para convertir NaN (y probablemente + y - infinito) a un valor diferente? No importa si la información de NaN o infinito se pierde, ¡solo quiero una fila legible!

Sé que podría hacer algo como esto:

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

Pero me preocupa el mantenimiento, ya que tendrá que agregarse manualmente para cualquier doble asignado a la base de datos.

¿Fue útil?

Solución

Mi primera impresión de esto sería buscar el tipo en el que Hibernate persiste double como. Así que puede refactorizar el método set (...) en DoubleType . Sin embargo, eso significaría que tendría que anotar cada tipo de Double con @ org.hibernate.annotations.type (type = " myDouble ") después de que haya definido " myDouble " usando @ org.hibernate.annotations.TypeDef en package-info: creo que quiere evitar todo esto por mantenimiento (más allá de eso, tendría que ir al corazón de Hibernate).

Otros consejos

Podrías modificar la hibernación. Todo lo que tienes que hacer es cambiar la clase DoubleType.

Por supuesto, entonces tendrías que mantener ese parche a medida que evoluciona la hibernación, pero considerando que está en una clase única y bastante estable, esto podría ser más fácil que especificar un UserType para cada doble en tu modelo de dominio.

Después de esta discusión , tengo la sensación de que hibernar no ofrece una manera de convertir NaN en otra cosa. Creo que debes evitar los valores de NaN antes, incluso antes de que se escriban en las variables del miembro del bean (como agregar código de guard / conversion a los configuradores).

EDIT

Me temo que la mejor solución desagradable es usar el código de guarda y, lo que es aún peor, una columna adicional en la tabla, para marcar, si el valor es un número o no. Lo que sin duda complicará la consulta y las operaciones de inserción. Pero necesita NaN en la base de datos y no puede hacer que el controlador / base de datos jdbc se comporte correctamente (y acepte NaN como entradas válidas para los campos NÚMEROS).

Utilicé la solución UserType al final, pero resolví el problema de mantenimiento con una prueba de unidad. La clase de tipo es la siguiente:

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);
    }
}

La prueba de la unidad es aproximadamente (algunos detalles se eliminaron por brevedad):

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);
        }
    }
}

Tuve exactamente el mismo problema, y ??con la guía de estas soluciones, también preparé una clase de tipos personalizada que extendía DoubleType. Dentro de esa clase, convertí los valores NaN en nulos en la función set y viceversa para la función get, ya que null está bien para las columnas de mi base de datos. También cambié la asignación de las posibles columnas de NaN a la clase de tipo personalizada. Esa solución funcionó perfectamente para hibernar 3.3.2.

Desafortunadamente, después de actualizar Hibernate a 3.6.10, dejó de funcionar. Para que funcione de nuevo, reemplacé el tipo personalizado de la extensión de DoubleType para implementar UserType.

Las implementaciones importantes de la función de tipo de datos deben ser las siguientes:

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

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

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

Y aquí están las funciones de obtener y establecer:

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);
}

Lo siento, pero a juzgar por sus ejemplos y su pregunta, realmente tiene problemas para entender la persistencia de Java. Las entidades de base de datos se autogestionan a través de captadores y definidores, que pueden realizar cualquier validación que le gustaría tener. Si realmente establece los atributos sin ellos, le faltan los conceptos centrales del desarrollo orientado a objetos Y las entidades gestionadas por persistencia en particular. Me parece que necesita volver a diseñar su proyecto, tener problemas como estos son un signo seguro de fallas de diseño fundamentales ... solo le damos un consejo aquí, y esa es la solución:

@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();
}

.... es así de fácil.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top