Mapeando duas tabelas 0..n em hibernado
-
22-09-2019 - |
Pergunta
Eu tenho uma mesa usuários
CREATE TABLE "USERS" (
"ID" NUMBER NOT NULL ,
"LOGINNAME" VARCHAR2 (150) NOT NULL )
E eu tenho uma segunda tabela especialistas. Nenhum IID do usuário pode ocorrer duas vezes na tabela Specialusers, e apenas um pequeno subconjunto dos IDs dos usuários na tabela de usuários estão contidos na tabela 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")
/
Mapeando a tabela de usuários em Hibernate funciona bem
<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>
Mas estou lutando para criar o mapeamento para a mesa do Specialusers. Todos os exemplos (por exemplo, documentação de hibernados) na Internet que achei que não têm esse tipo de auto-referência. Eu tentei um mapeamento assim:
<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>
mas obteve o erro
Invocation of init method failed; nested exception is org.hibernate.DuplicateMappingException:
Duplicate class/entity mapping com.initech.User
Como devo mapear a tabela de especialistas? O que eu preciso no nível do aplicativo é uma lista dos objetos do usuário contidos na tabela Specialusers.
Solução
Como devo mapear a tabela de especialistas?
De acordo com a estrutura do seu USERS
e SPECIALUSERS
mesas, você tem um Tabela por subclasse hierarquia e É perfeitamente possível mapear esse tipo de hierarquia com hibernado.
Primeiro, certifique -se de que SpecialUser
herda a partir de User
No nível do modelo de objeto (essa é uma relação de herança, não uma auto-referência).
public class SpecialUser extends User {
}
Então, declare um <joined-subclass>
elemento no User
Mapeamento:
<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>
O que eu preciso no nível do aplicativo é uma lista dos objetos do usuário contidos na tabela Specialusers.
A seguinte consulta HQL retornaria todo o SpecialUser
(que são User
também):
from SpecialUser
Se mais tarde você precisar adicionar colunas ao SPECIALUSERS
tabela, adicione os atributos correspondentes ao SpecialUser
classe e mapeá -los dentro do <joined-subclass>
elemento. Consulte o link fornecido (à documentação) para obter os detalhes.
Outras dicas
Se você realmente precisar usar uma segunda tabela, deve mapeá -la para uma nova classe. O Hibernate sempre pode mapear apenas uma tabela para uma classe.
Como alternativa, adicione uma coluna à tabela de usuários que diz "esse usuário é especial". Se isso não for uma opção, crie uma visualização que une as duas tabelas e, assim, simula esta coluna. Em seguida, você pode selecionar usuários nesta coluna.
Se você seguir o caminho de duas classes, deve carregar uma lista dos usuários especiais e fazer o mapeamento em seu aplicativo.
Editar] Talvez você deva olhar para as relações entre pais e filhos. No seu caso, o usuário é o pai e seus papéis são os filhos. Portanto, todo usuário tem 0 .. N funções que são mapeadas em uma tabela diferente. Você pode então usar este HQL
from User u where :role in elements(u.roles)
para encontrar todos os usuários com uma determinada função. Mas na maioria das vezes, você terá um usuário específico e só precisará consultar se ela tem uma certa função.