Hibernate - Mapeamentos Um-para-Um
UMA one-to-one associação é semelhante a many-to-oneassociação com uma diferença de que a coluna será definida como única. Por exemplo, um objeto de endereço pode ser associado a um único objeto de funcionário.
Definir tabelas RDBMS
Considere uma situação em que precisamos armazenar nossos registros de funcionários na tabela EMPLOYEE, que terá a seguinte estrutura -
create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
address INT NOT NULL,
PRIMARY KEY (id)
);
Além disso, supondo que um endereço possa ser associado a um único funcionário, essa associação pode ser apresentada usando a associação um para um. Armazenaremos as informações relacionadas ao endereço em uma tabela separada com a seguinte estrutura -
create table ADDRESS (
id INT NOT NULL auto_increment,
street_name VARCHAR(40) default NULL,
city_name VARCHAR(40) default NULL,
state_name VARCHAR(40) default NULL,
zipcode VARCHAR(10) default NULL,
PRIMARY KEY (id)
);
Crie ambas as tabelas RBDMS e mantenha-as prontas para a próxima implementação.
Definir classes POJO
Vamos implementar uma classe POJO Employee, que será utilizado para persistir os objetos relacionados à tabela EMPLOYEE e possuindo uma variável do tipo Address.
import java.util.*;
public class Employee{
private int id;
private String firstName;
private String lastName;
private int salary;
private Address address;
public Employee() {}
public Employee(String fname, String lname, int salary, Address address ) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
this.address = address;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public String getLastName() {
return lastName;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
public Address getAddress() {
return address;
}
public void setAddress( Address address ) {
this.address = address;
}
}
Precisamos definir outra classe POJO correspondente à tabela ADDRESS para que os objetos de endereço possam ser armazenados e recuperados na tabela ADDRESS.
import java.util.*;
public class Address{
private int id;
private String street;
private String city;
private String state;
private String zipcode;
public Address() {}
public Address(String street, String city, String state, String zipcode) {
this.street = street;
this.city = city;
this.state = state;
this.zipcode = zipcode;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getStreet() {
return street;
}
public void setStreet( String street ) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity( String city ) {
this.city = city;
}
public String getState() {
return state;
}
public void setState( String state ) {
this.state = state;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode( String zipcode ) {
this.zipcode = zipcode;
}
}
Definir arquivo de mapeamento do Hibernate
Vamos desenvolver nossos arquivos de mapeamento que instruem o Hibernate como mapear as classes definidas para as tabelas do banco de dados. O elemento <many-to-one> será usado para definir a regra para estabelecer uma relação um-para-um entre as entidades EMPLOYEE e ADDRESS, mas o atributo da coluna será definido comounique a restrição e o restante do arquivo de mapeamento permanecerão como no caso de associação muitos para um.
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name = "Employee" table = "EMPLOYEE">
<meta attribute = "class-description">
This class contains the employee detail.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
<many-to-one name = "address" column = "address" unique="true"
class="Address" not-null="true"/>
</class>
<class name = "Address" table="ADDRESS">
<meta attribute = "class-description">
This class contains the address detail.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "street" column = "street_name" type = "string"/>
<property name = "city" column = "city_name" type = "string"/>
<property name = "state" column = "state_name" type = "string"/>
<property name = "zipcode" column = "zipcode" type = "string"/>
</class>
</hibernate-mapping>
Você deve salvar o documento de mapeamento em um arquivo com o formato <classname> .hbm.xml. Salvamos nosso documento de mapeamento no arquivo Employee.hbm.xml. Você já está familiarizado com a maioria dos detalhes de mapeamento, mas vamos ver todos os elementos do arquivo de mapeamento mais uma vez -
O documento de mapeamento é um documento XML com <hibernate-mapping> como o elemento raiz que contém dois elementos <class> correspondentes a cada classe.
o <class>elementos são usados para definir mapeamentos específicos de classes Java para as tabelas do banco de dados. O nome da classe Java é especificado usando oname atributo do elemento de classe e o nome da tabela do banco de dados é especificado usando o table atributo.
o <meta> element é um elemento opcional e pode ser usado para criar a descrição da classe.
o <id>elemento mapeia o atributo de ID exclusivo na classe para a chave primária da tabela do banco de dados. oname atributo do elemento id refere-se à propriedade na classe e o columnatributo refere-se à coluna na tabela do banco de dados. otype O atributo contém o tipo de mapeamento de hibernação, esses tipos de mapeamento serão convertidos do tipo de dados Java para SQL.
o <generator>O elemento dentro do elemento id é usado para gerar os valores da chave primária automaticamente. oclass atributo do elemento gerador é definido como native para deixar a hibernação pegar também identity, sequence ou hilo algoritmo para criar a chave primária, dependendo dos recursos do banco de dados subjacente.
o <property>elemento é usado para mapear uma propriedade de classe Java para uma coluna na tabela de banco de dados. oname atributo do elemento refere-se à propriedade na classe e o columnatributo refere-se à coluna na tabela do banco de dados. otype O atributo contém o tipo de mapeamento de hibernação, esses tipos de mapeamento serão convertidos do tipo de dados Java para SQL.
o <many-to-one>elemento é usado para definir o relacionamento entre as entidades EMPLOYEE e ADDRESS. onameatributo é definido para a variável definida na classe pai, no nosso caso é o endereço . ocolumn atributo é usado para definir o nome da coluna na tabela-pai EMPLOYEE, que é definido como unique para que apenas um objeto Employee possa ser associado a um objeto de endereço.
Por fim, criaremos nossa classe de aplicativo com o método main () para executar o aplicativo. Usaremos este aplicativo para salvar alguns registros de Funcionários junto com seus certificados e, em seguida, aplicaremos as operações CRUD a esses registros.
import java.util.*;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class ManageEmployee {
private static SessionFactory factory;
public static void main(String[] args) {
try {
factory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
}
ManageEmployee ME = new ManageEmployee();
/* Let us have one address object */
Address address1 = ME.addAddress("Kondapur","Hyderabad","AP","532");
/* Add employee records in the database */
Integer empID1 = ME.addEmployee("Manoj", "Kumar", 4000, address1);
/* Let us have another address object */
Address address2 = ME.addAddress("Saharanpur","Ambehta","UP","111");
/* Add another employee record in the database */
Integer empID2 = ME.addEmployee("Dilip", "Kumar", 3000, address2);
/* List down all the employees */
ME.listEmployees();
/* Update employee's salary records */
ME.updateEmployee(empID1, 5000);
/* List down all the employees */
ME.listEmployees();
}
/* Method to add an address record in the database */
public Address addAddress(String street, String city, String state, String zipcode) {
Session session = factory.openSession();
Transaction tx = null;
Integer addressID = null;
Address address = null;
try {
tx = session.beginTransaction();
address = new Address(street, city, state, zipcode);
addressID = (Integer) session.save(address);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return address;
}
/* Method to add an employee record in the database */
public Integer addEmployee(String fname, String lname, int salary, Address address){
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try {
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary, address);
employeeID = (Integer) session.save(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
return employeeID;
}
/* Method to list all the employees detail */
public void listEmployees( ){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
List employees = session.createQuery("FROM Employee").list();
for (Iterator iterator = employees.iterator(); iterator.hasNext();){
Employee employee = (Employee) iterator.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
Address add = employee.getAddress();
System.out.println("Address ");
System.out.println("\tStreet: " + add.getStreet());
System.out.println("\tCity: " + add.getCity());
System.out.println("\tState: " + add.getState());
System.out.println("\tZipcode: " + add.getZipcode());
}
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
/* Method to update salary for an employee */
public void updateEmployee(Integer EmployeeID, int salary ){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Employee employee = (Employee)session.get(Employee.class, EmployeeID);
employee.setSalary( salary );
session.update(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Compilação e execução
Aqui estão as etapas para compilar e executar o aplicativo mencionado acima. Certifique-se de definir PATH e CLASSPATH apropriadamente antes de prosseguir com a compilação e execução.
Crie o arquivo de configuração hibernate.cfg.xml conforme explicado no capítulo de configuração.
Crie o arquivo de mapeamento Employee.hbm.xml conforme mostrado acima.
Crie o arquivo de origem Employee.java conforme mostrado acima e compile-o.
Crie o arquivo de origem Address.java conforme mostrado acima e compile-o.
Crie o arquivo de origem ManageEmployee.java conforme mostrado acima e compile-o.
Execute o binário ManageEmployee para executar o programa.
Você obteria o seguinte resultado na tela e, ao mesmo tempo, seriam criados registros nas tabelas EMPLOYEE e ADDRESS.
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
First Name: Manoj Last Name: Kumar Salary: 4000
Address
Street: Kondapur
City: Hyderabad
State: AP
Zipcode: 532
First Name: Dilip Last Name: Kumar Salary: 3000
Address
Street: Saharanpur
City: Ambehta
State: UP
Zipcode: 111
First Name: Manoj Last Name: Kumar Salary: 5000
Address
Street: Kondapur
City: Hyderabad
State: AP
Zipcode: 532
First Name: Dilip Last Name: Kumar Salary: 3000
Address
Street: Saharanpur
City: Ambehta
State: UP
Zipcode: 111
Se você verificar as tabelas EMPLOYEE e CERTIFICATE, elas devem ter os seguintes registros -
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+---------+
| id | first_name | last_name | salary | address |
+----+------------+-----------+--------+---------+
| 7 | Manoj | Kumar | 5000 | 5 |
| 8 | Dilip | Kumar | 3000 | 6 |
+----+------------+-----------+--------+---------+
2 rows in set (0.00 sec)
mysql> select * from ADDRESS;
+----+-------------+-----------+------------+---------+
| id | street_name | city_name | state_name | zipcode |
+----+-------------+-----------+------------+---------+
| 5 | Kondapur | Hyderabad | AP | 532 |
| 6 | Saharanpur | Ambehta | UP | 111 |
+----+-------------+-----------+------------+---------+
2 rows in set (0.00 sec)
mysql>