У меня есть устаревшие таблицы в базе данных Oracle, к которым я хотел бы получить доступ из приложения Java с Hibernate. Проблема в том, что таблицы не имеют хороших первичных ключей. Например, таблица будет выглядеть так:
create table employee (
first_name varchar(64) not null,
last_name varchar(64) not null,
hired_at date,
department varchar(64)
);
create unique index emp_uidx on employee (firstname, lastname, hired_at);
Первоначальный дизайнер решил использовать столбец hired_at
в качестве поля состояния, полагая, что базе данных никогда не нужно будет различать Джона Смита за пределами компании, но что сотрудники с одинаковыми именами могут быть идентифицированы по дате их hired_at , Очевидно, это создает первичный ключ, который частично обнуляем и изменяем. Поскольку база данных не допускает это в качестве первичного ключа, он использует уникальный индекс.
Теперь, если я попытаюсь написать для этого отображение Hibernate, я мог бы придумать что-то вроде этого:
<hibernate-mapping>
<class name="com.snakeoil.personnel" table="employee">
<composite-id class="com.snakeoil.personnel.EmpId" name="id">
<key-property name="firstName" column="first_name" type="string"/>
<key-property name="lastName" column="last_name" type="string"/>
</composite-id>
<property name="hiredAt" column="hired_at" type="date"/>
<property name="department" type="string">
</class>
</hibernate-mapping>
Это работает для чтения данных, но когда я создаю новые записи, которые отличаются только датой приема на работу, я сталкиваюсь с org.hibernate.NonUniqueObjectExceptions. В качестве альтернативы я мог бы рассмотреть возможность Oracle ROWID:
<id column="ROWID" name="id" type="string">
<generator class="native"/>
</id>
Это прекрасно работает и для чтения данных. Но очевидно, что вы не можете сохранять новые объекты, поскольку Hibernate теперь генерирует исключение org.hibernate.exception.SQLGrammarException: не удалось получить следующее значение последовательности при попытке сохранить сущность.
Очевидный выход из этого - суррогатные ключи. Это, однако, потребовало бы изменения схемы базы данных, что возвращает нас к этой "устаревшей" вещи.
Что я пропускаю? Есть ли способ заставить Hibernate сотрудничать с Oracle ROWID, может быть, с другим генератором? Или есть способ заставить первую идею работать, возможно, с помощью умных DAO, которые многократно вытесняют и перезагружают сущности и скрывают сложность от приложения? Или я должен искать альтернативу Hibernate, возможно, Ibatis?