Унаследованная таблица Oracle без хорошего ПК: как переходить в спящий режим? - PullRequest
7 голосов
/ 05 октября 2009

У меня есть устаревшие таблицы в базе данных 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?

Ответы [ 2 ]

7 голосов
/ 05 октября 2009

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

Лучше всего добавить синтетический ключ. Используйте триггер, чтобы заполнить столбец значением последовательности.

Вы немного расплывчаты в унаследованном аспекте, поэтому трудно быть уверенным, каковы последствия. Добавление столбца нарушило бы любой оператор вставки, который явно не перечисляет целевые столбцы. Он также может разбить любые запросы SELECT * (если только они не выбраны в переменную, объявленную с использованием ключевого слова %ROWTYPE. Но вам не придется изменять любое другое приложение, поэтому оно использует новый первичный ключ вместо существующих столбцов - если только вы очень хочу.

5 голосов
/ 05 октября 2009

Я бы добавил суррогатный ключ с последовательностью поддержки. Это не изменит вашей наследственной семантики, и Hibernate будет удовлетворен.

Просто любопытно - если в индексе есть имя, фамилия и дата найма, почему ваш составной ключ исключает дату найма? Я бы также ожидал увидеть все поля индекса в составном ключе.

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