logo
5 модуль

17.5. Объектно-реляционная проекция

В приведенном выше примере, для того, чтобы получить конкретный объект Student, соответсвующий строке таблицы STUDENT, нам требовалось сначала выполнить запрос, создать объект и выполнить его инициализацию. А для того, чтобы сохранить измененное состояние объекта, необходимо сначала создать запрос, заполнить соответсвующие параметры, запрос выполнить. Аналогичные действия требуются для работы с объектами Faculty, соответствующими сущности «факультет».

Усложнение модели предметной области (в контексте приложения) ведет к усложнению кода взаимодействия с базой данных. Сохранение состояния набора объектов в таблицах базы данных и наоборот, восстановление состояния набора объектов из записей в базе данных, с одной стороны, является достаточно однотипной задачей, с другой стороны, требует немалых трудозатрат. Эта задачу называют объектно-реляционной проекцией (Object-Relational Mapping, ORM).

На данный момент существуют ORM-решения (Hibernate, EJB и др.), которые позволяют абстрагироваться от понятия базы данных, настроив отображение между объектами и базой данных в конфигурационных файлах или иным способом, и оперировать исключительно моделью предметной области в Java (или другом языке).

Модель предметной области в базе данных и в Java, в общем случае, не имеют однозначного соответствия. Например, то, что студент слушает несколько курсов, в базе данных моделируется отдельной таблицей STUDENT_COURSE, а на стороне Java этот факт можно представить как коллекцию объектов Course, связанную с объектом Student.

В следующем небольшом примере показано, как с использованием библиотеки Hibernate настроить отображение класса Student на таблицу STUDENT в конфигурационном XML-файле, как получить объект по его идентификатору и как сохранить новый объект.

Конфигурационный файл Student.hbm.xml:

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping >

<class name="Student" table="STUDENT">

<id name="id" type="integer" column="id" unsaved-value="null">

<generator class="increment"/>

</id>

<property name="firstName" column="first_name" />

<property name="lastName" column="last_name"/>

</class>

</hibernate-mapping>

Получаем объект с идентификатором 1:

Integer id = 1;

Student student = (Student) session.get(Student.class, 1);

Здесь session — вспомогательный объект класса org.hibernate.Session из библиотеки Hibernate.

Сравним с JDBC-аналогом:

int id = 1;

PreparedStatement st = con.prepareStatement(

"SELECT * FROM STUDENT WHERE id=?");

st.setInt(1, id);

ResultSet rs =st.executeQuery();

if(rs.next()){

student = new Student();

student.setId(rs.getInt("id"));

student.setFirstName(rs.getString("first_name"));

student.setLastName(rs.getString("last_name"));

}

st.close();

Сохраняем объект:

session.save(student);

Сравним с JDBC-аналогом:

PreparedStatement st = con.prepareStatement(

"INSERT INTO STUDENT (id, first_name, last_name) VALUES (?,?,?)");

st.setInt(1, student.getId());

st.setString(2, student.getFirstName());

st.setString(3, student.getLastName());

st.executeUpdate();

st.close();

Объект, связанный с сессией Hibernate (посредством вызова метода save(), get() и др.) считается сохраненным (persistent), и в случае, если состояние его изменяется, оно автоматически синхронизируется с базой данных, т. е. явно вызывать метод update() не нужно. Это поведение установлено по умолчанию и его при необходимости можно изменить. Но благодаря такой реализации, понятие базы данных вытесняется, т. е. как говорилось выше, в Java-программе мы начинаем оперировать исключительно моделью предметной области.

Подробное изучение Hibernate выходит за рамки курса.