Управление данными приложения. Hibernate
Технологии обеспечения синхронизации внутренних данных приложения и его базы данных развиваются в настоящий момент достаточно активно. Технология EJB предоставляет соответствующие механизмы, но за счет значительного снижения удобства разработки и модификации компонентов. Обеспечение той же функциональности при более простой внутренней организации кода является основным направлением развития в данной области.
Возможным решением этой задачи являются объектно-реляционные преобразователи (object-relation mappers, ORM), которые обеспечивают автоматическую синхронизацию между данными приложения в виде наборов связанных объектов и данными, хранящимися в системе управления базами данных (СУБД) в реляционном виде, т.е. в форме записей в нескольких таблицах, ссылающихся друг на друга с помощью внешних ключей.
Одним из наиболее широко применяемых и развитых в технологическом плане объектно-реляционных преобразователей является Hibernate [7,8,9].
Базовая парадигма, лежащая в основе избранного Hibernate подхода, — это использование объектов обычных классов Java (быть может, оформленных в соответствии с требованиями спецификации JavaBeans — с четко выделенными свойствами) в качестве объектного представления данных приложения. Такой подход даже имеет название-акроним POJO (plain old Java objects, простые старые Java-объекты), призванное показать его отличие от сложных техник построения компонентов, похожих на EJB.
Большое достоинство подобного подхода — возможность использовать один раз созданные наборы классов, представляющих понятия предметной области, в качестве модели данных любых приложений на основе Java, независимо от того, являются ли они распределенными или локальными, требуется ли в них синхронизация с базой данных и сохранение данных объектов или нет.
увеличить изображение
Рис. 15.2. Реляционное представление данных о книгах и авторах
Например, для представления в объектном виде данных о книгах и их авторах, соответствующих показанной на рис. 15.2 группе таблиц, могут быть использованы представленные ниже классы:
import java.util.Set; import java.util.HashSet;
public class Author { private int id;
private String firstName; private String surname;
private Set books = new HashSet();
public int getId () { return this.id; } private void setId (int id) { this.id = id; }
public String getFirstName () { return this.firstName; } public void setFirstName (String firstName) { this.firstName = firstName; }
public String getSurname () { return this.surname; } public void setSurname (String surname) { this.surname = surname; }
public Set getBooks () { return this.books; } public void setBooks (Set books) { this.books = books; } }
public class Book { private int id;
private String title; private String isbn;
private Set authors = new HashSet();
public int getId () { return this.id; } private void setId (int id) { this.id = id; }
public String getIsbn () { return this.isbn; } public void setIsbn (String isbn) { this.isbn = isbn; }
public String getTitle () { return this.title; } public void setTitle (String title) { this.title = title; }
public Set getAuthors () { return this.authors; } public void setAuthors (Set authors) { this.authors = authors; } }
Пример 15.1.
Для определения отображения объектов этих классов в записи соответствующих таблиц используются конфигурационные файлы со следующим содержанием. Первый фрагмент представляет собой описание отображения объектов класса Author на записи таблицы Authors, которое обычно помещается в файл Author.hbm.xml:
<hibernate-mapping> <class name="Author" table="Authors"> <id name="id" column="ID"> <generator class="increment"/> </id> <property name="firstName" column="FirstName"/> <property name="surname"/ column="Surname"> <set name="books" table="BookAuthors" inverse="true"> <key column="AuthorID"/> <many-to-many column="BookID" class="Book"/> </set> </class> </hibernate-mapping>
Второй фрагмент представляет собой содержание аналогичного файла Book.hbm.xml, описывающего отображение объектов класса Book на записи таблицы Books.
<hibernate-mapping> <class name="Book" table="Books"> <id name="id" column="ID"> <generator class="increment"/> </id> <property name="title" column="Title"/> <property name="isbn"/ column="ISBN"> <set name="authors" table="BookAuthors" inverse="true"> <key column="BookID"/> <many-to-many column="AuthorID" class="Author"/> </set> </class> </hibernate-mapping>
При использовании объектов указанных классов в рамках приложения на основе Hibernate обеспечивается автоматическая синхронизация данных объектов с данными соответствующих записей, а также автоматическая поддержка описанного отношения типа "многие-ко-многим".
Кроме того, Hibernate поддерживает удобные средства для описания сложных соответствий между объектами и записями таблиц при использовании наследования. Так, легко могут быть поддержаны: отображение данных всех объектов классов-наследников в одну таблицу, отображение объектов разных классов-наследников в разные таблицы, отображение данных полей общего класса-предка в одну таблицу, а данных классов-наследников — в разные таблицы, а также смешанные стратегии подобных отображений.
В приложениях на основе Hibernate объекты одного и того же класса могут быть как хранимыми, т.е. представляющими данные, хранящиеся в базе данных, так и временными, не имеющими соответствующих записей в базе данных. Перевод объекта из одного из этих видов в другой осуществляется при помощи всего лишь одного вызова метода вспомогательного класса среды Hibernate.
C помощью дополнительной службы NHibernate [7] возможности среды Hibernate могут быть использованы и из приложений на базе .NET.