Foreing Key não está sendo atribuida automaticamente (RESOLVIDO)

2 respostas
rafaelbrizola

Salve galera,
Tenho 2 tabelas: Pessoa e Login e a relação entre elas é 1 para 1.

Tabela Pessoa
ID_PESSOA
… (outros campos)

Tabela Login
ID_LOGIN (primary key)
ID_PESSOA (foreign key para a Tabela PESSOA)
… (outros campos)

As classes estão mapeadas assim:
PESSOA

@Entity
@Table(name = "TB_PESSOA")
public class Pessoa implements Serializable{
    
    @Id
    @SequenceGenerator(name = "TB_PESSOA_ID_PESSOA_SEQ", sequenceName = "TB_PESSOA_ID_PESSOA_SEQ", allocationSize = 1)
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="TB_PESSOA_ID_PESSOA_SEQ")
    @Column(name = "ID_PESSOA", columnDefinition="number")
    private Long niPessoa;
    
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="ID_PESSOA")
    private Login login;
    
    //Getters and Setters
    ....

LOGIN

@Entity
@Table(name = "TB_LOGIN")
public class Login implements Serializable {

    @Id
    @SequenceGenerator(name = "TB_LOGIN_ID_LOGIN_SEQ", sequenceName = "TB_LOGIN_ID_LOGIN_SEQ", allocationSize = 1)
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="TB_LOGIN_ID_LOGIN_SEQ")
    @Column(name = "ID_LOGIN", columnDefinition="number")
    private Long idLogin;

    @GenericGenerator(name = "foreignLogin", strategy = "foreign", parameters = {
        @Parameter(name = "property", value = "pessoa")
    })
    @Column(name = "ID_PESSOA", columnDefinition = "number")
    private Long niPessoa;

    @OneToOne(mappedBy="login")
    private Pessoa pessoa;

    // Getters and Setters
    ...

Antes de salvar a entidade PESSOA, eu seto a pessoa dentro de login:

...
login.setPessoa(pessoa);
...

Mas quando tento salvar a entidade pessoa (e o login que é um atributo desta classe e deveria ser salvo junto) ocorre o seguinte erro:

cannot insert NULL into ("CADBETA"."TB_LOGIN"."ID_PESSOA")

No log dá pra ver que a entidade pessoa está sendo salva corretamente, o id do login está sendo gerado através da sequence, mas o id da pessoa não está sendo copiado para o campo niPessoa de login.

Alguém sabe oq está faltando?
Valeu!

2 Respostas

rafaelbrizola

Olhando o código fonte do Hibernate, me parece que os Generators só são tratados quando o campo tem a anotação @Id ou @EmbeddedId, conforme código abaixo: (Extraido do link http://www.docjar.com/html/api/org/hibernate/cfg/AnnotationBinder.java.html)

if ( !entityBinder.isIgnoreIdAnnotations() &&
    ( property.isAnnotationPresent( Id.class )
    || property.isAnnotationPresent( EmbeddedId.class ) ) ) {
        if ( isIdentifierMapper ) {
            throw new AnnotationException(
                "@IdClass class should not have @Id nor @EmbeddedId properties"
            );
        }
        log.debug( inferredData.getPropertyName() + " is an id" );
        //clone classGenerator and override with local values
        HashMap<String, IdGenerator> localGenerators = (HashMap<String, IdGenerator>) classGenerators.clone();
        localGenerators.putAll( buildLocalGenerators( property, mappings ) );
        ........

Alguém sabe se é assim mesmo? E se for, será que tem outro jeito pra fazer??

rafaelbrizola

Galera, descobri oq era. Eu estava mapeando a classe do jeito errado.
Eu tenho que por o @OneToOne e @JoinColumn em Login, não em Pessoa.
Segue abaixo como ficou:

PESSOA

@Entity
@Table(name = "TB_PESSOA")
public class Pessoa implements Serializable{
    
    @Id
    @SequenceGenerator(name = "TB_PESSOA_ID_PESSOA_SEQ", sequenceName = "TB_PESSOA_ID_PESSOA_SEQ", allocationSize = 1)
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="TB_PESSOA_ID_PESSOA_SEQ")
    @Column(name = "ID_PESSOA", columnDefinition="number")
    private Long niPessoa;
    
    @OneToOne(mappedBy="pessoa", cascade = CascadeType.ALL)
    private Login login;

    ....

LOGIN

@Entity
@Table(name = "TB_LOGIN")
public class Login implements Serializable {

    @Id
    @SequenceGenerator(name = "TB_LOGIN_ID_LOGIN_SEQ", sequenceName = "TB_LOGIN_ID_LOGIN_SEQ", allocationSize = 1)
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="TB_LOGIN_ID_LOGIN_SEQ")
    @Column(name = "ID_LOGIN", columnDefinition="number")
    private Long idLogin;

    @OneToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="ID_PESSOA")
    private Pessoa pessoa;

    ....

Dessa maneira eu nem preciso criar o campo niPessoa em login, pois posso recurperar direto do atributo pessoa.
Bom, se alguém tiver esse problema, tae :smiley:
[]'S

Criado 3 de dezembro de 2008
Ultima resposta 3 de dez. de 2008
Respostas 2
Participantes 1