JPA Mapeando Duas Tabelas em uma Classe

EXISTE UMA NOVA VERSÃO DESSE POST.
CLICK AQUI: http://uaihebert.com/?p=1622&page=11

Olá, boa tarde.

Vamos ver hoje como mapear duas tabelas em uma classe. Veremos uma abordagem simples para conseguirmos realizar essa tarefa.

Caso você precise criar o ambiente necessário para executar uma aplicação com JPA, você pode acessar os primeiros posts que contém os links para download e o passo a passo das configurações. Os outros posts sobre JPA são (do mais recente para o mais antigo): Mapeando Datas (Date) e Enum, Chave Primária Composta, SequenceGenerator, TableGenerator – Chave Primária Simples, Auto Create Schema Script com: Ant, Hibernate 3 e JPA 2, Tutorial Hibernate 3 com JPA 2.

Estarei utilizando aqui o banco de dados Postgres, e irei postar o script para se criar as tabelas e inserir um registro em cada. Caso você tenha dúvidas de como configurar sua aplicação (ex.: persistence.xml, bibliotecas, build path) visite os primeiros posts sobre o assunto. Vou colocar aqui, apenas o básico.

CREATE TABLE hello.person
(
  id integer NOT NULL,
  "name" character varying(255) NOT NULL
)
WITH (
  OIDS=FALSE
);
ALTER TABLE hello.person OWNER TO postgres;

CREATE TABLE hello.health_care
(
  id integer NOT NULL,
  "company_name" character varying(255)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE hello.health_care OWNER TO postgres;

-- Insert a person and his healt care company
INSERT INTO hello.person values (1 , 'john');
INSERT INTO hello.health_care values ( 1, 'best ever');

Um caso simples onde a pessoa tem um plano de saúde. Mas imagine que esse plano de saúde não é controlado pela sua aplicação, ela é mantida por outra aplicação.

Em nosso caso, não é necessário criar uma classe PlanoDeSaude, pois como queremos apenas exibir o nome do plano de saúde, ele foi incorporado à classe Person (Pessoa).

Vamos ver agora como ficará nossa classe Person:

package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.Table;

@Entity
@Table(name = "person")
@SecondaryTable(name = "health_care", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "id") })
public class Person {

    @Id
    private int id;

    @Column
    private String name;

    @Column(table = "health_care", name = "company_name")
    private String companyName;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

Sobre o código acima:

  • A anotação @SecondaryTable indica ao JPA que existe outra tabela que contém dados da classe atual.
  • O parâmetro pkJoinColumns da anotação @SecondaryTable serve para indicar qual a chave que faz a junção. Como não indicamos nenhuma chave do lado da classe Person na anotação @SecondaryTable, o JPA irá utilizar a chave primária da Person (person_id == health_care_id).
  • Na anotação @Column do atributo companyName, informamos em qual tabela o JPA irá procurar o campo através do parâmetro “table”.

Vou colocar abaixo, como executar uma busca simples:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Hello");
        EntityManager em = emf.createEntityManager();

        try {
            em.getTransaction().begin();

            Person person = em.find(Person.class, 1);

            System.out.println(person.getName());
            System.out.println(person.getCompanyName());

            em.getTransaction().commit();
        }
        catch (Exception e) {
            em.getTransaction().rollback();
            e.printStackTrace();
        }
        finally{
            emf.close();
        }

        System.out.println("It is over");
    }
}

Execute o código e veja o resultado:

Imagem Console.

Note que o nome da empresa veio como se fizesse parte da classe Person.

Caso você tenha alguma dúvida/sugestão basta postar.

Até a próxima.

