Linguagens orientadas a objeto utilizam atualmente frameworks ORM para persistir objetos no banco de dados relacional. Um clássico relacionamento entre duas tabelas em um banco de dados é feito através de uma chave primaria que contem um identificador em uma tabela e dados adicionais e uma chave estrangeira em outra tabela que define a referencia ao seu registro mestre, este tipo de referencia é comumente conhecido como referencia pai e filho ou mestre e detalhes. Ao longo dos anos os dados alimentados em tabelas mestre/detalhes foram inseridos através de scripts SQL escritos manualmente, ou seja se faz necessário que o desenvolvedor escreva um script pra inserir os dados na tabela mestre primeiro e depois escreva outro script para inserir os dados na tabela de detalhes, a chave estrangeira previne que somente seja inseridos dados na tabela de detalhes no qual possui uma referencia na tabela mestre, tornando assim o banco de dados integro.
Os frameworks modernos nos permitem persistir objetos utilizando a sintaxe da programação orientada a objeto de sua preferencia ao invés de usar scripts SQL tradicionais, pois estes serão criados automaticamente pelo próprio framework. Uma das vantagens de se usar este tipo de framework é que você pode persistir dados diretamente de seus objetos não precisando escrever linhas de código SQL. No entanto é preciso que você domine os conceitos exigidos pelo framework para criar cada tipo de recurso que a linguagem SQL oferece para que seu código rode redondo e com ótimo desempenho.
No caso do Hibernate é necessário que você utilize corretamente as anotações pra que o framework saiba como funciona o relacionamento entre as duas tabelas.
One To One: http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/#d5e3678
One To One Mapping
1 – Primeiramente crie duas tabelas utilizando o script abaixo no banco de dados Oracle e crie sua foreign key adequadamente, caso a chave estrangeira esteja incorreta o Hibernate não conseguira utilizar o relacionamento adequadamente:
2 – Crie um novo projeto Java SE e utilize os códigos abaixo para suas respectivas classes. Atente-se para as anotações pois elas são importantes e precisam estar corretamente decoradas em seus atributos ou métodos, nunca misture as anotações entre atributos e métodos:
3 – Após rodar sua aplicação abra o Oracle SQL Developer e veja o conteúdo das duas tabelas. Você pode reparar que com apenas uma Sequence criando o identificador você automaticamente gravou os dados mestre/detalhes fazendo referencia ao seu ID:
Exemplo:
Neste exemplo criamos duas tabelas e uma chave estrangeira que faz referencia ao seu identificador criando um relacionamento mestre/detalhes. Utilizamos o framework Hibernate e seu relacionamento One To One para persistir dois objetos que foram mapeados adequadamente para salvar registros mestres e seus detalhes mantendo a integridade relacional no banco de dados.
SQL
-- Cria Sequence Participante CREATE SEQUENCE SEQ_CARROS START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE; -- Cria tabela de participantes CREATE TABLE CARROS ( ID_CARRO INTEGER NOT NULL , DESCRICAO VARCHAR2(30) NOT NULL , CONSTRAINT CARROS_PK PRIMARY KEY ( ID_CARRO ) ENABLE ); -- Cria tabela de carro_detalhes CREATE TABLE CARROS_DETALHES ( ID_CARRO INTEGER NOT NULL , MARCA VARCHAR2(30) NOT NULL , MODELO VARCHAR2(30) NOT NULL , ANO INTEGER NOT NULL , CONSTRAINT CARROS_DETALHES_PK PRIMARY KEY ( ID_CARRO ) ENABLE ); -- Cria Contraint chave estrangeira ALTER TABLE CARROS_DETALHES ADD CONSTRAINT CARRO_FK FOREIGN KEY (ID_CARRO) REFERENCES CARROS (ID_CARRO);
Java
Carros
package org.desenvolvimento.aberto; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.SequenceGenerator; import javax.persistence.Table; @Entity @Table(name = "CARROS") public class Carros { @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_CARROS") @SequenceGenerator(name = "SEQ_CARROS", sequenceName = "SEQ_CARROS") @Column(name = "ID_CARRO") private int id_carro; @Column(name = "DESCRICAO") private String descricao; // Cria instancia dos detalhes @OneToOne(mappedBy= "carros", cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name = "ID_CARRO") private CarrosDetalhes carroDetalhes; // Getters & Setters Carros public int getId_carro() { return id_carro; } public void setId_carro(int id_carro) { this.id_carro = id_carro; } public String getDescricao() { return descricao; } public void setDescricao(String descricao) { this.descricao = descricao; } // Getter & Setter detalhes public CarrosDetalhes getCarroDetalhes() { return carroDetalhes; } public void setCarroDetalhes(CarrosDetalhes carroDetalhes) { this.carroDetalhes = carroDetalhes; } }
CarrosDetalhes
package org.desenvolvimento.aberto; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; @Entity @Table(name = "CARROS_DETALHES") public class CarrosDetalhes { @GenericGenerator(name = "generator", strategy = "foreign", parameters = @Parameter(name = "property", value = "carros")) @Id @GeneratedValue(generator = "generator") @Column(name = "ID_CARRO") private int id_carro; @Column(name = "MARCA") private String marca; @Column(name = "MODELO") private String modelo; @Column(name = "ANO") private int ano; @OneToOne(fetch = FetchType.LAZY) @PrimaryKeyJoinColumn private Carros carros; public int getId_carro() { return id_carro; } public void setId_carro(int id_carro) { this.id_carro = id_carro; } public String getMarca() { return marca; } public void setMarca(String marca) { this.marca = marca; } public String getModelo() { return modelo; } public void setModelo(String modelo) { this.modelo = modelo; } public int getAno() { return ano; } public void setAno(int ano) { this.ano = ano; } public Carros getCarros() { return carros; } public void setCarros(Carros carros) { this.carros = carros; } }
Teste
package org.desenvolvimento.aberto; import org.hibernate.Session; public class Testar { public static void main(String[] args) { // Cria sessão Session session = DBConexaoFactory.getSessionFactory().openSession(); // Cria transação session.beginTransaction(); // Cria objeto de detalhes CarrosDetalhes detalhes = new CarrosDetalhes(); detalhes.setMarca("Honda"); detalhes.setModelo("Civic"); detalhes.setAno(2015); // Cria objeto carro Carros carros = new Carros(); carros.setDescricao("Honda"); // adiciona detalhes ao carro carros.setCarroDetalhes(detalhes); detalhes.setCarros(carros); // salva carro session.save(carros); // Confirma e encerra transação session.getTransaction().commit(); } }
DbConexaoFactory
package org.desenvolvimento.aberto; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class DBConexaoFactory { private static final SessionFactory sessionFactory = buildSessionFactory(); // Constroi sessão @SuppressWarnings("deprecation") private static SessionFactory buildSessionFactory() { try { // buildSessionFactory não será utilizado em versões superiores // Veremos outros métodos para criar um Factory // Não é necessário incluir o "hibernate.cfg.xml" no configure() // Incluímos somente a nível de fácil entendimento da chamada da // configuração. // Você pode retirar a chamada. return new Configuration().configure("hibernate.cfg.xml") .buildSessionFactory(); } catch (Throwable ex) { // Em caso de erro System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } // Retorna Factory da sessão public static SessionFactory getSessionFactory() { return sessionFactory; } // Encerra Sessão public static void shutdown() { getSessionFactory().close(); } }
Hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:xe</property> <property name="hibernate.connection.username">user</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.connection.pool_size">10</property> <property name="show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property> <property name="hibernate.current_session_context_class">thread</property> <mapping class="org.desenvolvimento.aberto.Carros" /> <mapping class="org.desenvolvimento.aberto.CarrosDetalhes" /> </session-factory> </hibernate-configuration>