Mapeamento one-to-one com pk-fk - socorro!

9 respostas
K

Amigos, me ajudem...

Fiz tudo direitinho, olha aí...

No meu banco de dados eu criei:
CREATE TABLE tablea(
  id integer NOT NULL DEFAULT nextval('tablea_seq'::regclass),
  CONSTRAINT tablea_pkey PRIMARY KEY (id)
)
CREATE TABLE tableb(
  id integer NOT NULL,
  CONSTRAINT tableb_pkey PRIMARY KEY (id),
  CONSTRAINT tableb_fkey FOREIGN KEY (id)
      REFERENCES tablea (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
No meu código criei as duas tabelas (TableA e TableB):
@Entity (name="TableA")
@SequenceGenerator(name = "tablea_seq", sequenceName = "tablea_seq")
@Table (schema="public", name="tablea")
public class TableA {

	@Id
	@GeneratedValue(
		strategy = GenerationType.AUTO, 
		generator = "tablea_seq"
	)
	@Column (name="id")
	private Integer id;

	@OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)  
	@PrimaryKeyJoinColumn
	private TableB tableB;
	
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public TableB getTableB() {
		return tableB;
	}
	public void setTableB(TableB tableB) {
		this.tableB = tableB;
	}
	
}
@Entity (name="TableB")
@Table (schema="public", name="tableb")
public class TableB {

	@GenericGenerator(name = "gerador", strategy = "foreign", 
		parameters = @Parameter(name = "property", value = "tableA"))
	@Id
    @GeneratedValue(generator = "gerador")   
    @Column(name = "id")
	private Integer id;
	
	@OneToOne(mappedBy = "tableB", fetch = FetchType.LAZY)
	private TableA tableA;

	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public TableA getTableA() {
		return tableA;
	}
	public void setTableA(TableA tableA) {
		this.tableA = tableA;
	}
	
}
...e o teste:
TableA tableA = new TableA();		
TableB tableB = new TableB();
tableA.setTableB(tableB);
tableB.setTableA(tableA);		
dao.incluir(tableA);
...e tudo o que tenho é a exceção abaixo:
01:12:47,890 ERROR JDBCExceptionReporter:234 - ERROR: insert or update on table "tableb" violates foreign key constraint "tableb_fkey"
  Detail: Key (id)=(5) is not present in table "tablea".

Então, está gerando a sequencia (como vê acima = 5), mas parece estar violando a foreignkey da TableB. Detalhe: as duas tabelas estão em branco (sem registros). A cada nova tentativa é gerado uma sequencia, mas sem sucesso na inclusão dos registros. Dá a entender que primeiro tem de gravar na tableA, para depois gravar na tableB, mas não está ocorrendo...

Me ajudem aí, estou no sufoco com isto, precisando resolver. Passei o dia pesquisando isto e a única solução que existe é esta, mas não está funcionando...

Obrigado a todos.

9 Respostas

T

você ja tento no lugar do @PrimaryKey usa @JoinColumn(name=“tabelaA”) ?

M

Violação do chava por conta disso aki:

@OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL) @PrimaryKeyJoinColumn private TableB tableB;

O

Eu faço assim:

public class Pessoa{

  private Long idPessoa;
  private Sogra sogra;

  @Id
  @Column(name="IDPESSOA");
  public Long getIdPessoa(){
        return idPessoa;
  }

   
  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name="IDSOGRA" )
  @ForeignKey (name="FK_PESSOA_SOGRA")  
  public Sogra getSogra(){
      return sogra;
  }

}

Isso deve resolver. Posso estar esquecendo algum atributo, mas daí você dá uma lida na documentação do hibernate annotatios

K

Sim, tentei assim em TableA:

@OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL) @JoinColumn(name="tableA") private TableB tableB;
…e o resultado é o mesmo:

13:41:38,617 ERROR JDBCExceptionReporter:234 - ERROR: insert or update on table "tableb" violates foreign key constraint "tableb_fkey" Detail: Key (id)=(9) is not present in table "tablea".

<blockquote>Violação do chava por conta disso aki:

@OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)

@PrimaryKeyJoinColumn

private TableB tableB;</blockquote>

Retirei isto “@PrimaryKeyJoinColumn” e o resultado foi:

