Prevenir criacao de chave estrangeira @OneToOne

8 respostas
boneazul

E ai pessoal tudo bom ??

Estou com o seguinte problema tenho uma tabela que tem uma referencia para ela mesma com a anotação @OneToOne so que ela nao é obrigatoria , ou seja nao pode haver verificação de integridade no banco mas o problema é que o hibernate sempre gera essa constraint pra mim , tenho como falar pra ele apenas mapear sem que crie a constraint ??

.
.

 @Entity
 @Table(name="UNIDADE"))
 public class Unidade {

		 @Id
		 @GeneratedValue
		 @Column(name="UNI_ID")
		 private Long id;

		 @Column(name="LOG_ATIVO")
		 private char ativo='S';

		 @Column(name="UNI_NOME")
		 private String nome;
		 
		 @OneToOne(fetch=FetchType.LAZY)
		 @JoinColumn(name="DES_ID")
		 @ForeignKey(name="DESTINATARIO_UNIDADE")
		 private Destinatario destinatario;
		 
		 @OneToOne(fetch=FetchType.LAZY)
		 @JoinColumn(name="UNI_UNIDADEPAI")
		 @ForeignKey(name="UNIDADE_UNIDADE")
		 private Unidade unidadepai;
		 
		 @Column(name="UNI_ENDCOMPLEMENTO")
		 @Lob
		 private String endereco;
		 
                 //Aqui eu não quero que ele crie a constraint pois essa coluna pode ser null
		 @OneToOne(fetch=FetchType.LAZY)
		 @JoinColumn(name="UNI_IDREFERENCIA")
		 private Unidade unidadereferencia;
		 
                 //Aqui eu não quero que ele crie a constraint pois essa coluna pode ser null
		 @OneToOne(fetch=FetchType.LAZY)
		 @JoinColumn(name="DES_IDREFERENCIA")
		 private Destinatario destinatarioreferencia;
		 
		 @Column(name="UNI_LIBERADA")
		 private char liberada='N';

		 public void setId(Long id){
			 this.id=id;
		 }

		 public Long getId(){
			 return this.id;
		 }

		 public void setAtivo(char ativo){
			 this.ativo=ativo;
		 }

		 public char getAtivo(){
			 return this.ativo;
		 }

		 public void setNome(String nome){
			 this.nome=nome;
		 }

		 public String getNome(){
			 return this.nome;
		 }

		public void setEndereco(String endereco) {
			this.endereco = endereco;
		}

		public String getEndereco() {
			return endereco;
		}

		public void setDestinatario(Destinatario destinatario) {
			this.destinatario = destinatario;
		}

		public Destinatario getDestinatario() {
			return destinatario;
		}

		public void setUnidadepai(Unidade unidadepai) {
			this.unidadepai = unidadepai;
		}

		public Unidade getUnidadepai() {
			return unidadepai;
		}

		public void setUnidadereferencia(Unidade unidadereferencia) {
			this.unidadereferencia = unidadereferencia;
		}

		public Unidade getUnidadereferencia() {
			return unidadereferencia;
		}

		public void setDestinatarioreferencia(Destinatario destinatarioreferencia) {
			this.destinatarioreferencia = destinatarioreferencia;
		}

		public Destinatario getDestinatarioreferencia() {
			return destinatarioreferencia;
		}

		public void setLiberada(char liberada) {
			this.liberada = liberada;
		}

		public char getLiberada() {
			return liberada;
		}

 }

Basicamente queria saber como mapear @OneToOne sem que ele crie uma chave estrangeira ?? Alguem dá uma luz ?? Procurei na documentação isso e não encontrei…

8 Respostas

L

Eu mapeio assim e não tenho problemas.

class Menu {
...
@ManyToOne(optional = true, fetch = FetchType.LAZY)
@JoinColumn(name = "ID_MENU_PAI", referencedColumnName = "ID_MENU", nullable = true)
private Menu				menuPai;

@OneToMany(mappedBy = "menuPai", cascade = { CascadeType.REMOVE }, fetch = FetchType.LAZY)
private Set<Menu>			subMenus;
...
}

Edit: note que não uso o cascade, se tivesse usando cascade e o menuPai tivesse não nulo o mesmo seria salvo/atualizado.

boneazul
lsjunior:
Eu mapeio assim e não tenho problemas.
class Menu {
...
@ManyToOne(optional = true, fetch = FetchType.LAZY)
@JoinColumn(name = "ID_MENU_PAI", referencedColumnName = "ID_MENU", nullable = true)
private Menu				menuPai;

@OneToMany(mappedBy = "menuPai", cascade = { CascadeType.REMOVE }, fetch = FetchType.LAZY)
private Set<Menu>			subMenus;
...
}

Edit: note que não uso o cascade, se tivesse usando cascade e o menuPai tivesse não nulo o mesmo seria salvo/atualizado.

