Как аннотировать столбец Id, если значение генерируется триггером? - PullRequest
8 голосов
/ 18 августа 2011

У меня есть установка с Oracle XE 10g, Hibernate 3.5, JPA 2.0. Существует простая таблица с первичным ключом, которая генерируется триггером базы данных при вставке. Триггер получает значение из последовательности. Конструкция триггера / последовательности была создана Oracle XE.

Фактический вопрос: как мне получить текущее значение Id в моей сущности после EntityManager.persist?
Я попробовал:

@Id
private long id;

-> идентификатор: 0;

@Id
@Generated(GenerationTime.ALWAYS)
@Column(insertable = false, updatable = false)
private long id;

-> идентификатор: 0;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;

-> Сбой из-за того, что Hibernate пытается напрямую запросить последовательность (которая не существует).

Идентификаторы генерируются в базе данных при первых двух подходах, но у меня нет значения в моем объекте .

Ответы [ 3 ]

7 голосов
/ 18 декабря 2012

Вопреки комментариям @JB Низета, я могу думать о многих причинах, по которым мы позволяем триггеру назначать идентификаторы: выполнение хранимых процедур, ручное выполнение SQL-запросов и выполнение собственных запросов в Hibernate, и это только некоторые из них.

Лично я нашел следующее решение вполне удовлетворительным. Это позволяет Hibernate найти максимальный идентификатор и увеличивать его каждый раз, когда вызывается оператор вставки. Но когда оператор попадает в базу данных, идентификатор игнорируется и переопределяется идентификатором, сгенерированным триггером, поэтому уникальность в проблеме кластера :

    @Id
    @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;

Самый большой недостаток - @GenericGenerator - это аннотация Hibernate, поэтому вы теряете переносимость JPA. Программистам также не ясно, что этот идентификатор на самом деле связан с последовательностью.

Другой альтернативой является изменение триггера на последовательность приращения только тогда, когда идентификатор равен нулю. См. « Проблема спящего режима с Oracle Trigger для генерации идентификатора из последовательности ». В большинстве случаев это лучшее решение, поскольку оно четко показывает, что идентификатор связан с последовательностью. Единственное, что меня беспокоит, так это то, что он дает пользователю / спящему параметру возможность вставлять любой идентификатор без фактического запроса последовательности в первую очередь.

2 голосов
/ 18 августа 2011

Если вы не привязаны к триггеру, это похоже на уровень запутывания в последовательности, и он выходит за рамки обычного жизненного цикла Hibernate.Почему бы напрямую не вызвать последовательность:

@SequenceGenerator(name="alias_for_my_sequence", sequenceName="seq_name_in_oracle")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="alias_for_my_sequence")
@Id
private Long id;

Тогда вы получите значение обратно, так как Hibernate непосредственно участвует в генерации, и после этого ничего не происходит.

1 голос
/ 14 октября 2011

Вы можете обменять сгенерированный дБ ключ в сеансе Oracle. Для этого триггер вставки должен вызвать

dbms_session.set_identifier(new_id)

Из вашего кода вы можете получить новое значение ключа с помощью запроса

String sql = "SELECT sys_context('USERENV', 'CLIENT_IDENTIFIER') FROM dual";
Query query = em.createNativeQuery(sql);
String new_id = (String) query.getSingleResult();

Важно использовать один и тот же экземпляр EntityManager для сохранения новой сущности и получения сгенерированного значения ключа.

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