13:46:25,904 ERROR JDBCExceptionReporter:234 - ERROR: insert or update on table "tableb" violates foreign key constraint "tableb_fkey" Detail: Key (id)=(10) is not present in table "tablea".

Quanto a observação do odd.silva, só é válida quando as tabelas possuem o relacionamento assim:

<pk> ------<fk><uk>

Neste caso funciona perfeitamente, no entanto estou tentando do jeito correto (pk —> pk-fk), e não estou obtendo sucesso.

Segundo a documentação, o correto é fazer exatamente do jeito que eu fiz. Será que é algum bug?
Detalhe:
Quando eu recupero a tableA que já existe no banco, aí a tableB é inserida e não ocorre exception. No entanto, se eu tentar inserir somente a tableA, mesmo colocando optional=true no relacionamento de ambos, ocorre esta exception:

13:53:22,014 ERROR HibernateConvertException:37 - THROWABLE -->javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: br.eti.amazu.appblank.domain.TableA.tableB

Ou seja: para persisir TableA a TableB não pode ser nula.

Alguém aí tem novas idéias?
Alguém já tentou onoToOne com pk —> pk-fk?

Me parece um bug em JPA…

Obrigado, e continuo aguardando novas idéias de alguém que já tenha feito isto.

T

apaga seu banco e pedi pro jpa cria as tabelas pra vc, eu fiz do jeito que falei acima pra você e funciono, nunca tive problemas.

K

OK, tentei ao invés de "@JoinColumn(name="tableA")", coloquei @JoinColumn(name="id").
Resultado:
Parabéns tiago e Mr.style, ambos estão corretos!
parabéns também ao oddy.silva. A sua colocação para a TableA também está correta. (lembrando que o join não é com o objeto "tableA" mas sim com o "id" da coluna tableA).
FUNCIONOU - - PROBLEMA RESOLVIDO.

Abaixo vai o código completo e corrigido:
@Entity (name="TableA")
@SequenceGenerator(name = "tablea_seq", sequenceName = "tablea_seq")
@Table (schema="public", name="tablea")
public class TableA {

	@Id
	@GeneratedValue(
		strategy = GenerationType.AUTO, 
		generator = "tablea_seq"
	)
	@Column (name="id")
	private Integer id;

	@OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)  
	@JoinColumn(name="id")
	private TableB tableB;
	
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public TableB getTableB() {
		return tableB;
	}
	public void setTableB(TableB tableB) {
		this.tableB = tableB;
	}
	
}
@Entity (name="TableB")
@Table (schema="public", name="tableb")
public class TableB {

	@GenericGenerator(name = "gerador", strategy = "foreign", 
		parameters = @Parameter(name = "property", value = "tableA"))
	@Id
    @GeneratedValue(generator = "gerador")   
    @Column(name = "id")
	private Integer id;
	
	@OneToOne(mappedBy = "tableB", fetch = FetchType.LAZY)
	private TableA tableA;

	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public TableA getTableA() {
		return tableA;
	}
	public void setTableA(TableA tableA) {
		this.tableA = tableA;
	}
	
}
O

É nóis. :smiley:

K

Pessoal, desculpe ressuscitar o tópico, mas me deparei com um problema estranho.
o relacionamento funciona somente quando tento inserir tableA e tableB concomitantemente.
Caso eu jah tenha o registro em tableA e tento persistir a tableB, simplesmente não ocorre nada (o cosole printa a sql insert em tableB - tem-se a impressão de haver o insert em tableB), mas quando vou olhar a tabela, o registro não eh inserido… estranho.

TableA tableA = dao.recuperar(nrRegistro); //recupera a tableA, deixando-a gerenciada. TableB tableB = new TableB(); tableB.setTableA(tableA); tableA.setTableB(tableB); dao.persist(tableB);
E aí, onde estou errando? (lembrando que o mapeamento eh ---->
Desde já agradeço a todos.

K

Simplesmente retirei do spring a configuração abaixo e tudo voltou a funcionar direito:

<prop key="hibernate.connection.release_mode">auto</prop>

Mas afinal, então naum entendi direito para que isto serve!!!
Obrigado a todos.

Criado 22 de março de 2011
Ultima resposta 22 de mai. de 2011
Respostas 9
Participantes 4