Hibernate: asignaciones de varios a uno
UN many-to-oneLa asociación es el tipo de asociación más común en el que un Objeto se puede asociar con varios objetos. Por ejemplo, el mismo objeto de dirección se puede asociar con varios objetos de empleado.
Definir tablas RDBMS
Considere una situación en la que necesitamos almacenar nuestros registros de empleados en la tabla EMPLOYEE, que tendrá la siguiente estructura:
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)
);
Además, muchos empleados pueden tener la misma dirección, por lo que esta asociación se puede presentar mediante la asociación de varios a uno. Almacenaremos la información relacionada con la dirección en una tabla separada que tiene la siguiente estructura:
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)
);
Cree ambas tablas RBDMS y manténgalas listas para la próxima implementación.
Definir clases POJO
Implementemos una clase POJO Employee, que se utilizará para conservar los objetos relacionados con la tabla EMPLEADO y que tengan una variable de tipo Dirección.
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;
}
}
Necesitamos definir otra clase POJO correspondiente a la tabla ADDRESS para que los objetos de dirección se puedan almacenar y recuperar en la tabla 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 archivo de asignación de Hibernate
Desarrollemos nuestros archivos de mapeo, que le indican a Hibernate cómo mapear las clases definidas a las tablas de la base de datos. El elemento <many-to-one> se utilizará para definir la regla para establecer una relación de varios a uno entre las entidades EMPLOYEE y ADDRESS.
<?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"
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>
Debe guardar el documento de mapeo en un archivo con el formato <classname> .hbm.xml. Guardamos nuestro documento de mapeo en el archivo Employee.hbm.xml. Ya está familiarizado con la mayoría de los detalles del mapeo, pero veamos todos los elementos del archivo de mapeo una vez más:
El documento de mapeo es un documento XML que tiene <hibernate-mapping> como el elemento raíz que contiene dos elementos <class> correspondientes a cada clase.
los <class>Los elementos se utilizan para definir asignaciones específicas de clases Java a las tablas de la base de datos. El nombre de la clase Java se especifica mediante elname El atributo del elemento de clase y el nombre de la tabla de la base de datos se especifica utilizando el table atributo.
los <meta> El elemento es un elemento opcional y se puede utilizar para crear la descripción de la clase.
los <id>El elemento asigna el atributo de ID único en la clase a la clave principal de la tabla de la base de datos. losname atributo del elemento id se refiere a la propiedad en la clase y el columnEl atributo se refiere a la columna de la tabla de la base de datos. lostype El atributo contiene el tipo de mapeo de hibernación, estos tipos de mapeo se convertirán del tipo de datos Java a SQL.
los <generator>El elemento dentro del elemento id se utiliza para generar los valores de clave primaria automáticamente. losclass atributo del elemento generador se establece en native para dejar que hibernate retome identity, sequence o hilo algoritmo para crear la clave principal en función de las capacidades de la base de datos subyacente.
los <property>El elemento se utiliza para asignar una propiedad de clase Java a una columna en la tabla de la base de datos. losname atributo del elemento se refiere a la propiedad en la clase y el columnEl atributo se refiere a la columna de la tabla de la base de datos. lostype El atributo contiene el tipo de mapeo de hibernación, estos tipos de mapeo se convertirán del tipo de datos Java a SQL.
los <many-to-one>El elemento se utiliza para establecer la relación entre las entidades EMPLOYEE y ADDRESS. losnameEl atributo se establece en la variable definida en la clase principal, en nuestro caso es la dirección . loscolumn El atributo se utiliza para establecer el nombre de la columna en la tabla principal EMPLOYEE.
Finalmente, crearemos nuestra clase de aplicación con el método main () para ejecutar la aplicación. Usaremos esta aplicación para guardar algunos registros de empleados junto con sus direcciones y luego aplicaremos operaciones CRUD en esos 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 address = ME.addAddress("Kondapur","Hyderabad","AP","532");
/* Add employee records in the database */
Integer empID1 = ME.addEmployee("Manoj", "Kumar", 4000, address);
/* Add another employee record in the database */
Integer empID2 = ME.addEmployee("Dilip", "Kumar", 3000, address);
/* List down all the employees */
ME.listEmployees();
/* Update employee's salary records */
ME.updateEmployee(empID1, 5000);
/* Delete an employee from the database */
ME.deleteEmployee(empID2);
/* 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();
}
}
/* Method to delete an employee from the records */
public void deleteEmployee(Integer EmployeeID){
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Employee employee = (Employee)session.get(Employee.class, EmployeeID);
session.delete(employee);
tx.commit();
} catch (HibernateException e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
} finally {
session.close();
}
}
}
Compilación y ejecución
Estos son los pasos para compilar y ejecutar la aplicación mencionada anteriormente. Asegúrese de haber configurado PATH y CLASSPATH correctamente antes de continuar con la compilación y ejecución.
Cree el archivo de configuración hibernate.cfg.xml como se explica en el capítulo de configuración.
Cree el archivo de mapeo Employee.hbm.xml como se muestra arriba.
Cree el archivo fuente Employee.java como se muestra arriba y compílelo.
Cree el archivo fuente Address.java como se muestra arriba y compílelo.
Cree el archivo fuente ManageEmployee.java como se muestra arriba y compílelo.
Ejecute el binario ManageEmployee para ejecutar el programa.
Obtendría el siguiente resultado en la pantalla, y al mismo tiempo se crearían registros en las tablas EMPLOYEE y 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: Kondapur
City: Hyderabad
State: AP
Zipcode: 532
First Name: Manoj Last Name: Kumar Salary: 5000
Address
Street: Kondapur
City: Hyderabad
State: AP
Zipcode: 532
Si revisa sus tablas EMPLOYEE y ADDRESS, deben tener los siguientes registros:
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+---------+
| id | first_name | last_name | salary | address |
+----+------------+-----------+--------+---------+
| 1 | Manoj | Kumar | 5000 | 5 |
+----+------------+-----------+--------+---------+
1 row in set (0.00 sec)
mysql> select * from ADDRESS;
+----+-------------+-----------+------------+---------+
| id | street_name | city_name | state_name | zipcode |
+----+-------------+-----------+------------+---------+
| 1 | Kondapur | Hyderabad | AP | 532 |
+----+-------------+-----------+------------+---------+
1 row in set (0.00 sec)
mysql>