[Resolvido]Mapeamento One to One

8 respostas
J

Galera boa tarde!
Estou com o seguinte problema…

Eu estava Mapeando algumas classes com o relacionamento one to one utilizando annotations do Hibernate… Até ai tudo bem…
Mas quando eu salvo a classe no banco, o campo no qual deveria estar chave da outra tabela do relacionamento está como null… alguém tem idéia do que pode ser?
No banco de dados possuo a tabela pessoa e a tabela endereco, no qual a tabela endereco tem um campo que faz referencia a chave primária de pessoa

Segue minhas classes com a anotação…

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name ="pessoa")
public class Pessoa {
	
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="id")
	private String idPessoa;
	
	@Column(name="nome")
	private String nome;
	
	@Column(name="cpf")
	private String cpf;
	
	@Column(name="sexo")
	private String sexo;
	
	@Temporal(TemporalType.DATE)
	@Column(name="dataNascimento")
	private Date dataNascimento;
	
	@OneToOne(mappedBy="pessoa")
	@Cascade(org.hibernate.annotations.CascadeType.ALL)
	private Endereco endereco;

//Getters e Setters
@Entity
@Table(name="endereco")
public class Endereco {
	
	@Id
	@GeneratedValue
	@Column(name="id")
	private String idEndereco;
	
	@Column(name="logradouro")
	private String logradouro;
	
	@Column(name="bairro")
	private String bairro;
	
	@Column(name="cep")
	private String cep;
	
	@Column(name="cidade")
	private String cidade;
	
	@Column(name="uf")
	private String uf;
	
	@OneToOne
	@JoinColumn(name="pessoa_endereco")
	private Pessoa pessoa;

Utilizei como exemplo o mapeamento utilizado neste topico… http://www.guj.com.br/posts/list/131341.java#707414

Agradeço desde já!

8 Respostas

D

Perguntinhas:

Pq vc usa a anotação @Inheritance em Pessoa?
Pq os ids, tanto de pessoa, quando de endereço são Strings?
A anotação @Table, da forma que você está usando, só tem sentido se vc quiser que a tabela tenha o mesmo nome em qualquer SO. No MySQL, caso a anotação não fosse usada, seria gerada a tabela "pessoa" (letra minúscula) no Windows, enquanto no Linux é com letra maiúscula (Pessoa). E isso faz diferenã no Linux, pq até os nomes das tabelas são case sensitive. Enfim, acho desnecessário o uso da anotação @Table, a não ser que você precise de alguma outra configuração, como definição de campos unique... Enfim...
A entidade pessoa é a dona do relacionamento, certo?
O mappedBy deve ficar a entidade que é usada como parte do relacionamento, e não na dona do relacionamento. O mappedBy serve para vc ter a "volta" do relacionamento.
Se não me engano, o comportamento padrão é já é cascade. Então vc pode tirar a anotação @Cascade.
Pq está usando a anotação @JoinColumn?
Pq define o nome de cada coluna? Deixe que o hibernate já cuida disso p/ vc... Por padrão, o nome da coluna vai ser o mesmo do atributo.

Seguem as entidades corrigidas:

@Entity
// cpf deve ser único. vc tem o id como chave artificial, mas o cpf ainda deve ser único.
@Table( uniqueConstraints ={ @UniqueConstraint( columnNames = "cpf" ) } )
public class Pessoa {
	
	@Id
	@GeneratedValue
	private long id;
	
	private String nome;
	
	private String cpf;
	
	private String sexo;
	
	@Temporal(TemporalType.DATE)
	private Date dataNascimento;
	
	@OneToOne
	@NotNull
	private Endereco endereco;

}

@Entity
public class Endereco {
	
	@Id
	@GeneratedValue
	private long idEndereco;
	
	private String logradouro;
	
	private String bairro;
	
	private String cep;
	
	private String cidade;
	
	private String uf;
	
