вторник, 29 июня 2010 г.

Hibernate and primitive type values

  Примитивные примитивы слишком примитивны для хибернэйта. Парадигму мозгоёбства можно описать следующей фразой одного эксперта:Hibernate doesn't care about values, just mappings(https://forum.hibernate.org/viewtopic.php?t=949814).Сказал в 2004 году - как отрезал. Ничего пока принципиально не поменялось. Геморой проистекает из того, что хибернэйт по-умолчнию вместо примитивных типов пишет в базу null. А потом приводит этот null к примитивам(например int). Так что вылетающие из недр хибернэйта
org.springframework.orm.hibernate3.HibernateSystemException: Null value was assigned to a property of primitive type setter of  MovableObject.movingStatus; nested exception is org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of MovableObject.movingStatus
-"это нормально".

Вообще хибернэйт не обладает magic свойствами, всё что он гарантирует в плане метаданных-
а)При начале работы с чистой бд все мапинги хибернэйта будут промаплены
б)При изменениее мапинга старые данные не будут утеряны

А это означает что изменение мапинга столбцов, таблиц и тп, на уже существующую бд через хибернэйт - будут "как то" применены. "Как-то" - по факту это добавление новых столбцов в таблицу, и сохранение метаданных старых.

Лечение. 

1) 100% лечение. Переписывем все геттеры. вместо примитивных типов используем врапперы (Integer) и делаем их проверку на null

    @Column(name = "OBJECTSTATUS")
    private Integer objectStatus ;


    public int getObjectStatus() {
        if (objectStatus == null) {
            objectStatus = 0;
        }
        return objectStatus;
    }

2) @Column(name = "OBJECTSTATUS", nullable = false)
Лечение работает при вставках новых объектов с незаданными полями, имеет ряд противопоказаний. При добавлении мапинга нового столбца лечение не сработает. Также оно вероятно не сработает если изменить мапинг уже существующей колонки(c firebird 2.1.3+hibernate 3.5.1 не сработает точно).
  
Так же присутствует полный просос при работе с наследованием по @DiscriminatorValue - поля которые казалось бы не используются в объектной модели, очень даже используются в таблицах и как результат - ошибки хибернэйта при попытках кастовать  нулл к примитивам.

3)@Column(name = "OBJECTSTATUS")
    private int objectStatus = 0;
Лечение работает при вставках новых объектов с незаданными полями 

   

Самым правильным наверное будет делать так:

  @Column(name = "OBJECTSTATUS")
    private Integer objectStatus=0;

    public int getObjectStatus() {
        if (objectStatus == null) {
            objectStatus = 0;
        }
        return objectStatus;
    }

-при вставках строк гарантируем что будет выставлен везде 0
-при вставке столбца  гарантируем что не возникнет ошибки и через геттер всегда получим дефолтное значение



PS.
1)прокачать знания про то как 6.2.1. Hibernate event-based validation 2)@NotFound(action=NotFoundAction.IGNORE) - это для объектов

понедельник, 21 июня 2010 г.

String.format depends on locality...

Неожиданно. Сужает область применения String.format до вывода в консоль.
public class xxx {
    @Test
    public void xxxx() {
        double xxx = 123.5657;
        System.out.println(Double.toString(xxx));
        //123.5657
        System.out.println(String.format("%.2f", xxx));//работет прально если Formatter formatter = new Formatter(sb, Locale.US)
        //123,57
        System.out.println((new BigDecimal(xxx)).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
        //123.57
        String.format("%.2f", xxx).replaceAll(",", ".");
        //123.57
    }
}