Inicial > Programação > A Melhor Forma de Mapear um Relacionamento OneToOne com JPA

A Melhor Forma de Mapear um Relacionamento OneToOne com JPA

Normalmente, em um relacionamento um-para-um anotado com @OneToOne, a entidade principal e a entidade secundária têm seus próprios identificadores, mas a entidade secundária também armazena uma referência para a chave estrangeira da entidade principal.

Figura 1 – Relacionamento de duas tabelas (note que é um M:N e não necessariamente um 1:1)

  CREATE TABLE TBL_PESSOA(  
    PK_PESSOA NUMBER(10) NOT NULL, 
    NM_PESSOA    VARCHAR2(256) NOT NULL, 
   CONSTRAINT PK_PESSOA PRIMARY KEY (PK_PESSOA)
  );

  CREATE TABLE TBL_PET( 
    PK_PET NUMBER(10) NOT NULL, 
    FK_PESSOA NUMBER(10) NOT NULL, 
    NM_PET    VARCHAR2(256) NOT NULL, 
    CONSTRAINT PK_PET PRIMARY KEY (PK_PET),
    CONSTRAINT FK_PET_PESSOA FOREIGN KEY (FK_PESSOA)
    REFERENCES TBL_PESSOA(PK_PESSOA)
  );

Com o modelo tradicional de mapeamento um-para-um, o banco de dados normalmente indexa tanto a chave primária quanto a chave estrangeira, o que é interessante para diminuir o scanning das tabelas, mas isso tem um custo na aplicação: mesmo anotando com FetchType.LAZY sem optional, a tabela A (pai) se comportará como FetchType.EAGER, o que é ruim para performance e uso de memória.

Se é um relacionamento um-para-um, significa que uma linha da tabela B estará relacionada à apenas uma linha da tabela A. Sendo assim, faria mais sentido utilizar a chave estrangeira da tabela A como chave primária da tabela B. Para isso, vamos utilizar a anotação @MapsId. Utilizando essa anotação, você não precisa de um relacionamento bidirecional, mas esse não é nosso propósito: vamos apenas utilizar a chave primária de uma tabela Pessoa em uma tabela Pet – nesse modelo, uma Pessoa só pode ter um Pet:

Figura 2 – Relacionamento entre Pessoa e Pet

A implementação simplificada abaixo desdobra esse relacionamento:

@Entity
@Table(name = "TBL_PESSOA")
public class Pessoa {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "PK_PESSOA")
   private Long id;

   @OneToOne(mappedBy = "pessoa", cascade = CascadeType.ALL, 
       fetch = FetchType.LAZY, optional = true)
   private Pet pet;
}

@Entity
@Table(name = "TBL_PET")
public class Pet {
   @Id
   private Long id;

   @MapsId
   @OneToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "PK_PESSOA")
   private Pessoa pessoa;

}

No banco de dados, o relacionamento é armazenado assim:

  CREATE TABLE TBL_PESSOA(	
    PK_PESSOA NUMBER(10) NOT NULL, 
    NM_PESSOA    VARCHAR2(256) NOT NULL, 
	  CONSTRAINT PK_PESSOA PRIMARY KEY (PK_PESSOA)
  );

  CREATE TABLE TBL_PET( 
    PK_PESSOA NUMBER(10) NOT NULL, 
    NM_PET    VARCHAR2(256) NOT NULL, 
    CONSTRAINT PK_PET PRIMARY KEY (PK_PESSOA),
    CONSTRAINT FK_PET_PESSOA FOREIGN KEY (PK_PESSOA)
    REFERENCES TBL_PESSOA(PK_PESSOA)
  );

Figura 3 – Relacionamento 1:1 com PK compartilhada

Anúncios
  1. Nenhum comentário ainda.
  1. No trackbacks yet.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

w

Conectando a %s

%d blogueiros gostam disto: