J'ai des tables héritées dans une base de données Oracle auxquelles j'aimerais accéder à partir d'une application Java avec Hibernate. Le problème est le suivant: les tables n'ont pas de bonnes clés primaires. Par exemple, une table ressemblerait à ceci:Table Oracle ancienne sans PK bon: Comment Hiberner?
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);
Le concepteur original a décidé d'utiliser la colonne hired_at
comme un champ d'état, pensant que la base de données aurait jamais besoin de faire la distinction entre le John Smith en dehors de la société, mais les employés portant le même nom pourraient être identifiés par leur date d'embauche. Évidemment, cela crée une clé primaire partiellement nulle et modifiable. Comme la base de données ne l'autorisait pas en tant que clé primaire, il utilisait un index unique à la place.
Maintenant, si je tente d'écrire un mapping Hibernate pour cela, je pourrais venir avec quelque chose comme ceci:
<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>
Cela fonctionne pour les données de lecture, mais quand je crée de nouvelles entrées qui ne diffèrent que par leur HiredAt date, je cours dans org.hibernate.NonUniqueObjectExceptions. Alternativement, je pourrais envisager la fonctionnalité ROWID d'Oracle:
<id column="ROWID" name="id" type="string">
<generator class="native"/>
</id>
Cela fonctionne très bien pour lire des données, aussi. Mais évidemment, vous ne pouvez pas persister de nouveaux objets, car Hibernate lance maintenant une exception org.hibernate.exception.SQLGrammarException: n'a pas pu obtenir la valeur de la séquence suivante en essayant de stocker l'entité.
La solution la plus évidente consiste à utiliser des clés de substitution. Cela nécessiterait toutefois de modifier le schéma de la base de données, ce qui nous ramène à cette situation «patrimoniale».
Que suis-je en train de négliger? Existe-t-il un moyen de faire coopérer Hibernate avec le ROWID d'Oracle, peut-être avec un générateur différent? Ou y a-t-il un moyen de faire fonctionner la première idée, peut-être avec des DAOs intelligents qui expulsent et rechargent beaucoup d'entités, et cachent la complexité de l'application? Ou devrais-je chercher une alternative à Hibernate, Ibatis peut-être?
Oui, semble que c'est la meilleure idée.Toutes les autres options semblent exiger une magie DAO cryptographique – wallenborn
Oracle ROWID est" stable "Le seul problème est quand (citation): _Si vous supprimez et réinsérez une ligne avec l'importation et l'exportation Utilitaires, par exemple, alors son rowid peut changer.Si vous supprimez une ligne, alors Oracle peut réaffecter son rowid à une nouvelle ligne insérée plus tard._ – xmedeko
@xmedeko - l'omis volontairement la première phrase de ce paragraphe "Vous ne devriez pas utiliser ROWID comme la clé primaire d'une table. "Http://docs.oracle.com/cd/B19306_01/server.102/b14200/pseudocolumns008.htm – APC