Вопрос

Я использую Hibernate в качестве своего JPA-провайдера, который подключается к базе данных Progress.Когда значение NaN сохраняется, это вызывает множество проблем - это предотвращает чтение строки при определенных обстоятельствах.Есть ли способ подключиться к стандартному постоянству двойного типа, чтобы преобразовать NaN (и, возможно, + и - infinity) в другое значение?Не имеет значения, потеряна ли информация NaN или infinity, мне просто нужна читаемая строка!

Я знаю, что мог бы сделать что-то подобное:

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

Но я беспокоюсь о техническом обслуживании, поскольку его придется добавлять вручную для любых двойников, сопоставленных с базой данных.

Это было полезно?

Решение

Моим первым впечатлением будет поиск типа, который в Hibernate сохраняется как double . Таким образом, вы можете реорганизовать метод set (...) в DoubleType . Это будет означать, однако, что вам нужно будет аннотировать каждый тип Double с помощью @ org.hibernate.annotations.type (type = " myDouble ") после того, как вы определили " myDouble & Quot; использование @ org.hibernate.annotations.TypeDef в package-info - я думаю, что вы хотите избежать всего этого для сопровождения (помимо этого вам придется идти в самое сердце Hibernate).

Другие советы

Вы можете изменить сам Hibernate. Все, что вам нужно сделать, это изменить класс DoubleType.

Конечно, вам придется поддерживать этот патч по мере развития гибернации, но, учитывая, что он находится в одном достаточно стабильном классе, это может быть проще, чем указание UserType для каждого двойного в вашей доменной модели.

После этого обсуждения, У меня такое ощущение, что hibernate не предлагает способа преобразовать NaN во что-то другое.Я думаю, вы должны предотвратить значения NaN раньше, даже до того, как они будут записаны в переменные-члены bean (например, добавление кода защиты / преобразования к установщикам).

Редактировать

Боюсь, лучшее неприятное решение - использовать защитный код и, что еще хуже, дополнительный столбец в таблице, чтобы указать, является ли значение числом или нет.Что, безусловно, усложнит операции запроса и вставки.Но вам нужен NaN в базе данных, и вы не можете заставить драйвер / базу данных jdbc вести себя должным образом (и принимать NaN в качестве допустимых входных данных для числовых полей).

В конце концов, я использовал решение UserType, но решил проблему обслуживания с помощью модульного теста. Класс типов выглядит следующим образом:

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

Юнит тест примерно такой (некоторые детали для краткости удалены):

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

У меня была точно такая же проблема, и под руководством этих решений я также подготовил класс пользовательских типов, расширяющий DoubleType. Внутри этого класса я преобразовал значения NaN в null в функции set и наоборот для функции get, поскольку для моих столбцов базы данных null в порядке. Я также изменил отображение для возможных столбцов NaN на класс пользовательских типов. Это решение отлично работает в спящем режиме 3.3.2.

К сожалению, после обновления Hibernate до 3.6.10 он перестал работать. Чтобы заставить его работать снова, я заменил пользовательский тип с расширения DoubleType на реализацию UserType.

Важные реализации функций типа данных должны быть следующими:

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

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

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

А вот функции get и 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);
}

извините, но, судя по вашим примерам и вашему вопросу, у вас действительно есть проблемы с пониманием стойкости Java. Объекты базы данных управляются самостоятельно через геттеры и сеттеры - они могут выполнять любую проверку, которую вы хотели бы иметь. Если вы действительно устанавливаете атрибуты без них, вам не хватает основных концепций объектно-ориентированной разработки и персистентности - в частности, управляемых объектов. Мне кажется, что вам нужно реорганизовать свой проект, поскольку подобные проблемы являются явным признаком фундаментальных недостатков дизайна ... просто дать несколько советов здесь - и вот решение:

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

.... это так просто.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top