@OneToOne(fetch=FetchType.LAZY,optional=true)
		 @JoinColumn(name="UNI_IDREFERENCIA",referencedColumnName="UNI_ID",nullable = true)
		 private Unidade unidadereferencia;
		 
		 @OneToOne(fetch=FetchType.LAZY,optional=true)
		 @JoinColumn(name="DES_IDREFERENCIA",referencedColumnName="DES_ID",nullable = true)
		 private Destinatario destinatarioreferencia;

fiz do seu modo mas mesmo assim ele continua gerando o sql;

alter table UNIDADE add constraint FK19B0468E959902AC foreign key (DES_IDREFERENCIA) references DESTINATARIO;
alter table UNIDADE add constraint FK19B0468E8A6053C9 foreign key (UNI_IDREFERENCIA) references UNIDADE;

estou usando o hibernate 3.5.2 ...ser bug isso e ele esta ignorando akeles optional??

L

Agora que vc postou no texto eu entendi. O Hibernate está criando a chave estrangeira.

A criação da chave estrangeira está correta, só que a coluna não é obrigatoria, podendo ter seu valor nulo.

Verifica apenas se está podendo ter valores nulos, por que sempre que adicionar um relacionamento uma foreign key será criada, a menos que mapeie manualmente.

boneazul

lsjunior:
Agora que vc postou no texto eu entendi. O Hibernate está criando a chave estrangeira.

A criação da chave estrangeira está correta, só que a coluna não é obrigatoria, podendo ter seu valor nulo.

Verifica apenas se está podendo ter valores nulos, por que sempre que adicionar um relacionamento uma foreign key será criada, a menos que mapeie manualmente.

Entao essas colunas podem ou nao receber o null,so que quando receber um valor nao precise verificar a constraint pq é integracao de dois bancos diferentes entao eu nao garanto que os ids serão iguais e fico tomando erro

ORA-02291: restrição de integridade (GESTAOCONTRATO.FK19B0468E8A6053C9) violada - chave mãe não localizada

e fico tomando esse erro…se eu falar pra ele nao criar essas constraint ou evitar akeles sql de alter table meu banco na vai retornar essa restricao de integridade e resolveria meu problema…

como é esse mapeamento manual???ou alguma outra sugestão ??

L

Se vc não puder garantir que os IDs na coluna da foreign key são validos vai haver erro de todo jeito no momento que for recuperar o objeto.

Então o correto é armazenar apenas o valor e não fazer o relacionamento. No seu caso aqueles dois campos seriam mapeados como o tipo do ID deles.

boneazul

lsjunior:
Se vc não puder garantir que os IDs na coluna da foreign key são validos vai haver erro de todo jeito no momento que for recuperar o objeto.

Então o correto é armazenar apenas o valor e não fazer o relacionamento. No seu caso aqueles dois campos seriam mapeados como o tipo do ID deles.

Entendi entao voce diz de mapear como Long os dois por exemplo??

L

É o jeito, por que o hibernate da erro quando não encontra o valor mapeado, algo do tipo ‘linha não encontrada com o identificador 1’.

Nas situações onde houver a necessidade de exibir esses valores como objetos mesmo vc pode usar uma classe auxiliar que estende a classe original, ou até ela mesmo desde que anotada como @Transient, para armazenar essas referências, que devem ser recuperadas separadamente. Tem outras formas de fazer, um pouco mais complicadas, para colocar essa referência na classe desejada. Uma forma é usar ‘new’ dentro do SQL do hibernate. Não sei se pra vc atenderia.

boneazul

lsjunior:
É o jeito, por que o hibernate da erro quando não encontra o valor mapeado, algo do tipo ‘linha não encontrada com o identificador 1’.

Nas situações onde houver a necessidade de exibir esses valores como objetos mesmo vc pode usar uma classe auxiliar que estende a classe original, ou até ela mesmo desde que anotada como @Transient, para armazenar essas referências, que devem ser recuperadas separadamente. Tem outras formas de fazer, um pouco mais complicadas, para colocar essa referência na classe desejada. Uma forma é usar ‘new’ dentro do SQL do hibernate. Não sei se pra vc atenderia.

O correto seria mapear como entidade mesmo anotando com @Transient e na recuperacao fazer os sets ?? Nao tem como informar isso automatico tem ?? Vamos supor que nao use hql pra poder utilizar o ‘select new … from’…

Se tem algum trecho de código usando um @Transient usando uma classe e uma mapeamento disso ??

seria algo do tipo né

@Column(name="UNI_IDREFERENCIA")
private Long unidadereferencia;

@Transient
private Unidade unidadeRef;

como seria o mapeamento disso … voce saberia dizer??

Criado 22 de outubro de 2010
Ultima resposta 22 de out. de 2010
Respostas 8
Participantes 2