Hibernate пакетная операция не работает, как ожидалось - PullRequest
1 голос
/ 03 декабря 2010

У меня есть класс Person со следующими полями:

id, hashedId, описание

id - это первичный ключ, сгенерированный последовательностью, а hashedId не равен Null.

Я делаю следующее:

  1. session.saveOrUpdate (person)
  2. person.setHashedId (hash (person.getId ()))

Идентификатор автоматически генерируется в БД.Когда я делаю это, разве я не ожидаю только 2 операторов

  1. Выберите, чтобы получить следующий идентификатор последовательности (идентификатор человека)
  2. Вставить, чтобы вставить запись о человеке?

Тем не менее, он пытается вставить сразу после шага 1 (во время окончательной фиксации транзакции, конечно) с нулевым hashedId - я получаю обратно ошибку нарушения ограничения - HashedId не может быть нулевым.

Ответы [ 3 ]

2 голосов
/ 03 декабря 2010

Когда вы вызываете Session.save() или подобное, Hibernate немедленно генерирует идентификаторы и выполняет вставку, а не просто ставит ее в очередь, чтобы сохранить позже. Таким образом, нет пробела, в котором элемент имеет свой идентификатор, назначенный до его вставки. Для стратегии генерации идентификаторов «идентичности» все равно их невозможно разделить ...

По моему опыту, самый безопасный и простой способ справиться с этим случаем - это использовать Interceptor (или, может быть, EventListener?), Чтобы перехватить сущность, вставляемую с незаданным свойством hashedId, и сгенерировать ее непосредственно перед сохранением. Это немного неприятно, но ИМХО лучше, чем затягивать генерацию идентификатора в код приложения.

Вот пример, в котором я генерирую свойство 'reference' для новой сущности Ticket (используя Interceptor):

public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
    Type[] types) {
    boolean changed = super.onSave(entity, id, state, propertyNames, types);

    if (entity instanceof Ticket) {
        for (int i = 0; i < propertyNames.length; i++) {
            if (propertyNames[i].equals("reference") && state[i] == null) {
                state[i] = generateTicketReference((Integer) id);
                changed = true;
            }
        }
    }

    return changed;
}
1 голос
/ 03 декабря 2010

Hibernate делает правильные вещи :-) См. http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping-declaration-id, раздел "5.1.4.4. Столбцы и последовательности идентификаторов"

Это потому, что Hibernate не знает об идентификаторе, если он генерируетсяпо БД.И идентификатор на самом деле не присваивается записи только потому, что вы вызвали последовательность.Таким образом, вы должны либо позволить Hibernate сохранить запись и получить фактический идентификатор для записи, либо использовать идентификатор, сгенерированный Hibernate (например, hilo) (или сгенерировать его самостоятельно, с назначенным типом генератора).

0 голосов
/ 04 декабря 2010

Поле HashedId получено из идентификатора, верно? основанный на недорогой функции, я полагаю? Так что в этом случае вам действительно нужно сохранить это поле в БД? Используете ли вы это непосредственно в запросах? Разве вы не можете просто заставить метод getHashedId () всегда возвращать хеш (this.id)? Таким образом, у вас не будет этого поля hashedId в БД, и вам не придется им управлять - так как оно просто выводится на основе идентификатора.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...