Collections no Hibernate

12 respostas
Rodrigo_Carvalho_Aul

Estou tentando usar o Hibernate. Na hora de fazer a persistência de classes simples tá beleza, mas não estou conseguindo fazer quando tenho uma classe com uma collection:

public class Empresa {
	private int id;
	private String razaoSocial;
	private String cnpj;
	private String inscricaoEstadual;
	private String inscricaoMunicipal;
	private String site;
	private Email[] emails;

	public String getCnpj() {
		return cnpj;
	}

	public Email[] getEmails() {
		return emails;
	}

	public int getId() {
		return id;
	}

	public String getInscricaoEstadual() {
		return inscricaoEstadual;
	}

	public String getRazaoSocial() {
		return razaoSocial;
	}

	public String getSite() {
		return site;
	}

	public void setCnpj(String string) {
		cnpj = string;
	}

	public void setEmails(Email[] emails) {
		this.emails = emails;
	}

	public void setId(int i) {
		id = i;
	}

	public void setInscricaoEstadual(String string) {
		inscricaoEstadual = string;
	}

	public void setRazaoSocial(String string) {
		razaoSocial = string;
	}

	public void setSite(String string) {
		site = string;
	}

	public String getInscricaoMunicipal() {
		return inscricaoMunicipal;
	}

	public void setInscricaoMunicipal(String string) {
		inscricaoMunicipal = string;
	}

}

O mapeamento está assim:

<hibernate-mapping>
	<class name="Empresa" table="Empresas">
		<id name="id" type="int" unsaved-value="null" />
		<property name="razaoSocial"/>
		<property name="cnpj"/>
		<property name="inscricaoEstadual"/>
		<property name="inscricaoMunicipal"/>
		<property name="site"/>
		<set name="emails" table="EmpresasEmails" readonly="true">
			<key column="Empresa"/>
			<many-to-many column="Email" class="Email"/>
		</set>
	</class>
</hibernate-mapping>

Na primeira vez que tento dar um save com esse objeto, ele dá erro de NullPointerException e depois fica dizendo que a tabela tá lockada.

Alguém tem alguma idéia?

PS: estou usando o MySql 4 e a classe Email está mapeada e funcionando.

12 Respostas

cv1

Nao tenho certeza sobre o uso de arrays com o mapeamento <set>… nao seria melhor usar um java.util.Set ou uma outra Collection?

Alias, se alguem puder esclarecer isso, eu agradeco :smiley:

maxguzenski


o hibernate nao funciona com Arrays, deve-se usar List ou Set

no seu caso, que me parece ser um relacionamento de one-to-many
deve-se usar Set

private Set email;

public void setEmail(Set email) {
   this.email = email;
}


o relacionamento many-to-many so se usa quando se tem uma tabela intermediaria e vc quer retira-la no mappiamento.
como disse, é one-to-many, pois cada registro (1) aponta para varios (many)


o Set funciona usando codigo hash e metodo equals quando acontecer colisao de codigo hash (interface Set nao aceita elementos repetidos)

aconcelho profundamente, voce redefenir os metodos “public int hashCode()” e “public boolean equals(Object o)”
para maior performace.

Rodrigo_Carvalho_Aul

Eu tentei usar List ou Set e deu o erro:

javax.servlet.ServletException: Empresa.setEmails([LEmail;)V

Mas eu acho que no meu caso é many-to-many sim. Veja a estrutura de tabelas:

CREATE TABLE `Emails` (
	`ID` int(10) NOT NULL auto_increment,
	`Endereco` varchar(50) NOT NULL,
	PRIMARY KEY  (`ID`),
	UNIQUE  (`Endereco`)
) TYPE=InnoDB;

CREATE TABLE `Empresas` (
	`ID` int(10) NOT NULL auto_increment,
	`RazaoSocial` varchar(50) NOT NULL,
	`CNPJ` char(14) NULL,
	`InscricaoEstadual` varchar(20) NULL,
	`InscricaoMunicipal` varchar(20) NULL,
	`Site` varchar(50) NULL,
	PRIMARY KEY  (`ID`),
	UNIQUE (`CNPJ`)
) TYPE=InnoDB;

CREATE TABLE `EmpresasEmails` (
	`Empresa` int(10) NOT NULL,
	`Email` int(10) NOT NULL,
	UNIQUE (`Empresa`, `Email`),
	INDEX `indexEmpresa` (`Empresa`),
	INDEX `indexEmail` (`Email`),
	FOREIGN KEY (`Empresa`) REFERENCES `Empresas`(`ID`),
	FOREIGN KEY (`Email`) REFERENCES `Emails`(`ID`)
) TYPE=InnoDB;
ricardolecheta

Collections are declared by the set, list, map, bag, array and <primitive-array>

http://hibernate.bluemars.net/hib_docs/reference/html/collections.html#collections-s1-3

cv1

“maxguzenski”:
aconcelho profundamente, voce redefenir os metodos “public int hashCode()” e “public boolean equals(Object o)”
para maior performace.

Cuidado com isso… redefinir equals() e hashCode() nao garante ganhos de performance, e pode levar a bugs sérios se vc não souber direito o que tá fazendo, ainda mais quando vc está trabalhando com Sets, que dependem desses métodos pra fazer a classificação dos objetos :wink:

Rodrigo_Carvalho_Aul

Eu já tinha tentado com <array>, não tinha visto o <primitive-array>. mas dá erro de java.lang.NullPointerException.

O Mapeamento ficou assim:

<hibernate-mapping>
	<class name="Empresa" table="Empresas">
		<id name="id" type="int" unsaved-value="null" />
		<property name="razaoSocial"/>
		<property name="cnpj"/>
		<property name="inscricaoEstadual"/>
		<property name="inscricaoMunicipal"/>
		<property name="site"/>
		<primitive-array name="emails" table="EmpresasEmails" cascade="all">
			<key column="Empresa"/>
			<many-to-many column="Email" class="Email"/>
		</primitive-array>
	</class>
</hibernate-mapping>
ricardolecheta

java.lang.NullPointerException aonde?

para saber mais sobre as collections veja aqui;
http://www.xylax.net/hibernate/

cv1

primitive-array é só pra arrays de primitivos, como o próprio nome diz… serve apenas para int[], char[], e por aí vai :slight_smile:

Mas, afinal, pq usando <array> nao deu certo?

Rodrigo_Carvalho_Aul

O problema do NullPointerException acho que tem a ver com isso que achei no FAQ do Hibernate:

Quanto ao erro usando <array>, o erro foi o seguinte:

javax.servlet.ServletException: Another object was associated with this id (the object with the given id was already loaded): [Email#0]

O mapeamento tá assim:

<hibernate-mapping>
	<class name="Empresa" table="Empresas">
		<id name="id" type="int" unsaved-value="null" />
		<property name="razaoSocial"/>
		<property name="cnpj"/>
		<property name="inscricaoEstadual"/>
		<property name="inscricaoMunicipal"/>
		<property name="site"/>
		<array name="emails" table="EmpresasEmails" cascade="all">
			<key column="Empresa"/>
			<index column="id"/>
			<many-to-many column="Email" class="Email"/>
		</array>
	</class>
</hibernate-mapping>

Mas pra ser sincero, não sei pra que serve essa tag <index column/>, e sem ela dá o erro de java.lang.NullPointerException quando tento abrir a sessão do Hibernate.

sessionFactory = new Configuration().configure().buildSessionFactory();

O erro completo nesse caso é:

java.lang.NullPointerException
	at net.sf.hibernate.cfg.Binder.getTypeFromXML(Binder.java:762)
	at net.sf.hibernate.cfg.Binder.bindValue(Binder.java:348)
	at net.sf.hibernate.cfg.Binder.bindIntegerValue(Binder.java:489)
	at net.sf.hibernate.cfg.Binder.bindListSecondPass(Binder.java:919)
	at net.sf.hibernate.cfg.Binder$ListSecondPass.secondPass(Binder.java:1178)
	at net.sf.hibernate.cfg.Binder$SecondPass.doSecondPass(Binder.java:1116)
	at net.sf.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:495)
	at net.sf.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:614)

[]'s

cv1

O problema aqui é que vc está definindo o id “id” duas vezes - uma no objeto Empresa, e outra no array emails. Use um outro nome (sei lah, emails_id) que esse erro deve sumir :wink:

Rodrigo_Carvalho_Aul

Acho que não é isso não: mudei a classe e o mapeamento e continua dando o mesmo erro:

<class name="Empresa" table="Empresas">
		<id name="id_empresa" type="int" unsaved-value="null" />
		<property name="razaoSocial"/>
		<property name="cnpj"/>
		<property name="inscricaoEstadual"/>
		<property name="inscricaoMunicipal"/>
		<property name="site"/>
		<array name="emails" table="EmpresasEmails" cascade="all">
			<key column="Empresa"/>
			<index column="id_emails"/>
			<many-to-many column="Email" class="Email"/>
		</array>
	</class>

Mas alguém sabe pra serve a tag <index column> ?

maxguzenski

“cv”:
“maxguzenski”:
aconcelho profundamente, voce redefenir os metodos “public int hashCode()” e “public boolean equals(Object o)”
para maior performace.

Cuidado com isso… redefinir equals() e hashCode() nao garante ganhos de performance, e pode levar a bugs sérios se vc não souber direito o que tá fazendo, ainda mais quando vc está trabalhando com Sets, que dependem desses métodos pra fazer a classificação dos objetos ;)

o problema de voce deixar o equals e hashCode da classe Object, é que o hashCode retorna a posicao de memoria, e equals faz um simples " == "

o quer quer dizer, voce nao teste se a classe é equivalentemente iguais, apenas testa se sao a MESMA classe, logo classe com valores iguais vao entrar no Set sem problemas (o que pelo certo, nao devia), e varios metos de comparacao de objetos da classe Set deixam de funcionar.

http://hibernate.bluemars.net/109.html

Criado 6 de agosto de 2003
Ultima resposta 6 de ago. de 2003
Respostas 12
Participantes 4