JPA Mapear fk tipo String

26 respostas
gRoOve

Olá galera, como eu faço pra mapear um campo do tipo String que irá referenciar outra tabela(FK)?
No caso a tabela referenciada teria que ficar como? Tenho que mapear o campo que eu quero referenciar como @Id correto?

26 Respostas

Rodrigo_Sasaki

se não me engano tem que usar o @JoinColumn também

@Id
    @JoinColumn(name = "COLUNA_MINHA_TABELA", referencedColumnName = "COLUNA_OUTRA_TABELA", nullable = false)
    private String campo;
gRoOve

Não estou sabendo fazer isso, eu tenho as tabelas Usuario e GrupoAcesso, eu preciso que sempre que adicionar um Usuario adicione também um GrupoAcesso e o campo login da tabela GrupoAcesso referencie o campo login da tabela Usuario, da pra fazer isso?
Seguem meus códigos:

package com.modelo.bean;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.JoinColumn;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToOne;

@Entity
public class Usuario implements Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	protected Integer idUsuario;
	protected String login;
	protected String senha;
	@Column(length = 60)
	protected String nome;
	
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "idContato")
	protected Contato contato = new Contato();
	
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "idEndereco")
	protected Endereco endereco = new Endereco();
	
	@OneToOne(cascade = CascadeType.PERSIST)
	protected GrupoAcesso grupoAcesso = new GrupoAcesso();

	public Integer getIdUsuario() {
		return idUsuario;
	}

	public void setIdUsuario(Integer idUsuario) {
		this.idUsuario = idUsuario;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getSenha() {
		return senha;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}

	public String getNome() {
		return nome;
	}

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

	public Contato getContato() {
		return contato;
	}

	public void setContato(Contato contato) {
		this.contato = contato;
	}
	
	public GrupoAcesso getGrupoAcesso() {
		return grupoAcesso;
	}

	public void setGrupoAcesso(GrupoAcesso grupoAcesso) {
		this.grupoAcesso = grupoAcesso;
	}
	

	public Endereco getEndereco() {
		return endereco;
	}

	public void setEndereco(Endereco endereco) {
		this.endereco = endereco;
	}
}
package com.modelo.bean;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

@Entity
public class GrupoAcesso implements Serializable {
	@JoinColumn(name="login", referencedColumnName="login")
	@OneToOne
	private String login = "zezin";
	
	@Id
	private String nomeGrupoAcesso;
	
	public GrupoAcesso(){
		
	}
	
	public String getNomeGrupoAcesso() {
		return nomeGrupoAcesso;
	}

	public void setNomeGrupoAcesso(String nomeGrupoAcesso) {
		this.nomeGrupoAcesso = nomeGrupoAcesso;
	}

}
Rodrigo_Sasaki

Seu @JoinColumn referente ao GrupoAcesso tem que estar na sua entidade usuário

gRoOve

Mas de acordo com a especificação do JAAS eu preciso criar a referência a partir de um campo da tabela de acesso GrupoAcesso para a tabela de Usuario. Como fica agora?
Quem referencia é GrupoAcesso para Usuario "/

Rodrigo_Sasaki

ta… você disse que sempre quando gravar um Usuario, quer que seja gravado um GrupoAcesso… portanto você tem que referenciar na sua entidade Usuario como isso deve ser feito… deve definir a coluna do banco e o CascadeType

@OneToOne(cascade = CascadeType.PERSIST)  
@JoinColumn(name="login", referencedColumnName="login") 
protected GrupoAcesso grupoAcesso = new GrupoAcesso();

se fosse pra gravar um Usuario sempre que um GrupoAcesso fosse gravado (o que não faz sentido), aí sim seria ao contrário

gRoOve

Então é isso mesmp, quando gravar um Usuario tem que gravar um GrupoAcesso, contudo a FK vem do GrupoAcesso pro Usuario sacou?

Rodrigo_Sasaki

então…

na sua tabela Usuario você tem um campo LOGIN que é uma FK referente à tabela GrupoUsuario, certo?

[b]Usuario

idUsuario (PK)
login(varchar)
senha(varchar)
nome(varchar)
idContato (FK)
idEndereco (FK)
idGrupoAcesso (FK)[/b]

ou não é assim?

gRoOve

Não. Na tabela GrupoAcesso tenho uma FK que referencia o campo login do Usuario:

GrupoUsuario
nomeGrupoUsuario(varchar)
login(FK)

Usuario
login(varchar)

Rodrigo_Sasaki

ta… então não vai dar certo hehehe

você não vai conseguir gravar um GrupoAcesso quando gravar o Usuario usando o Cascade se suas tabelas estão modeladas dessa maneira…

porque eu imagino que o Usuario é quem tem que ter a chave do GrupoAcesso ao qual ele pertence, e não o inverso…

gRoOve

Cara, eu fiz do jeito que deveria ser Usuario com FK pro GrupoAcesso e funcionou \o/
Tava viajando nessa, vlw pela ajuda ai :slight_smile:
Abraço!

gRoOve

Só maus uma dúvida, aqui:

package com.modelo.bean;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.JoinColumn;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToOne;

@Entity
public class Usuario implements Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	protected Integer idUsuario;
	protected String login;
	protected String senha;
	@Column(length = 60)
	protected String nome;
	
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "idContato")
	protected Contato contato = new Contato();
	
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "idEndereco")
	protected Endereco endereco = new Endereco();
	
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "login")
	protected GrupoAcesso grupoAcesso = new GrupoAcesso();

	public Integer getIdUsuario() {
		return idUsuario;
	}

	public void setIdUsuario(Integer idUsuario) {
		this.idUsuario = idUsuario;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getSenha() {
		return senha;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}

	public String getNome() {
		return nome;
	}

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

	public Contato getContato() {
		return contato;
	}

	public void setContato(Contato contato) {
		this.contato = contato;
	}
	
	public GrupoAcesso getGrupoAcesso() {
		return grupoAcesso;
	}

	public void setGrupoAcesso(GrupoAcesso grupoAcesso) {
		this.grupoAcesso = grupoAcesso;
	}
	

	public Endereco getEndereco() {
		return endereco;
	}

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

Eu quero usar o campo login como FK tb, tem como? Deste jeito que eu fiz ta dando erro…

Rodrigo_Sasaki

Sem problemas hehehe
essas coisas podem ser confusas mesmo

só altere o seu primeiro post desse tópico e adicione a tag [RESOLVIDO] no título do tópico :slight_smile:

gRoOve

Postei uma última dúvida ai :slight_smile:

Rodrigo_Sasaki

que erro? posta aí

você não precisa dar os news nos atributos daquele jeito…

gRoOve

Ta dizendo que o campo “login” está repetido "/

com.sun.faces.mgbean.ManagedBeanCreationException: Não é possível criar instância para·a classe: com.modelo.managedBean.UsuarioMB.
	at com.sun.faces.mgbean.BeanBuilder.newBeanInstance(BeanBuilder.java:193)
	at com.sun.faces.mgbean.BeanBuilder.build(BeanBuilder.java:102)
	at com.sun.faces.mgbean.BeanManager.createAndPush(BeanManager.java:409)
	at com.sun.faces.mgbean.BeanManager.create(BeanManager.java:269)
	at com.sun.faces.el.ManagedBeanELResolver.resolveBean(ManagedBeanELResolver.java:244)
	at com.sun.faces.el.ManagedBeanELResolver.getValue(ManagedBeanELResolver.java:116)
	at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176)
	at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203)
	at org.apache.el.parser.AstIdentifier.getValue(AstIdentifier.java:69)
	at org.apache.el.parser.AstValue.getValue(AstValue.java:112)
	at org.apache.el.parser.AstNot.getValue(AstNot.java:42)
	at org.apache.el.parser.AstAnd.getValue(AstAnd.java:37)
	at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
	at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
	at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
	at javax.faces.component.UIComponentBase.isRendered(UIComponentBase.java:413)
	at org.primefaces.component.menu.MenuRenderer.encodePlainMenuContent(MenuRenderer.java:118)
	at org.primefaces.component.menu.MenuRenderer.encodePlainSubmenu(MenuRenderer.java:159)
	at org.primefaces.component.menu.MenuRenderer.encodePlainMenuContent(MenuRenderer.java:128)
	at org.primefaces.component.menu.MenuRenderer.encodeMarkup(MenuRenderer.java:100)
	at org.primefaces.component.menu.BaseMenuRenderer.encodeEnd(BaseMenuRenderer.java:40)
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1786)
	at javax.faces.render.Renderer.encodeChildren(Renderer.java:168)
	at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:845)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1779)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1782)
	at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:402)
	at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:125)
	at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:470)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Thread.java:722)
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: TurismoGuiadoPU] Unable to build EntityManagerFactory
	at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:677)
	at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:126)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:51)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:33)
	at com.modelo.dao.UsuarioDAO.<init>(UsuarioDAO.java:18)
	at com.modelo.managedBean.UsuarioMB.<init>(UsuarioMB.java:19)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
	at java.lang.Class.newInstance0(Class.java:372)
	at java.lang.Class.newInstance(Class.java:325)
	at com.sun.faces.mgbean.BeanBuilder.newBeanInstance(BeanBuilder.java:188)
	... 49 more
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.modelo.bean.Usuario column: login (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)
	at org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:696)
	at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:450)
	at org.hibernate.mapping.RootClass.validate(RootClass.java:192)
	at org.hibernate.cfg.Configuration.validate(Configuration.java:1102)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1287)
	at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:859)
	at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:669)
Rodrigo_Sasaki

mostra denovo suas classes Usuarios e GrupoAcesso, pra eu ver como elas estão agora…

gRoOve

Segue ai:

Usuario

package com.modelo.bean;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.JoinColumn;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToOne;

@Entity
public class Usuario implements Serializable {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	protected Integer idUsuario;
	protected String login;
	protected String senha;
	@Column(length = 60)
	protected String nome;
	
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "idContato")
	protected Contato contato;
	
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "idEndereco")
	protected Endereco endereco;
	
	@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "login")
	protected GrupoAcesso grupoAcesso;

	public Integer getIdUsuario() {
		return idUsuario;
	}

	public void setIdUsuario(Integer idUsuario) {
		this.idUsuario = idUsuario;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getSenha() {
		return senha;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}

	public String getNome() {
		return nome;
	}

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

	public Contato getContato() {
		return contato;
	}

	public void setContato(Contato contato) {
		this.contato = contato;
	}
	
	public GrupoAcesso getGrupoAcesso() {
		return grupoAcesso;
	}

	public void setGrupoAcesso(GrupoAcesso grupoAcesso) {
		this.grupoAcesso = grupoAcesso;
	}
	

	public Endereco getEndereco() {
		return endereco;
	}

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

GrupoAcesso

package com.modelo.bean;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

@Entity
public class GrupoAcesso implements Serializable {

	@Id
	private String login;
	private String nomeGrupoAcesso;

	public GrupoAcesso() {
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getNomeGrupoAcesso() {
		return nomeGrupoAcesso;
	}

	public void setNomeGrupoAcesso(String nomeGrupoAcesso) {
		this.nomeGrupoAcesso = nomeGrupoAcesso;
	}
}
Rodrigo_Sasaki

adicione o (insertable = false e updatable = false) na sua anotação @JoinColumn

gRoOve

Ok. Resolveu =))
Estou com outro problema agora "/, tipo a pk da minha tabela GrupoAcesso será o login mesmo, pois ele não pode ser repetido tb, estou anotando ele assim:

@Entity
public class GrupoAcesso implements Serializable {

	@Id
	private String login";
	
	private String nomeGrupoAcesso = "promotor";
	

	public GrupoAcesso() {
	}

	public GrupoAcesso(String login) {
		this.login = login;
	}

ai ocorre este erro:

Erro: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.modelo.bean.GrupoAcesso

Pois bem, como eu vou setar manualmente o campo login?
Tentei passar o atributo pro construtor na hora de instanciar a classe Usuario mas não rolou "/

@OneToOne(cascade = CascadeType.PERSIST)
	@JoinColumn(name = "login", insertable=false, updatable=false)
	protected GrupoAcesso grupoAcesso = new GrupoAcesso(this.login);

Ve alguma saída?

Rodrigo_Sasaki

acho que essa entidade tem que ser pensada melhor… o que seria o login? o login do usuário?

porque se for, acho que não faz sentido…

a tabela deveria ter um id, talvez sequencial, e o nome do Grupo (Administradores, Visitantes, etc…)

gRoOve

Isto, é o nome do usuário mesmo, poderia ser um id mesmo, só pra saber qual o grupo de cada usuário, sacou?

Eu pensei um pouco e resolvi sentado o login do grupoAcesso na hora de salvar no BD, no ManagedBean, assim:

public String salvar() {
		usuario.getGrupoAcesso().setLogin(usuario.getLogin());
		if (usuarioDAO.inserirUsuario(usuario)) {
			return "sucessoOperacao";
		} else {
			return "falhaOperacao";
		}
	}

Você que ficou POG demais isso? Seria interessante deixar como ID em vez de login na tabela GrupoAcesso?

Rodrigo_Sasaki

eu faria diferente…

deixaria só um id e um nome no grupo… e pra saber os usuários do grupo faria algo como

“Select * from Usuario where idGrupo = ?”

mas eu não tenho muita experiência com isso… talvez seja melhor alguma outra pessoa te responder essa hehehe

gRoOve

Concordo plenamente com vc, o que acontece agora é que esbarramos na especficação JAAS, porque ela cruza os logins entre as tabelas, se eu usar o id-grupo na tabela GrupoAcesso vai parar de autenticar dai. Po, me arrependi de ter usado esse JAAS na moral =((

Cara, sabe onde eu consigo uma documentação completa sobre JPA?

Rodrigo_Sasaki

bom… documentação não sei… eu sempre pesquiso as coisas que preciso e acabo encontrando…

agora tem esse post muito bacana do jakefrog que explica as coisas com uma abordagem mais prática…

eu gostei bastante

gRoOve

Já li este tópico, é bom mesmo…mas gostaria de um material de referência, tipo, saber quais propriedades cada mapeamento possui, essas coisas…
Você trabalha com isso ou só estuda?

Rodrigo_Sasaki

é vergonhoso mas tenho que dizer que trabalho heehhe

e realmente não sei tudo o que deveria saber… mas estou me aprimorando também ^^

Criado 20 de abril de 2012
Ultima resposta 20 de abr. de 2012
Respostas 26
Participantes 2