	@OneToOne(mappedBy="endereco")
	@NotNull
	private Pessoa pessoa;

}

Seria legal vc usar as anotações @Length (definir o tamanho da coluna), @NotNull (coluna não pode ser null) e @NotEmpty (valor não pode ser vazio, ou seja, uma String vazia por exemplo) para melhorar a definição de suas colunas. Já coloquei a @NotNull nos relacionamentos, entretanto não sei se os seus requisitos definem que uma pessoa deve ter obrigatoriamente um endereço. Outra sugestão seria usar um relacionamento ManyToMany entre Pessoa e Endereço, pq uma pessoa pode ter mais de um endereço e um endereço pode ser de mais de uma pessoa, mas mais uma vez, isso depende dos seus requisitos.
Acho que é isso.

[]´s

D

Ah, mais alguns pitacos.
Caso o endereço seja realmente único por pessoa, ou seja, mesmo que Ana e João morem na mesma casa, eles tem endereços cadastrados de forma independente, eu recomendaria que você migrasse os campos da classe endereço para a classe Pessoa. Ai vc não precisaria ter a tabela Endereço, visto que como é 1x1, essa tabela seria desnecessária. Outra sugestão sera converter tanto cidade quanto estado (ambos atributos de enredeço) em entidades. Então Pessoa teria um relacinamento ManyToOne com Cidade, e Cidade, por sua vez, teria um relacionamento ManyToOne com Estado, Várias Pessoas podem morar em uma Cidade, e uma Cidade é de um Estado. Mais uma vez, depende dos seus requisitos. Mesmo que deixe o relacionamento 1x1 entre Pessoa e Endereco, recomendo que você crie as entidades Cidade e Estado.

[]´s

J


Pq vc usa a anotação @Inheritance em Pessoa?
Pq os ids, tanto de pessoa, quando de endereço são Strings?
A anotação @Table, da forma que você está usando, só tem sentido se vc quiser que a tabela tenha o mesmo nome em qualquer SO. No MySQL, caso a anotação não fosse usada, seria gerada a tabela “pessoa” (letra minúscula) no Windows, enquanto no Linux é com letra maiúscula (Pessoa). E isso faz diferenã no Linux, pq até os nomes das tabelas são case sensitive. Enfim, acho desnecessário o uso da anotação @Table, a não ser que você precise de alguma outra configuração, como definição de campos unique… Enfim…
A entidade pessoa é a dona do relacionamento, certo?
O mappedBy deve ficar a entidade que é usada como parte do relacionamento, e não na dona do relacionamento. O mappedBy serve para vc ter a “volta” do relacionamento.
Se não me engano, o comportamento padrão é já é cascade. Então vc pode tirar a anotação @Cascade.
Pq está usando a anotação @JoinColumn?
Pq define o nome de cada coluna? Deixe que o hibernate já cuida disso p/ vc… Por padrão, o nome da coluna vai ser o mesmo do atributo.

Então cara, o @Inheritance eu utilizo porque tenho uma classe (Funcionario) que estende de pessoa. Vendo alguns exemplos vi que foi utilizado desta forma
As outras anotações tabmém foram pegas em exemplos e utilizadas, pois sou iniciante com o Hibernate e estou apanhando um pouco…
Agora sabendo que nçao preciso definir cada nome de coluna, facilita minha vida :slight_smile:

Pensei mesmo em colocar o endereço junto com a pessoa. não fiz porque tinha feito alguns outros sistemas no qual o endereço era separado de pessoa, sendo uma tabela para cada…
Agora criar uma classe para cidade e outra para estados eu nao tinha pensado ainda nao, mas é uma boa de se fazer… vou tentar aqui…

Quanto ao codigo irei testar e respondo logo mais…

No mais, muito obrigado pela resposta
Abraços

D

Legal jhonatam.
Quando à anotação Inheritance, entendi sua proposta.
Em relação à separação do endereço em uma classe, verifique seus requisitos. Se um enderço não puder ser compartilhado entre Pessoas ou Funcionários, simplesmente migre os campos da classe Endereço para Pessoa e pronto.

Na hora que terminar, posta suas entidades p/ eu ver. Recomendo fortemente o uso das entidades para cidade e estado.

[]´s

J

Segue como ficou minhas classes…

@NamedQueries({
	@NamedQuery(name=Funcionario.CONSULTAR_FUNCIONARIOS , query="from Funcionario")
	
})

@Entity 
public class Funcionario extends Pessoa{
	
	public static final String CONSULTAR_FUNCIONARIOS = "consultarFuncionarios";
	
	public Funcionario() {}
	
	private String idFuncionario;
	
	@NotNull
	private String cargo;
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(uniqueConstraints={@UniqueConstraint(columnNames="cpf")})
public class Pessoa {
	
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="id")
	private String idPessoa;
	
	@Length(max=128)
	@NotNull
	private String nome;
	
	@Length(max=11)
	@NotNull
	private String cpf;
	
	@NotNull
	private String sexo;
	
	@Temporal(TemporalType.DATE)
	private Date dataNascimento;
	
	@Length(max=128)
	@NotNull
	private String logradouro;
	
	@Length(max=64)
	@NotNull
	private String bairro;
	
	@Length(max=8)
	@NotNull
	private String cep;
	
	@Length(max=128)
	@NotNull
	private String cidade;
	
	@Length(max=128)
	@NotNull
	private String uf;

Fiz a junção das classes endereco e pessoa, pois como vc tinha falado, não fazia sentido pelo mapeamento one to one. Também coloquei as anotações @Length e @NotNull
As classes cidade e UF comecei a fazer, mas não vou terminar hoje…
Muito Obrigado… Abraços

D

Olá.

Ainda não concordo com os ids em String, ainda mais se forem ser usados “apenas” como chaves artificiais.

[]´s

C

David, desculpe reabrir o tópico, mas ficou a dúvida, se bem que voce falou que depende dos requisitos.
Uma ‘Pessoa’(física ou jurídica) pode ter mais que um endereço e tals. Então é necessária esta normalização. Mas são vários casos.

No cadastro de uma agência bancária, haverá apenas um endereço para esta agência. No caso de um fornecedor, já poderão ter 2 endereços. No caso de um cliente, poderao ter até 3 endereços. Já no caso de um usuário, um endereço. No caso de aluno, 2 endereços. E haverão casos em que nao haverá a necessidade de nenhum endereço.

Neste caso, acredito que deveria ser realmente ManyToOne como voce disse. Na tabela endereço, minha chave primária poderia ser pessoa+tipoEndereco, mas dai recai o pecado de chave composta.

Como proceder neste caso ?

X

Alguem podria mi dizer pra que serve isso:

@NamedQueries({  
    @NamedQuery(name=Funcionario.CONSULTAR_FUNCIONARIOS , query="from Funcionario")  
       
 })
Criado 25 de julho de 2010
Ultima resposta 27 de dez. de 2011
Respostas 8
Participantes 4