14 thoughts on “JPA Mapeando Duas Tabelas em uma Classe

    • Olá Charles, bom dia.

      Até hoje não vi limitação quanto ao mapeamento de duas tabelas em uma classe influenciar em um mapeamento de relacionamento.

      Não vejo problema, em uma classe que tem duas tabelas como persistência no banco, ser utilizada em algum relacionamento 1:n ou n:1 ou n:n.

      Obrigado pela visita.

    • Olá frantchesco, bom dia.

      Existe sim, basta utilizar a anotação conforme abaixo:
      @SecondaryTables(value={@SecondaryTable(name="TABELA_A"), @SecondaryTable(name="TABELA_B"), @SecondaryTable(name="TABELA_C")})
      Espero ter ajudado,
      Obrigado pela visita.

  1. Boa Noite uaihebert, estou com uma dúvida e acho q vc pode me ajudar.

    Tenho uma entidade chamada documento que recebe como atributo (chaves estrangeiras) duas outras entidades: funcionario e tipodocumento. Quanto ao relacionamento de documento com tipodocumento está tudo certo, mas quanto tento mapear o relacionamento de funcionario com documento o servidor acusa um erro.

    Já tentei todos os tipos de relacionamento. @OneToMany, @ManyToOne, @OneToOne, etc e nenhum deles funcionou. E agora? Alguma dica para me ajudar?

    • Macksuel, boa noite.

      Vi no GUJ que você conseguiu resolver seu problema.

      Desculpe a demora, estava a finalizar o post que saiu na quinta feira.

      Até a próxima! o_

  2. tenho uma entidade PESSOA que tem como seconday uma entidade FOTO, porém não cosigo efetuar updates na entidade pessoa, gera o seguinte erro:

    javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not insert/select ids for bulk update

    o que poderia ser?

    • Olá, fcc

      Olhando apenas pelos dados informados não tenho como te falar.

      Seria necessária uma análise de todo as classes relacionadas a esse erro.

      Você conseguiria uma resposta melhor no http://www.guj.com.br . O pessoal do fórum presta uma ótima consultoria gratuita lá.

      Obrigado pela visita.

  3. Boa Tarde
    Será que é possível mapear uma tabela do banco em 2 entidades?
    Se sim, uma poderia ter a coleção da outra? e como poderia diferenciar-las na hora de recuperar registros?

    Desde já agradeço

    • Alexandre, bom dia.

      É possível sim, basta você criar as Entities com nome diferente e com a anotação @Table apontar para a mesma tabela.

      Não sei te falar se haveria problema de relacionamento entre elas, pois nunca precisei fazer isso ou ouvi de alguém fazendo.

      Desculpe não poder ajudar mais.

      Até mais.

  4. oi, tudo bem?!

    uma dúvida…

    tenho duas tabelas em bancos diferentes, a primeira é uma tabela de empresa onde há milhares de registros e a outra é uma tabela no meu banco onde se o usuário não encontra na primeira ele cadastra…

    quando for pesquisar, se a primeira retorna menos de 100 registros é completado com o resultado da outra tabela, desconsiderando os que tem o mesmo cnpj…

    gostaria de saber se é possível fazer esse mapeamento para uma só classe mesmo com bases diferentes!

    obrigado mais uma vez!

    • Thiago, boa noite.

      Honestamente não me vem nada a cabeça que seja nativo do JPA.

      O que você poderia fazer era criar uma VIEW que faria a consulta nos dois bancos. O problema seria na hora de criar/atualizar/excluir algum registro.

      Se for só para leitura, a VIEW server.

      Obrigado pela visita.

      • Boa noite, Hebert!

        Entendi, na verdade a tabela com milhares de registros já é uma view e muito lenta e só é utilizada para leitura, a tabela que seria atualizada é a do meu banco…

        a propósito fiz meu primeiro sistema com base no seu:
        http://uaihebert.com/aplicacao-web-completa-jsf-ejb-jpa-jaas/
        e está funcionando perfeitamente…

        Gostaria de agradecer mais uma vez e te desejar tudo de bom, pois você já me ajudou muito, Obrigado !!!

        • Thiago, fico feliz em saber que meu projeto está ajudando você de algum modo.

          Realmente fazer o persist em tabela diferente já aumentaria a complexidade. Honestamente eu deixaria apenas o JPA apontando para seu banco, e a consulta a VIEW usando NativeQuery. Desse modo seria mais fácil.

          Seria realmente necessário você pegar essa VIEW e criar otimizações necessárias, algo como: índices, paginações, particionamento, etc.

          Obrigado pelo apoio. (:

Leave a Comment