Mappatura di due tabelle 0..n in Hibernate
-
22-09-2019 - |
Domanda
Ho una tabella Utenti
CREATE TABLE "USERS" (
"ID" NUMBER NOT NULL ,
"LOGINNAME" VARCHAR2 (150) NOT NULL )
e ho una seconda tabella SpecialUsers.Nessun UserId può essere presente due volte nella tabella SpecialUsers e solo un piccolo sottoinsieme degli ID degli utenti nella tabella Users è contenuto nella tabella SpecialUsers.
CREATE TABLE "SPECIALUSERS" (
"USERID" NUMBER NOT NULL,
CONSTRAINT "PK_SPECIALUSERS" PRIMARY KEY ("USERID") )
ALTER TABLE "SPECIALUSERS" ADD CONSTRAINT "FK_SPECIALUSERS_USERID" FOREIGN KEY ("USERID")
REFERENCES "USERS" ("ID")
/
La mappatura della tabella Users in Hibernate funziona bene
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="USERS">
<id name="id" column="ID" type="java.lang.Long">
<meta attribute="use-in-tostring">true</meta>
<generator class="sequence">
<param name="sequence">SEQ_USERS_ID</param>
</generator>
</id>
<property name="loginName" column="LOGINNAME" type="java.lang.String" not-null="true">
<meta attribute="use-in-tostring">true</meta>
</property>
</class>
</hibernate-mapping>
Ma ho difficoltà a creare la mappatura per la tabella SpecialUsers.Tutti gli esempi (es.nella documentazione di Hibernate) in Internet ho scoperto che non hanno questo tipo di autoreferenzialità.Ho provato una mappatura come questa:
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="SPECIALUSERS">
<id name="id" column="USERID">
<meta attribute="use-in-tostring">true</meta>
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<one-to-one name="user" class="User"/>
</class>
</hibernate-mapping>
ma ho ricevuto l'errore
Invocation of init method failed; nested exception is org.hibernate.DuplicateMappingException:
Duplicate class/entity mapping com.initech.User
Come devo mappare la tabella SpecialUsers?Ciò di cui ho bisogno a livello applicativo è un elenco degli oggetti User contenuti nella tabella SpecialUsers.
Soluzione
Come devo mappare la tabella SpecialUsers?
Secondo la struttura del tuo USERS
E SPECIALUSERS
tavoli, hai un Tabella per sottoclasse gerarchia e è perfettamente possibile mappare questo tipo di gerarchia con Hibernate.
Per prima cosa, assicurati che SpecialUser
eredita da User
a livello del modello a oggetti (si tratta di una relazione di ereditarietà, non di autoreferenzialità).
public class SpecialUser extends User {
}
Quindi dichiarare a <joined-subclass>
elemento in User
la mappatura di:
<hibernate-mapping package="com.initech.domain">
<class name="com.initech.User" table="USERS">
<id name="id" column="ID" type="java.lang.Long">
<meta attribute="use-in-tostring">true</meta>
<generator class="sequence">
<param name="sequence">SEQ_USERS_ID</param>
</generator>
</id>
<property name="loginName" column="LOGINNAME" type="java.lang.String" not-null="true">
<meta attribute="use-in-tostring">true</meta>
</property>
<joined-subclass name="com.initech.SpecialUser" table="SPECIALUSERS">
<key column="USERID"/>
</joined-subclass>
</class>
</hibernate-mapping>
Ciò di cui ho bisogno a livello applicativo è un elenco degli oggetti User contenuti nella tabella SpecialUsers.
La seguente query HQL restituirebbe tutti i file SpecialUser
(quali sono User
pure):
from SpecialUser
Se in seguito è necessario aggiungere colonne al file SPECIALUSERS
tabella, aggiungi gli attributi corrispondenti alla tabella SpecialUser
class e mapparli all'interno del file <joined-subclass>
elemento.Fare riferimento al collegamento fornito (alla documentazione) per i dettagli.
Altri suggerimenti
Se è davvero necessario utilizzare una seconda tabella, è necessario associare ad una nuova classe. Hibernate può sempre mappare solo una tabella ad una classe.
In alternativa, aggiungere una colonna alla tabella utente che dice "questo utente è speciale". Se questo non è un'opzione, creare una vista che unisce le due tabelle e simula questa colonna in tal modo. Quindi, è possibile selezionare gli utenti da questa colonna.
Se si va il modo in due classi, è necessario caricare un elenco di utenti speciali e fare la mappatura nell'applicazione.
[EDIT] Forse si dovrebbe guardare in relazioni padre-figlio. Nel tuo caso, l'utente è il capogruppo e le sue funzioni sono i figli. Quindi, ogni utente ha 0..n ruoli che sono mappati in una tabella diversa. È quindi possibile utilizzare questo HQL
from User u where :role in elements(u.roles)
per trovare tutti gli utenti con un certo ruolo. Ma la maggior parte del tempo, avrete un utente specifico e solo bisogno di interrogare se ha un certo ruolo.