Galera,
Tenho que mapear num sistema uma hierarquia de classes. Tenho a classe Acesso que é abstrata, e as classes AcessoPagina e AcessoComponente que estendem a classe abstrata.
Seguindo a documentação de referência do Hibernate, verifiquei a seguinte forma de realizar este mapeamento, criando uma tabela por classe concreta, ou seja, no meu BD exitem duas tabelas com os atributos da classe abstrata e das classes concretas.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="package.entity">
<class name="Acesso" abstract="true" mutable="true">
<cache usage="transactional" />
<id name="id" type="long" column="ID_ACESSO">
<generator class="native">
<param name="sequence">SQ_ACESSO</param>
</generator>
</id>
<property name="msisdn" type="string" column="MSISDN" />
<union-subclass name="AcessoPagina" table="MD_ACESSO_PAGINA">
<property name="idPagina" type="long" column="ID_PAGINA" />
<property name="idAplicacao" type="long" column="ID_APLICACAO" />
<many-to-one name="idPag" class="Pagina" column="ID_PAGINA" />
<many-to-one name="idAplic" class="Aplicacao" column="ID_APLICACAO" />
</union-subclass>
<union-subclass name="AcessoComponente" table="MD_ACESSO_COMPONENTE">
<property name="idComponente" type="long" column="ID_COMPONENTE" />
<property name="idPagina" type="long" column="ID_PAGINA" />
<many-to-one name="id" class="Componente" column="ID_COMPONENTE" />
<many-to-one name="id" class="Pagina" column="ID_PAGINA" />
</union-subclass>
</class>
</hibernate-mapping>
Porém é apresentado o seguinte erro:
org.hibernate.MappingException: Repeated column in mapping for entity: package.entity.AcessoPagina column: ID_PAGINA (should be mapped with insert="false" update="false")
at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:652)
at org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:674)
Alguém teria idéia da causa deste erro. Procurei por várias alternativas, mas sem sucesso até o momento
Abçs.
Bom dia,
Você está declarando duas vezes o mesmo campo (ou coluna) da tabela.
<union-subclass name="AcessoPagina" table="MD_ACESSO_PAGINA">
<property name="idPagina" type="long" column="ID_PAGINA" /> //propriedade declarada pela primeira vez
<property name="idAplicacao" type="long" column="ID_APLICACAO" />
<many-to-one name="idPag" class="Pagina" column="ID_PAGINA" /> //propriedade declarada pela segunda vez
<many-to-one name="idAplic" class="Aplicacao" column="ID_APLICACAO" />
</union-subclass>
Olá AGAraujo,
Obrigado pela ajuda, mas fiz exatamente o que me indicou, e o erro continua o mesmo.
Alguma outra idéia?
Obrigado.
Passe por favor a estrurua das classes que resolvemos agora!!!
rs.
OK. Desde já agradeço a ajuda.
public abstract class Acesso implements Serializable {
public Long id;
public String msisdn;
private Pagina pagina;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMsisdn() {
return msisdn;
}
public void setMsisdn(String msisdn) {
this.msisdn = msisdn;
}
public Pagina getPagina() {
return pagina;
}
public void setPagina(Pagina pagina) {
this.pagina = pagina;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Acesso))
return false;
Acesso outroAcesso = (Acesso) object;
return this.id == outroAcesso.id;
}
@Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + (getId() != null ? getId().hashCode() : 0);
return hash;
}
}
public class AcessoPagina extends Acesso {
private static final long serialVersionUID = 1L;
private Aplicacao aplicacao;
public Aplicacao getAplicacao() {
return aplicacao;
}
public void setAplicacao(Aplicacao aplicacao) {
this.aplicacao = aplicacao;
}
}
public class AcessoComponente extends Acesso {
private static final long serialVersionUID = 1L;
private Componente componente;
public Componente getComponente() {
return componente;
}
public void setComponente(Componente componente) {
this.componente = componente;
}
}
Meu mapeamento ATUAL:
<hibernate-mapping>
<!-- Mapeamento da subclasse AcessoPagina -->
<class name="package.AcessoPagina" table="MD_ACESSO_PAGINA" lazy="false">
<cache usage="transactional" />
<id name="id" type="long" column="ID_ACESSO">
<generator class="native">
<param name="sequence">SQ_ACESSO</param>
</generator>
</id>
<property name="msisdn" type="string" column="MSISDN"
not-null="true" />
<!-- <property name="pagina" type="long" column="ID_PAGINA" /> -->
<!-- <property name="aplicacao" type="long" column="ID_APLICACAO" /> -->
<many-to-one name="pagina" class="Pagina">
<column name="ID_PAGINA" />
</many-to-one>
<many-to-one name="aplicacao" class="Aplicacao">
<column name="ID_APLICACAO" />
</many-to-one>
</class>
<!-- Mapeamento da subclasse AcessoComponente -->
<class name="package.AcessoComponente" table="MD_ACESSO_COMPONENTE"
lazy="false">
<cache usage="transactional" />
<id name="id" type="long" column="ID_ACESSO">
<generator class="native">
<param name="sequence">SQ_ACESSO</param>
</generator>
</id>
<property name="msisdn" type="string" column="MSISDN"
not-null="true" />
<!-- <property name="pagina" type="long" column="ID_PAGINA" /> -->
<!-- <property name="aplicacao" type="long" column="ID_APLICACAO" /> -->
<many-to-one name="componente" class="Componente">
<column name="ID_COMPONENTE" />
</many-to-one>
<many-to-one name="pagina" class="Pagina">
<column name="ID_PAGINA" />
</many-to-one>
</class>
</hibernate-mapping>
Vlws
Boa cabra…
de cara já vi que o mapeamento anterior este estão diferentes… ou outro você mapeou como union-subclass e agora não.
O erro é o mesmo com este mapeamento?
De qualquer forma vou testar aqui e em 15 minutos retorno com a resposta.
Olha só consegui reproduzir seu erro fazendo como eu disse, utilizando a propriedade e o mapeamento de ManyToOne.
Voce num poderia mandar zipado apenas estas classes e seus respectivos mapeamentos para eu ver melhor, pois não consegui reproduzir o erro de outra forma.
Mande as 5 classes envolvidas e os respectivos mapeamentos. Ai resolvemos.
Vou preparar aqui o que fiz e envio ja tb
AgAraujo, obrigado pela atenção.
Seguinte, são estas as classes e apenas 1 arquivo de mapeamento. No caso ele mapaeia as classes concretas, e cada classe concreta possui uma tabela no BD.
Abçs.
[quote=AGAraujo]Boa cabra…
de cara já vi que o mapeamento anterior este estão diferentes… ou outro você mapeou como union-subclass e agora não.
O erro é o mesmo com este mapeamento?
De qualquer forma vou testar aqui e em 15 minutos retorno com a resposta.[/quote]
Verdade. Tentei de outra forma, mas ocorre o mesmo erro.
isso ocorre mesmo!! quanto o hibernate tem objetos que apontam para a mesma coluna vc tem que dizer qual que será persistido!! eu sempre deixo o objeto pro exemplo Pessoa como update false e insert false e crio um private Integer codPessoaPersistir;
desta forma quando eu quiser buscar a pessoa, sempre ela será carregada pelo mapeamento do objeto Pessoa e ao gravar ou atualizar seto a propriedade codPessoaPersistir
ok!!!
Olá arthurminarini,
Sim, mas reference-se a colunas diferentes, visto que no BD criei uma tabela para cada subclasse. Isso deveria ocorrer mesmo neste caso?
Abçs.
Cara seguinte, meu tempo está esgotando e queria deixar isto resolvido (em retribuíção ao que o GUJ já me ajudou). Vamos lá!!
Segue as classe que eu fiz o teste para tentar simular sua situação.
[code]public abstract class Access implements Serializable{
private Integer id;
private String name;
private Page page;
…
}
public class AccessComponent extends Access {
…
}
public class AccessPage extends Access {
…
}
public class Page implements Serializable{
private Integer id;
private String url;
…
}[/code]
Estas são as entidades que tenho e abaixo segue o mapeamento das classes utilizando a estratégia “table_per_class_concret”.
Arquivo Access.hbm.xml
<hibernate-mapping>
<class name="hibernateestudo.entities.Access" abstract="true">
<id name="id" column="id" access="field" />
<property name="name" column="name" />
<union-subclass name="hibernateestudo.entities.AccessPage" table="tb_accesspage" >
<many-to-one class="hibernateestudo.entities.Page" name="page" >
<column name="idpage" />
</many-to-one>
</union-subclass>
<union-subclass name="hibernateestudo.entities.AccessComponent" table="tb_accesscomp" >
<many-to-one class="hibernateestudo.entities.Page" name="page" >
<column name="idpage" />
</many-to-one>
</union-subclass>
</class>
</hibernate-mapping>
Arquivo Page.hbm.xml
<hibernate-mapping>
<class name="hibernateestudo.entities.Page" table="tb_page" >
<id name="id" column="id" />
<property name="url" column="url" />
</class>
</hibernate-mapping>
Tente comparar com o que você tem. Este mapeamento cria 3 tabelas, sendo estas “TB_ACCESSPAGE”, “TB_ACCESSCOMP” e “TB_PAGE”.
Veja se ajuda ai.
[quote=arthurminarini]isso ocorre mesmo!! quanto o hibernate tem objetos que apontam para a mesma coluna vc tem que dizer qual que será persistido!! eu sempre deixo o objeto pro exemplo Pessoa como update false e insert false e crio um private Integer codPessoaPersistir;
desta forma quando eu quiser buscar a pessoa, sempre ela será carregada pelo mapeamento do objeto Pessoa e ao gravar ou atualizar seto a propriedade codPessoaPersistir
ok!!![/quote]
Boa arthur,
só complementando sua colocação: o mapeamento para um propriedade mais de uma vez só deve ser visto em casos raros, sendo que na maioria das vezes é possível contornar isto. E claro que se isto realmente ocorrer é necessário definir no mapeamento que esta propriedade somente será alterada por uma única referência (no caso, as outras ficarão com updateble=false e insertable=false).
Porém para o caso do maranata o problema está na definição da estratégia de mapeamento com hierarquia (herança).
No primeiro caso que ele definiu, utilizou uma estratégia, depois postou outra. O caso que enviei a pouco para ele é a estratégia baseada na primeira situação, que resolve sem a preocupação de ter uma propriedade mapeada mais de uma vez.
Muito obrigado AGAraujo e arthurminarini.
AGAraujo vou tentar aqui, mas desde agradeço imensamente a atenção. Isso é raro. Parabéns!!!
Abçs.
Engradaço. Infelizmente não funcionou. Numa tentativa, quebrei a hierarquia, excluindo a classe Acesso e replicando seus atributos nas classes AcessoPagina e AcessoComponente (gerando duplicação de código :oops: ). Mas foi só para teste!!! E para minha surpresa gerou EXATAMENTE o mesmo erro…
Devo estar dando alguma outra cabeçada, mas qual?
Você já tem uma base de dados criada?
Está usando esta base de dados?
Se for manda o schema das 3 entidades (tabelas).
AGAraujo,
Tenho sim a base criada, a qual estou utilizando. As tabelas estão com suas respectivas FK criadas.
Segue os schemas solicitados. Mas eu criei uma tabela por subclasse. Para a classe abstrata eu não criei tabela, ok?
CREATE TABLE "MD_ACESSO_COMPONENTE"
( "ID_ACESSO" NUMBER,
"ISDN" VARCHAR2(4000 BYTE),
"ID_COMPONENTE" NUMBER,
"ID_PAGINA" NUMBER
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS NOLOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "BDR" ;
CREATE TABLE "MD_ACESSO_PAGINA"
( "ID_ACESSO" NUMBER,
"MSISDN" VARCHAR2(4000 BYTE),
"ID_PAGINA" NUMBER,
"ID_APLICACAO" NUMBER
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS NOLOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "BDR" ;
Abçs.
Cara fiz um teste usando sua entidades (tabelas)
Seu mapeamento deve ser este que se segue. Se ainda sim não der certo, o problema está em outro lugar… tipo: arquivo de configuração duplicado, ou coisas do tipo… mas teste primeiro.
Faça somente os ajustes necessários para suas classes.
<hibernate-mapping package="package.entity">
<class name="Acesso" abstract="true">
<cache usage="transactional" />
<id name="id" type="long" column="ID_ACESSO">
<generator class="native">
<param name="sequence">SQ_ACESSO</param>
</generator>
</id>
<union-subclass name="AcessoPagina" table="MD_ACESSO_PAGINA">
<property name="isdn" type="string" column="ISDN" />
<many-to-one name="idPag" class="Pagina" column="ID_PAGINA" />
<many-to-one name="idAplic" class="Aplicacao" column="ID_APLICACAO" />
</union-subclass>
<union-subclass name="AcessoComponente" table="MD_ACESSO_COMPONENTE">
<property name="msisdn" type="string" column="MSISDN" />
<many-to-one name="idComp" class="Componente" column="ID_COMPONENTE" />
<many-to-one name="idPag" class="Pagina" column="ID_PAGINA" />
</union-subclass>
</class>
</hibernate-mapping>
Estou reenviando o cogido adaptando as classes que me passou num post anterior.
Segue-se:
<hibernate-mapping package="package.entity">
<class name="Acesso" abstract="true">
<cache usage="transactional" />
<id name="id" type="long" column="ID_ACESSO">
<generator class="native">
<param name="sequence">SQ_ACESSO</param>
</generator>
</id>
<union-subclass name="AcessoPagina" table="MD_ACESSO_PAGINA">
<property name="msisdn" type="string" column="ISDN" />
<many-to-one name="pagina" class="Pagina" column="ID_PAGINA" />
<many-to-one name="aplicacao" class="Aplicacao" column="ID_APLICACAO" />
</union-subclass>
<union-subclass name="AcessoComponente" table="MD_ACESSO_COMPONENTE">
<property name="msisdn" type="string" column="MSISDN" />
<many-to-one name="componente" class="Componente" column="ID_COMPONENTE" />
<many-to-one name="pagina" class="Pagina" column="ID_PAGINA" />
</union-subclass>
</class>
</hibernate-mapping>
para as classes
[code]public abstract class Acesso implements Serializable {
public Long id;
public String msisdn;
private Pagina pagina;
…
}
public class AcessoPagina extends Acesso {
private Aplicacao aplicacao;
…
}
public class AcessoComponente extends Acesso {
private Componente componente;
…
}[/code]
mantendo seu banco de dados como está.
Prezados,
O erro é bizarro. Primeiro limpei o cache do navegador e depois do tomcat (pasta work). Não resolveu. Depois, exclui as classes Acesso, AcessoComponente e AcessoPagina da aplicação. Exclui também o arquivo de mapeamento e também a referência no arquivo de configuração do hibernate.
Supreendemente, continua a ocorrer a maledito erro!!!
Bizarro :shock: