[RESOLVIDO]Mapeamento JPA - Como mapear uma PK que é FK ao mesmo tempo

Fala galera, andei pesquisando mais não encontrei solução.

A minha dúvida é o seguinte, tenho 2 tabelas, empresa e usuario, porém na tabela empresa minha pk é o codigo_usuario que vem da tabela usuario, ou seja uma fk, no mysql consegui fazer isso sem problemas, mas quando crio a entidade ele me fala que não existe identificador na tabela empresa.

Alguém já passou por isso ou chuta alguma solução?

Abraço.

No caso sua pk vai ser o objeto da tabela que tem a relação, vai usar um embeddableId, veja:

http://docs.oracle.com/cd/B32110_01/web.1013/b28221/cmp30cfg001.htm

[]s

Cara, desculpe a ignorância, mas sempre utilizei embeddableId para chave composta, não entendi como vai funcionar para pk/fk.

Pode dar um exemplo de como ficaria.

Obrigado.

Se eu entendi bem, você tem um campo codigo_usuario na tabela empresa que referencia o campo codigo_usuario da tabela usuario (fk). Neste caso, tente assim:

@Entity
public class Empresa {
    @Id
    @Column(name = "codigo_usuario")
    private Integer codigo;
    @PrimaryKeyJoinColumn //ligando as tabelas pela pk
    @OneToOne //ou outro mapamento
    private Usuario;
}

Nesse caso sua tabela empresa tem uma coluna chamada codigo_usuario que referencia o codigo_usuario da tabela Usuario. O mapeamento @OneToOne serve apenas para poder carregar o usuario da empresa

Falou.

Wagner,

Eu até cheguei a fazer isso , mas minha dúvida é na tabela empresa, pois quando eu subo o JBOSS aparece um erro dizendo que não exite ID para tabela empresa.

Se não tem que aparecer esse erro, como ficaria a tabela empresa?

Abraço!

Para o mapeamento que eu falei, basta a tabela empresa ter um campo chamado codigo_usuario, uma restrição de PK e uma foreign key apontando pra tabela usuario.

Bota os campos relevantes das tuas tabelas aí pra gente ver como deve ficar. :smiley:

Wagner, coloquei assim:

[code]@Entity
@Table(name = “empresa”)
public class Empresa {

@Id
@Column(name = "codigo_usuario")
private Integer codigo;

@PrimaryKeyJoinColumn
@OneToOne(mappedBy = "empresa")
private Usuario usuario;[/code]

[code]@Entity
@Table(name = “cadastro_usuario”)
public class Usuario {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "codigo_usuario")
private Integer codigo;

@OneToOne
private Empresa empresa;[/code]

Porém na hora de inserir ele apresenta a seguinte mensagem:

20:36:45,812 WARN [org.hibernate.util.JDBCExceptionReporter] SQL Error: 1054, SQLState: 42S22
20:36:45,812 ERROR [org.hibernate.util.JDBCExceptionReporter] Unknown column ‘empresa_codigo_usuario’ in 'field list’
20:36:45,812 INFO [STDOUT] org.hibernate.exception.SQLGrammarException: could not insert: [com.leilaopecuario.entidades.Usuario]

Tenta algo assim:

@Entity
@Table(name = "empresa")
public class Empresa {

	@Id
	@Column(name = "codigo_usuario")
	private Integer codigo;

	@PrimaryKeyJoinColumn
	@OneToOne
	private Usuario usuario;
@Entity
@Table(name = "cadastro_usuario")
public class Usuario {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "codigo_usuario")
	private Integer codigo;

	@PrimaryKeyJoinColumn
	@OneToOne
	private Empresa empresa;

Wagner,

o problema agora ta sendo na persistencia, ta dizendo que a empresa está transiente, o que é verdade, porem era pra gerar o mesmo código de usuário que gera pra entidade usuário.

Tem alguma ideia como resolver?

Agradeço desde já.

object references an unsaved transient instance - save the transient instance before flushing: com.leilaopecuario.entidades.Usuario.empresa -> com.leilaopecuario.entidades.Empresa

Eu fiz um exemplo e percebi o problema. Consegui resolver desta maneira:

@Entity
@Table(name = "usuarios")
public class Usuario {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "codigo_usuario")
	private Integer codigo;

	@OneToOne(cascade=CascadeType.ALL)
	@PrimaryKeyJoinColumn
	private Empresa empresa;
}

@Entity
@Table(name = "empresas")
public class Empresa {

	@Id
	@Column(name = "codigo_usuario")
	@GeneratedValue(generator = "foreign")
	@GenericGenerator(name = "foreign", strategy = "foreign", parameters = { @Parameter(name = "property", value = "usuario") })
	private Integer codigo;

	@OneToOne(mappedBy="empresa")
	private Usuario usuario;
}

class Teste {

        @Test
	public void shouldPersistUsuarioWithEmpresa() {
		Usuario u1 = new Usuario();
		u1.setDescricao("theUser");
				
		Empresa e1 = new Empresa();
		e1.setDescricao("theCompany");
		
		u1.setEmpresa(e1);
		e1.setUsuario(u1);
		
		Session currentSession = sessionFactory.getCurrentSession();
		Transaction transaction = currentSession.beginTransaction();
		
		currentSession.save(u1);
		transaction.commit();
	}
}

Deu certinho aqui, vê aí como ficou. Agora, este mapeamento é estranho… hehe, eu criaria uma fk se pudesse, mas sei que as vezes não dá pra mexer no banco

Wagner,

Fiz exatamente isso, mas ta dando o seguinte erro:

null id generated for:class com.leilaopecuario.entidades.Empresa

Eu posso mexer no banco sim, mas queria usar uma pk/fk para forçar o usuário ter só um endereço, assim não tendo que criar uma chave na tabela endereço.

não entendi essa parte

Pode explicar? Presumo que é para gerar a chave de acordo com a chave da tabela usuário é isso?

segue meu código:

[code]@Entity
@Table(name = “cadastro_usuario”)
public class Usuario {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "codigo_usuario")
private Integer codigo;

@PrimaryKeyJoinColumn
@OneToOne(cascade=CascadeType.ALL)
private Empresa empresa;[/code]

[code]@Entity
@Table(name = “cadastro_empresa”)
public class Empresa {

@Id
@Column(name = "empresa_codigo_usuario")
@GeneratedValue(generator = "foreign")
@GenericGenerator(name = "foreign", strategy = "foreign", parameters = { @Parameter(name = "property", value = "usuario") })
private Integer codigoUsuario;

@PrimaryKeyJoinColumn
@OneToOne(mappedBy = "empresa")
private Usuario usuario;[/code]

desde já, agradeço!

Só pra checar, você associou a entidade ao usuário e o usuário à entidade? Assim:

Usuario u1 = new Usuario();
u1.setDescricao("theUser");

Empresa e1 = new Empresa();
e1.setDescricao("theCompany");

u1.setEmpresa(e1); // setando usuario da empresa
e1.setUsuario(u1); // e empresa do usuario

Veja se isso resolve, eu tb tive algum problema assim e era isso que faltava…

O GenericGenerator no caso é pra isso mesmo. No parâmetro nós especificamos que o id virá da propriedade usuario. Eu acredito que tenha até mais possibilidades, definir geradores customizados e coisas do gênero, mas confesso que aí já não entendo mais… hehe

Estranho , está exatamente igual porém continuo recebendo o erro.

Você pode mostrar como estão suas tabelas do banco?

Que raiva, to quase desistindo e colocando um id na tabela empresa…

Tabela usuarios
codigo_usuario (PK)

Tabela empresas
codigo_usuario (PK)
FK codigo_usuario para usuarios.codigo_usuario

hibernate_sequence pra gerar os ids de codigo_usuario.

Bom, tentei mudar o banco e nada, você pode copiar e colar o comando para gerar o banco a partir das Entity’s?

Fazendo assim não tem como eu errar.

Acredito que é a última vez que peço ajuda, desculpa ai…

Abraço!

Opa… segue a parte relevante do dump (tirei apenas esquema de permissões e coisas assim):

CREATE TABLE empresas (
    codigo_usuario integer NOT NULL,
    descricao text
);

CREATE SEQUENCE hibernate_sequence
    START WITH 1
    INCREMENT BY 1
    NO MAXVALUE
    NO MINVALUE
    CACHE 1;

CREATE TABLE usuarios (
    codigo_usuario integer NOT NULL,
    descricao text
);

ALTER TABLE ONLY empresas
    ADD CONSTRAINT empresas_pkey PRIMARY KEY (codigo_usuario);

ALTER TABLE ONLY usuarios
    ADD CONSTRAINT usuarios_pkey PRIMARY KEY (codigo_usuario);

ALTER TABLE ONLY empresas
    ADD CONSTRAINT empresas_codigo_usuario_fkey FOREIGN KEY (codigo_usuario) REFERENCES usuarios(codigo_usuario);

Falou!

Wagner, gerei o banco novamente, e verifiquei cada anotation para ver como ele gerava a FK.

Fiz uns testes e funcionou aqui, muito obrigado pela ajuda, caso precise espero poder ajudar um dia também.

Abraço!

Bacana, que bom que conseguiu!