Hibernate - Mapeamentos SortedMap
UMA SortedMap é uma coleção java semelhante a Mapque armazena elementos em pares de valores-chave e fornece uma ordem total em suas chaves. Elementos duplicados não são permitidos no mapa. O mapa é ordenado de acordo com a ordem natural de suas chaves ou por um Comparador normalmente fornecido no momento da criação do mapa classificado.
Um SortedMap é mapeado com um elemento <map> na tabela de mapeamento e um mapa ordenado pode ser inicializado com java.util.TreeMap.
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,
PRIMARY KEY (id)
);
Além disso, assuma que cada funcionário pode ter um ou mais certificados associados a ele. Armazenaremos as informações relacionadas ao certificado em uma tabela separada que possui a seguinte estrutura -
create table CERTIFICATE (
id INT NOT NULL auto_increment,
certificate_type VARCHAR(40) default NULL,
certificate_name VARCHAR(30) default NULL,
employee_id INT default NULL,
PRIMARY KEY (id)
);
Haverá one-to-many relação entre os objetos EMPLOYEE e CERTIFICATE.
Definir classes POJO
Vamos implementar uma classe POJO Employee, que será usado para persistir os objetos relacionados à tabela EMPLOYEE e ter uma coleção de certificados em List variável.
import java.util.*;
public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;
private SortedMap certificates;
public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
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 SortedMap getCertificates() {
return certificates;
}
public void setCertificates( SortedMap certificates ) {
this.certificates = certificates;
}
}
Precisamos definir outra classe POJO correspondente à tabela CERTIFICATE para que os objetos de certificado possam ser armazenados e recuperados na tabela CERTIFICATE. Essa classe também deve implementar a interface Comparable e o método compareTo que serão usados para classificar os elementos-chave do SortedMap no caso de você definir sort = "natural" em seu arquivo de mapeamento (consulte o arquivo de mapeamento abaixo).
public class Certificate implements Comparable <String>{
private int id;
private String name;
public Certificate() {}
public Certificate(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getName() {
return name;
}
public void setName( String name ) {
this.name = name;
}
public int compareTo(String that){
final int BEFORE = -1;
final int AFTER = 1;
if (that == null) {
return BEFORE;
}
Comparable thisCertificate = this;
Comparable thatCertificate = that;
if(thisCertificate == null) {
return AFTER;
} else if(thatCertificate == null) {
return BEFORE;
} else {
return thisCertificate.compareTo(thatCertificate);
}
}
}
Definir arquivo de mapeamento do Hibernate
Vamos desenvolver nosso arquivo de mapeamento que instrui o Hibernate como mapear as classes definidas para as tabelas do banco de dados. O elemento <map> será usado para definir a regra para o Mapa usado.
<?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>
<map name = "certificates" cascade="all" sort="MyClass">
<key column = "employee_id"/>
<index column = "certificate_type" type = "string"/>
<one-to-many class="Certificate"/>
</map>
<property name = "firstName" column = "first_name" type = "string"/>
<property name = "lastName" column = "last_name" type = "string"/>
<property name = "salary" column = "salary" type = "int"/>
</class>
<class name = "Certificate" table = "CERTIFICATE">
<meta attribute = "class-description">
This class contains the certificate records.
</meta>
<id name = "id" type = "int" column = "id">
<generator class="native"/>
</id>
<property name = "name" column = "certificate_name" 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 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 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 <map>O elemento é usado para definir o relacionamento entre as classes Certificado e Funcionário. Usamos ocascadeatributo no elemento <map> para dizer ao Hibernate para persistir os objetos Certificate ao mesmo tempo que os objetos Employee. oname atributo é definido como definido SortedMapvariável na classe pai, no nosso caso são certificados . osort atributo pode ser definido para natural para ter classificação natural ou pode ser definido para uma implementação de classe personalizada java.util.Comparator. Nós usamos uma classeMyClass que implementa java.util.Comparator para reverter a ordem de classificação implementada em Certificate classe.
o <index>O elemento é usado para representar as partes principais do par de mapa de chave / valor. A chave será armazenada na coluna certificate_type usando um tipo de string.
o <key>elemento é a coluna na tabela CERTIFICATE que contém a chave estrangeira para o objeto pai, isto é. mesa EMPLOYEE.
o <one-to-many>O elemento indica que um objeto Employee está relacionado a muitos objetos Certificate e, como tal, o objeto Certificate deve ter um pai Employee associado a ele. Você pode usar qualquer<one-to-one>, <many-to-one> ou <many-to-many> elementos com base em seus requisitos.
Se usarmos sort="natural"então não precisamos criar uma classe separada porque a classe Certificate já implementou a interface Comparable e o hibernate usará o método compareTo () definido na classe Certificate para comparar as chaves SortedMap. Mas estamos usando uma classe comparadora personalizadaMyClassem nosso arquivo de mapeamento, portanto, teríamos que criar essa classe com base em nosso algoritmo de classificação. Vamos fazer a classificação decrescente das chaves disponíveis no mapa.
import java.util.Comparator;
public class MyClass implements Comparator <String>{
public int compare(String o1, String o2) {
final int BEFORE = -1;
final int AFTER = 1;
/* To reverse the sorting order, multiple by -1 */
if (o2 == null) {
return BEFORE * -1;
}
Comparable thisCertificate = o1;
Comparable thatCertificate = o2;
if(thisCertificate == null) {
return AFTER * 1;
} else if(thatCertificate == null) {
return BEFORE * -1;
} else {
return thisCertificate.compareTo(thatCertificate) * -1;
}
}
}
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 nesses 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 a set of certificates for the first employee */
TreeMap set1 = new TreeMap();
set1.put("ComputerScience", new Certificate("MCA"));
set1.put("BusinessManagement", new Certificate("MBA"));
set1.put("ProjectManagement", new Certificate("PMP"));
/* Add employee records in the database */
Integer empID1 = ME.addEmployee("Manoj", "Kumar", 4000, set1);
/* Another set of certificates for the second employee */
TreeMap set2 = new TreeMap();
set2.put("ComputerScience", new Certificate("MCA"));
set2.put("BusinessManagement", new Certificate("MBA"));
/* Add another employee record in the database */
Integer empID2 = ME.addEmployee("Dilip", "Kumar", 3000, set2);
/* 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 employee record in the database */
public Integer addEmployee(String fname, String lname, int salary, TreeMap cert){
Session session = factory.openSession();
Transaction tx = null;
Integer employeeID = null;
try{
tx = session.beginTransaction();
Employee employee = new Employee(fname, lname, salary);
employee.setCertificates(cert);
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 iterator1 = employees.iterator(); iterator1.hasNext();){
Employee employee = (Employee) iterator1.next();
System.out.print("First Name: " + employee.getFirstName());
System.out.print(" Last Name: " + employee.getLastName());
System.out.println(" Salary: " + employee.getSalary());
SortedMap<String, Certificate> map = employee.getCertificates();
for(Map.Entry<String,Certificate> entry : map.entrySet()){
System.out.print("\tCertificate Type: " + entry.getKey());
System.out.println(", Name: " + (entry.getValue()).getName());
}
}
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();
}
}
}
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 Certificate.java conforme mostrado acima e compile-o.
Crie o arquivo fonte MyClass.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 os mesmos registros de tempo seriam criados nas tabelas EMPLOYEE e CERTIFICATE. Você pode ver que o tipo de certificado foi classificado na ordem inversa. Você pode tentar alterar seu arquivo de mapeamento, basta definirsort="natural" e execute seu programa e compare os resultados.
$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........
First Name: Manoj Last Name: Kumar Salary: 4000
Certificate Type: ProjectManagement, Name: PMP
Certificate Type: ComputerScience, Name: MCA
Certificate Type: BusinessManagement, Name: MBA
First Name: Dilip Last Name: Kumar Salary: 3000
Certificate Type: ComputerScience, Name: MCA
Certificate Type: BusinessManagement, Name: MBA
First Name: Manoj Last Name: Kumar Salary: 5000
Certificate Type: ProjectManagement, Name: PMP
Certificate Type: ComputerScience, Name: MCA
Certificate Type: BusinessManagement, Name: MBA
Se você verificar as tabelas EMPLOYEE e CERTIFICATE, elas devem ter os seguintes registros -
mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 74 | Manoj | Kumar | 5000 |
+----+------------+-----------+--------+
1 row in set (0.00 sec)
mysql> select * from CERTIFICATE;
+----+--------------------+------------------+-------------+
| id | certificate_type | certificate_name | employee_id |
+----+--------------------+------------------+-------------+
| 52 | BusinessManagement | MBA | 74 |
| 53 | ComputerScience | MCA | 74 |
| 54 | ProjectManagement | PMP | 74 |
+----+--------------------+------------------+-------------+
3 rows in set (0.00 sec)
mysql>