Mapeamento Herança Hibernate

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 :cry:

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 :wink:

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. :cry:

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: