Технология JPA

Основные интерфейсы и конфигурации. Требования к объектам домена. JPA связи, идентификация объектов. Выбор первичных ключей. Понятие и использование компонентов в Hibernate. Отображение ассоциации многие-к-одному. Отображение набора простых элементов.

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 31.01.2014
Размер файла 4,0 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Размещено на http://www.allbest.ru/

План

Введение

1. Основные интерфейсы

2. Конфигурации

3. Требования к объектам домена

4. Метаданные отображения

5. JPA связи. Идентификация объектов

6. Выбор первичных ключей

7. Понятие и использование компонентов в Hibernate

8. Отображение ассоциации многие-к-одному

9. Двунаправленная ассоциация один-ко-многим

10. Ассоциация один-к-одному

11. Списки. Отображение списка один-ко-многим

12. Отображение набора простых элементов

13. Ассоциация многие ко многим

14. Отображение наследования

Заключение

Введение

интерфейс конфигурация домен

JPA - это технология, обеспечивающая объектно-реляционное отображение простых JAVA объектов и предоставляющая API для сохранения, получения и управления такими объектами.

JPA - это спецификация (документ, утвержденный как стандарт, описывающий все аспекты технологии), часть EJB3 спецификации.

Сам JPA не умеет ни сохранять, ни управлять объектами, JPA только определяет правила игры: как что-то будет действовать. JPA также определяет интерфейсы, которые должны быть реализованы провайдерами. Плюс к этому JPA определяет то, как должны описываться метаданные отображения и как должны работать провайдеры. Дальше, каждый провайдер, реализуя JPA определяет получение, сохранение и управление объектами. У каждого провайдера реализация разная.

1. Основные интерфейсы

1. Интерфейс Persistence - по сути это класс. В нем практически нет методов, кроме пары статических. Один из них CreateEntityManagerFactory, то есть он создает EntityManagerFactory. Что он принимает на вход: persistence unit. По сути, он ищет percistance (конфигурацию), считывает ее и создает EntityManagerFactory на основе конфигурации. Здесь мы определяем к какой базе данных будем соединяться, логин, пароль и самое главное, в конфигурации определяется провайдер (какая конкретная реализация JPA будет использоваться). EntityManagerFactory - это интерфейс, реализация которого и есть провайдер.

2. EntityManagerFactory - это фабрика, которая содержит connection к базе, всю конфигурацию, кэш объекты и т.д. Суть фабрики - создавать EntityManager.

3. EntityManager - это менеджер сущностей. Он определяет сеанс взаимодействия с базой данных (один сеанс). Когда, например, нужно выполнить запрос, то мы создаем EntityManager, выполняем нужное действие, закрываем EntityManager.

Объекты EntityManager очень легковесные. Можно создавать их сколько угодно. По сути, здесь просто открывается подключение к базе данных. Может даже соединение уже будет открыто и он присоединиться к текущему.

EntityManagerFactory - фабрика и она создается долго (происходит инициализация всех сущностей, сканируются все классы, считываются аннотации, определяются связи и т. д.). Поэтому фабрика должна быть одна (в основном это так). На одну базу одна фабрика.

Для чего предназначены EntityManager? В нем есть один объект, который называется EntityTransaction (это интерфейс). Он определяет три метода. Begin (стартует транзакцию), commit, rollback. Также EntityManager может содержать несколько объектов Query, по сути, он их создает.

4. EntityManager содержит несколько Entity. Все Entity, которые загружаются из базы данных, например get name, будут висеть постоянно в памяти, то есть EntityManager содержит кэш этих маленьких объектов и пока EntityManager мы не закрыли, последующее обращение (get name) не полезет в базу данных.

Если рассматривать hibernate, то там есть два уровня кэша: первый - EntityManager, второй кэш - это EntityManagerFactory.

Последовательность вызова методов

Persistance, создаем create EntityManagerFactory, передавая параметры Unit. На выходе имеем фабрику либо ничего.

Обращаемся к фабрике и говорим “Дай мне EntityManager”

Потом к EntityManager “Дай мне transaction”

У transaction вызываем метод begin

Обращаемся к EntityManager. Вызываем query.

Query. ResultList

Transaction. Закрываем

EntityManager. Закрываем

Фабрику. Закрываем

Последовательность взаимодействия интерфейсов

Используя Spring, большинство этих действий мы вообще делать не будем. Транзакции Spring будет открывать и закрывать за нас, достаточно будет декларативно указать, что в том-то методе будет такая-то транзакция. Эта схема показывает, как бы мы работали, если бы не использовали Spring. Здесь показана работа с JPA напрямую.

2. Конфигурации

Базовая конфигурация

/META-INF/persistence.xml // именно этот файл ищется классом Persistance

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/persistence

http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

<persistence-unit name="unit name">

<provider> full JPA provider class name </provider>

<class> package.ClassName </class>

<properties> provider properties </properties>

</persistence-unit>

</persistence>

В одном файле xml можно определить несколько unit. С каждым unit может работать свой провайдер, каждый unit будет обращаться к своей базе. Чаще всего определяют один unit. Unit нужно дать уникально имя, которое позже я буду использовать при создании фабрики (CreateEntityManagerFactory(имя)).

Потом нужно указать провайдера.

Далее, необязательно - список классов, которые будут использоваться в работе. Почему необязательно? Некоторые провайдеры, как hibernate, могут делать это автоматически. Далее, мы пишем свойства, относящиеся к конкретному провайдеру. Это подключение к базе данных (url, login, password и т. д. для конкретного провайдера). Эти свойства считываются провайдером и потом создается фабрика.

Все это была базовая конфигурация.

Как будет выглядеть базовая конфигурация с Hibernate

Provider name

org.hibernate.ejb.HibernatePersistence

Provider properties

<property name="hibernate.connection.driver_class"

value="org.hsqldb.jdbcDriver"/>

<property name="hibernate.connection.url"

value="jdbc:hsqldb:mem:db"/>

<property name="hibernate.connection.username"

value="sa"/>

<property name="hibernate.dialect"

value="org.hibernate.dialect.HSQLDialect"/>

<property name="hibernate.hbm2ddl.auto"

value="create"/>

Последний параметр create. Это значит, что когда hibernate полностью считает всю конфигурацию (все ваши классы и аннотации), он сам создаст таблицы и связи между ними, а также поля. Если поставить параметр never, то hibernate будет стараться текущую конфигурацию JPA наложить на существующую базу данных.

Конфигурация с помощью Spring

db.properties

database.driver=com.mysql.jdbc.Driver

database.url=jdbc:mysql://localhost:3306/tpps

database.user=root

database.password=root

database.dialect=org.hibernate.dialect.MySQLDialect

database.createSchema=update

database.showSql=true

<bean id="propertyConfigurer"

class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="location" value="classpath:db.properties" />

</bean>

Не всегда полезно все настройки хранить в одном конфигурационном файле. Некоторые параметры лучше хранить во внешнем db.properties файле. В нем прописываем все свойства необходимые для подключения к базе данных. В Spring нужно определить бин с именем propertyConfigurer (имя должно быть именно таким).

Для работы с JPA в Spring нам нужно определить бин, который будет EntityManagerFactory (название может быть любым). У этого бина может быть несколько реализаций: есть Local, а есть JNDI.

EntityManagerFactory - будет получаться из JNDI, когда запущена внутри контейнера. Если же не внутри контейнера, как мы это делаем на Tomcat (там нет контейнера), то мы сами будем создавать эту фабрику (тогда используется Local).

<bean id="entityManagerFactory"

class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">

<property name="persistenceUnitName" value="unit_name" />

<property name="jpaProperties">

<props>

<prop key="hibernate.connection.url">

${connectionURL}

</prop>

<prop key="hibernate.connection.driver_class">

${connectionDriverName}

</prop>

<prop … >

</props>

</property>

</bean>

После этого в файле persistence.xml осталось определить только PersistanceUnitProvider. ${connectionURL} - это свойства из файла db.properties.

3. Требования к объектам домена

Чтобы JPA мог нормально работать, так как не каждый объект может быть сохранен в базу данных, нужно следить за следующими требованиями:

POJO или JavaBean объект

Класс должен быть не final, то есть его никто не должен наследовать

Наличие конструктора по умолчанию (без параметров)

Implements Serializable, чтобы объекты могли храниться в кэше, в сериализованном виде

Наличие полей идентификации, то есть ни один объект не может сохраняться в БД, если у него нет primary key.

Атрибуты - коллекции обязательно объявлены в терминах интерфейсов коллекции, а не конкретных реализаций. Если используются какие-либо списки, наборы, map-ы, они должны быть классами List, Map, Set и т. д., то есть должны соответствовать интерфейсам из Java Collection. JPA и hibernate следят за коллекциями.

В getters необходимо возвращать конкретно ссылку на коллекцию, а не ее копию (не создавать новые коллекции). Поэтому не рекомендуется использовать Array, так как когда мы возвращаем массив надо всегда делать copy, чтобы кто-то извне не смог изменить. Также от массива сложно наследоваться.

4. Метаданные отображения

После создания или генерирования классов можно добавлять метаданные отображения (МО).

МО делятся на аннотации над классом, аннотации над полями.

В JPA аннотации можно даже не прописывать. Если над полем нет аннотации, то оно все равно сохраняется в базу данных. JPA по умолчанию сохраняет все поля которые есть в объекте, если, конечно, над объектом стоит аннотация @Entity. Чтобы поле не сохранялось @Transient.

Не все поля сохраняются (если не implement Serializable то не сохраняются). Java Socket тоже не сохраняется.

5. JPA связи. Идентификация объектов

Идентичные объекты - ссылки на объекты равны. Сравнение оператором

Одинаковые объекты - одинаковые с логической точки зрения, но при этом имеют разные области памяти. Сравнение методом equals.

Идентичные в терминах БД - объекты ссылаются на одну и ту же запись одной таблицы с одинаковым primary key.

Желательно использовать суррогатный первичный ключ - тот, который никак не соответствует бизнес логике.

Например, мы считываем из базы один и тот же ряд, в итоге мы получаем один объект и второй, то есть, из двух разных запросов мы получаем два разных объекта. Представим себе, что в одном из объектов вы изменили информацию: поменяли телефон у пользователя. И пока еще ничего не сохраняли. Возникает вопрос: считать ли эти два объекта одинаковыми или нет? Если их сравнивать двумя равно, то объекты получаться разными (разные области памяти). Метод equals - смотря на то как мы его реализуем. Если начнем сравнивать логическую структуру объектов, то они опять будут разными, так как у них поменялось одно поле. Вопрос: как реализовать сравнение этих двух объектов? Ответ: суррогатный ключ. Никакого отношения к объекту этот ключ не должен иметь, его будет использовать только база данных. Тогда метод equals мы реализуем таким образом чтобы он сравнивал только этот ключ. Получается, что если ключ равен, то эти объекты одинаковые. Даже если в объектах будут меняться данные относящиеся к бизнес логике, например телефон, то при сравнении методом equals эти объекты будут равными.

6. Выбор первичных ключей

Управление первичными ключами лучше предоставить JPA.

@GeneratedValue (strategy = GenerationType).

AUTO - автоматический выбор

IDENTITY - алгоритм идентичности (возрастающий порядок, возможно с пустыми местами). Часто используется. Здесь id уникальные в пределах одной таблицы.

SEQUENCE - последовательный алгоритм

TABLE - используется дополнительная таблица для хранения последнего назначенного ключа.

Чтобы создать первичный ключ мы указываем аннотацию @id и рядом поставить @GeneratedValue, тогда id будет автоматически генерироваться (либо JPA, либо базой данных).

Переходим к связыванию объектов и отображение этих объектов в базу данных.

7. Понятие и использование компонентов в Hibernate

Компоненты - понятие из Hibernate (или встроенные классы - JPA)

Сущность (Entity) - объект, наделенный уникальным идентификатором. Entity - это объект, который будет содержать первичный ключ (id) и будет сохраняться в базу данных.

Компонент (Embedded class) - объект, без идентификатора.

Например, у нас есть Person, дополнительную информацию об адресе мы вынесли в отдельный объект Adress. Мы их связали, как один-к-одному. Вопрос: есть ли смысл хранить Adress в отдельной таблице? Если связь Composition, то жизненным циклом компонента управляется его родителем. Соответственно родитель ответственен за его создание, удаление и лучше данные хранить ближе к родителю. Смысл - разделить объекты на Person и Adress, но хранить в одном месте.

Есть два способа реализации:

Над полем класса ставим аннотацию @Embedded. Это будет означать, что когда Hibernate (любой провайдер JPA) начнет сохранять Person (над этим классом стоит аннотация @Entity) он увидит аннотацию @Embedded и перейдет по ссылке к классу Adress и также начнет сохранять все поля. Важно здесь то, что в адресе не будет уникального идентификатора.

Другой вариант - в классе Adress (над самим классом) ставим @Embeddable, тогда в классе Person мы не указываем никаких аннотаций.

Это первый способ объединения связей. Давайте рассмотрим следующий.

8. Отображение ассоциации многие-к-одному

Связь однонаправлена.

Пример: есть Item (продукт, например) и у него есть Bid (ставка). Каждая ставка содержит ссылку на свой продукт: ставка на продукт.

Как такая связь отображается в JPA? Со стороны Item делать ничего не нужно, так как в нем нет ссылок на Bid-ы. В классе Bid будет присутствовать ссылка на Item. Получается, что над свойством класса Bid мы ставим аннотацию @ManyToOne. По сути, создастся таблица Bid и в ней будет стоять Foreign key на item.

Примечание: Внешний ключ (англ. foreign key) - понятие теории реляционных баз данных. Внешним ключом называется поле таблицы, предназначенное для хранения значения первичного ключа другой таблицы с целью организации связи между этими таблицами.

Под аннотацией @ManyToOne может стоять аннотация @JoinColumn(name="ITEM_ID"). Если @ JoinColumn не указать, то имя foreign key (колонка) будет состоять из имени переменной, над которой стоит аннотация и имени первичного ключа базы на которую эта переменная ссылается.

Переходим к двунаправленной связи.

9. Двунаправленная ассоциация один-ко-многим

Здесь в Item есть ссылка на Bid и в Bid есть ссылка на Item. В этом случае Bid оставляем таким же как и в связи рассмотренной ранее. Но в Item мы должны создать коллекцию Bid-ов (либо Set, либо Collection, List) и над ней поставить аннотацию @OneToMany(mappedBy="item", cascade = CascadeType.ALL). В mappedBy указывается имя того поля которое ссылается с другой стороны, со стороны Bid-а, в нашем случае. Почему так? Hibernate, как и другая ORM реализация, не понимают двунаправленной связи. Для них все связи однонаправлены. Hibernate понимает это как две связи, одна идет к полю item класса Bid, а другая от поля item класса Bid к первичному ключу (полю) id класса Item.

Если мы делаем двунаправленные связи, то двунаправленностью нам нужно управлять самим. То есть мы должны создать какой-нибудь дополнительный метод (addBid(Bid bid) в котором установим bid.setItem(this) - метод класса Bid, bids.add(bid) - поле класса Item. Это и есть двунаправленная связь. Для поддержки двунаправленности предоставляется mappedBy (в Hibernate это inverse = true). Что этот атрибут позволяет делать? Он говорит, что для этой связи (OneToMany) у нас есть еще и обратная связь. То есть мы говорим, что другая связь тоже существует и Hibernate после этого начнет оптимизировать запросы.

Если mappedBy не указывать, то Hibernate при сохранении объектов сначала сохранит один объект, а потом тут же второй, то есть два раза выполниться команда INSERT. Если поставить это свойство, то foreign key не будет устанавливаться два раза.

Из всего этого важно подчеркнуть, что списками нужно управлять самим и если связь двунаправленная, то всегда используем mappedBy. Если мы хотим получить коллекцию Bid-ов, то делаем запрос к базе и получаем его.

Свойство CascadeType.ALL (есть еще INSERT, UPDATE, DELETE, ALL включает в себя все три каскада). Это означает каскадное обновление записей в базе данных.

CascadeType.INSERT - означает, что когда мы сохраняем объект Item, автоматически сохраняться все Bid-ы, которые мы в него добавили. Здесь получается, что мы делаем отдельно сохранения для Bid-ов и для Item-ов.
CascadeType.UPDATE - обновили объект Item и по каскаду обновляются все его Bid-ы или что-то изменили в Bid-е, то это опять по каскаду будет обновляться.

CascadeType.DELETE - если удаляем Item, то из базы удаляются все его Bid-ы.

10. Ассоциация один-к-одному

Когда один объект ссылается на другой объект и когда этот второй объект не является компонентом. Если хочется сделать так, чтобы каждый объект сохранялся в свою таблицу, а не все в одну. Есть один объект, есть второй и между ними связь один-к-одному.

Здесь используем аннотацию @OneToOne.

Здесь есть свои хитрости. Как сделать связь один-к-одному? У нас есть одна таблица и вторая. Как связать два ряда этих таблиц один-к-одному?

Есть две стратегии:

Связывание по первичному ключу. Первичный ключ в одном объекте соответствует первичному ключу в другом объекте. Это сложная ассоциация и управлять ею тоже не просто.

@OneToOne

@PrimaryKeyJoinColumn

Проще сделать, если мы в одной из таблиц создадим foreign key на другой первичный ключ. С точки зрения базы данных мы сделаем связь многие-к-одному, но с точки зрения объектов это будет один-к-одному.

@OneToOne

@JoinColumn(name = 'STAT_ID')

То есть в таблице Item (имя класса) создастся колонка STAT_ID, который будет ссылаться на Primary Key другого класса - таблицы. Можно еще через @JoinTable, но лучше без него.

11. Списки. Отображение списка один-ко-многим

Что если нам нужно отобразить список объектов? Чем список отличается от коллекции и от наборов в Java? Списки упорядоченный набор данных (get(index)). В Set набор не упорядоченный, но дубликатов там быть не может. Коллекции более гибкий тип данных.

По умолчанию в JPA запросы возвращают List, элементы которого упорядочены по id базы данных, либо вообще могут быть не упорядочены.

Что если нам нужно хранить индексы? Например, у нас есть электронный опросник, вопросы должны находится в строго заданных местах. Когда мы их добавляем в базу, то им присваиваются id, если это так, то вам повезло. А что если они назначаются не последовательно?

Когда мы их вытащим из базы, то они могут быть перепутаны. В данном случае нужно применить структуру данных именно List. В позицию 0 - такой-то объект 1 - другой и т.д. Вопрос: как их сохранить в базу, чтобы каждый объект был на своей позиции? В JPA нет способа сохранения всего этого в базу. Нужно использовать примочку Hibernate.

import org.hibernate.annotations.IndexColumn

public class Item {

@OneToMany

@IndexColumn(name = "BID_POSITION") указывается над списком Bid-ов.

Private List<Bid> bids;

Hibernate в классе Bid создаст дополнительную колонку и назовет ее BID_POSITION и там будет сохранять позиции элемента в списке. По сути, когда все будет доставаться, то сортировка будет по этой колонке, и мы будем получать список, где каждый элемент будет находиться в строго заданной позиции.

12. Отображение набора простых элементов

У нас есть класс Item и вместе с ним мы хотим хранить несколько картинок. Картинку сохраним на сервере, а путь поместим в базу.

Ставим Hibernate аннотацию @CollectionOfElements, а затем JPA аннотацию @JoinTable и @JoinColumn (по каким колонкам она будет соединяться).

Hibernate создаст две разные таблицы:

1 - Item.

2 - ITEM_IMAGE и в этой таблице будет всего два поля: ITEM_ID и String images. Причем эти два поля сделаются первичными ключами, чтобы они никогда не дублировались. Когда мы будет сохранять Item, то данные будут вноситься туда, когда будет доставать Item, то данные будут браться из этой таблицы. Тут даже каскады прописывать не нужно, они будут делаться автоматически.

То есть когда мы имеем связи между сущностями, то используем JPA аннотации типа @OneToMany, а когда используем связи, вроде как, обычных классов, то нужно использовать @CollectionOfElements.

Даже когда у нас есть коллекция компонентов (Embedded classes). Например, у нас есть Person, у него есть Adress. Если у него один адрес, то это стандартный embedded класс - эту ситуацию мы уже обсуждали. Что если у Person несколько адресов и мы не хотим делать адрес отдельной сущностью, а сделать как компонент? В данном случае только Hibernate позволит сохранить нам набор компонентов через @CollectionOfElements.

13. Ассоциация многие ко многим

Самая сложная ассоциация. Представим, у нас есть категория и у нас есть элемент. Элемент может находиться во многих категориях и в каждой категории может быть много элементов. В любом случае, будет создана отдельная таблица CATEGORY, будет создана таблица ITEM, а также дополнительная таблица, которая будет их соединять CATEGORY_ITEM.

Ассоциация многие-ко-многим. Однонаправленная связь

В категории мы имеем список элементов и над ними указываем @ManyToMany и дальше через аннотацию @JoinTable надо прописать нашу дополнительную таблицу. CAT_ITEM - связующая таблица. InverseJoinColumn - кто будет находиться с другой стороны. JoinColumn можно не указывать и тогда Hibernate все сделает за вас.

Ассоциация многие-ко-многим. Двунаправленная связь

14. Отображение наследования

Возможны следующие варианты шаблонов для отображения наследования:

таблица для конкретного класса с неявным полиморфизмом

таблица для конкретного класса с объединениями

таблица для иерархии классов

таблица для каждого подкласса

У нас есть супер класс BillingDetails в котором храниться пользователь, его персональный счет и дата создания. От этого класса наследуются два других класса: CreditCard и BankAccount. У каждого свои поля.

Каждый из шаблонов представленных ранее имеют свои преимущества и недостатки.

Шаблон «Таблица для конкретного класса»

Представляет иерархию наследования классов, используя по одной таблице для каждого конкретного класса этой иерархии.

Преимущества:

каждая таблица замкнутая и не содержит ненужных полей. То есть у нас нет первичных полей, у нас все поля относятся к конкретному объекту. Получается, что когда нам нужно выбрать объект CreditCard мы получаем список всех его полей. Hibernate инициализирует список своих полей, полей супер класса, если хотим, то используем его как супер класс, как отдельный объект. То есть мы одним запросом получаем наши собственные поля и в таблице нет ничего лишнего. Получается, что при доступе к классу мы получаем доступ к конкретной таблице. Если нам нужно сделать блокировку на запись, то мы делаем это для одной таблицы. Получается, что мы можем параллельно изменять информацию визитной карточки и информацию BankAccount, и можно параллельно менять эти две записи. Одна блокировка в одном месте, другая в другом: они не зависимы друг от друга.

при считывании данных не нужно выполнять соединений

доступ к таблице только в случае доступа к конкретному классу

Недостатки:

сложность реализации полиморфных связей, запросов, навигации. Это самый большой недостаток. Представим, что какой-нибудь другой класс, например, User. User ссылается на BillingDetails: получается полиморфная связь. Суть: выбрать все BillingDetails для конкретного пользователя. Сначала выполняем запрос к CreditCard, затем к BankAccount. Мы собираем всю информацию с этих таблиц, и по сути нам нужны только первые три поля. Получается, когда мы делаем полиморфный запрос, то выполняется несколько запросов для каждого нашего подкласса. Также если мы обращаемся к BillingDetails, то автоматически будет обращение ко всем нижестоящим классам.

изменение полей суперклассов требует изменения нескольких таблиц. Если мы начинаем менять поля суперкласса, то приходится эти поля менять в каждой из таблиц. Мы меняем структуру каждой таблицы. Изменение одной таблицы ведет к изменению других таблиц.

В данном случае иерархия классов в базе данных представляется таким образом, что для каждого конкретного класса создается своя таблица и в эту таблицу перегоняются все собственные поля и все поля верхних классов (родителей). То есть для каждого не абстрактного класса создаем свою таблицу.

У нас есть три объекта и в базе мы получим две таблицы CREDIT_CARD, BANK_ACCOUNT. В каждой таблице будут дублироваться поля, которые мы взяли у супер класса и дальше будут собственные поля. Это самый простой способ реализации наследования.

Такой шаблон рекомендуют использовать для самой верхушки иерархии. Так как эти абстрактные классы редко когда меняются, полиморфные запросы к ним обычно не делаются, к нижним да, а к верхним обычно нет.

Пример, класс DomainObject, содержит только одно поле - id и от этого класса наследуются все Entity. Id присутствует в каждой таблице как и в супер классе. Это по сути наш шаблон. Почему он здесь использован? Полиморфные запросы мы здесь вряд ли будет делать, нам вряд ли нужно будет получать все DomainObject. Зачем? Нам нужно получить либо все категории, всех пользователей и DomainObject-ты нам вряд ли когда понадобятся. Плюс, в DomainObject других полей вставлять тоже не будем.

В JPA есть две реализации этого шаблона.

Таблица для конкретного класса с неявным полиморфизмом

Если мы ставим аннотацию @MappedSuperclass, то все подклассы будут иметь поля суперкласса, их даже не нужно прописывать.

То есть если будет полиморфный запрос, то будут делаться запросы к подклассам.

Таблица для конкретного класса с объединениями

Структура таблиц такая же. При полиморфных запросах Hibernate будет использовать SQL операцию UNION и только один SELECT. За один UNION мы получим полиморфный ответ объект. Но остается проблема навигации, то есть когда мы получим доступ к конкретному BillingDetails Hibernate нужно будет сделать дополнительный запрос, узнавая к какому же он классу относится и вытащить дополнительные поля. То есть, проблема с навигацией остается, проблема с изменением схемы данных при добавлении новых полей тоже остается, но зато полиморфизм немного улучшаем.

Шаблон «Таблица для иерархии классов»

Представляет иерархию наследования классов в виде одной таблицы, столбцы которой соответствуют всем полям классов, входящих в иерархию.

Преимущества:

в структуру базы данных добавляется только одна таблица.

для извлечения данных не нужно выполнять соединение (объединений). Извлечение данных происходит очень быстро.

изменение полей суперклассов и подклассов НЕ требует изменения нескольких таблиц. Если мы начнем перемещать поля из суперкласса в другое место, то схема базы все равно не меняется. При добавлении поля изменения вносятся только в одну таблицу.

Недостатки:

Проблема NOT-NULL полей. Когда мы в таблицу сохраняем BankAccount, что делать с полями, которые относятся к визитной карточке? Поля ведь остаются пустыми. А что если по логике приложения, в полях не должно быть NULL, например, номер кредитной карты всегда должен существовать.

Проблемы параллельного считывания и блокировок. Соответственно, когда мы захотим изменить информацию о BankAccount мы блокируем информацию о кредитной карте и никто ее видеть не сможет.

Пустое место в неиспользуемых столбцах. Пустое место, оно все равно есть и при больших объемах работы могут возникнуть трудности. База разрастается из-за пустого места.

В предыдущем шаблоне, на каждый класс была таблица, здесь одна таблица на всю иерархию. Здесь создается одна таблица и в ней перечисляются все поля (супер класса и подклассов). То есть одна большая таблица с множеством колонок.

Применять этот шаблон лучше там, где маленькая иерархия классов (максимум 3). Когда в наших подклассах храниться очень мало полей. Максимум полей выносим в суперкласс, а в подклассах по одному. Плюс здесь в скорости.

Для этого шаблона, так как одна таблица, нужно хранить информацию о том, какие колонки к какому классу относятся.

Дополнительная колонка которая будет отвечать что и куда называется Discriminator.

Шаблон «Таблица для каждого подкласса»

Представляет иерархию наследования классов, используя по одной таблице для каждого класса (абстрактных в том числе).

Преимущества:

простая взаимосвязь между моделью домена и схемой БД

простота реализации полиморфных связей, запросов

таблицы не занимают лишнего места

реляционная модель полностью нормализована

Недостатки:

загрузка объектов требует соединения таблиц

перемещение полей из подкласса в суперкласс требует изменения структуры БД

частый доступ к таблицам суперклассов

Создается BillingDetails с полями, и по таблице для CREDIT_CARD и BANK_ACCOUNT (в них хранятся только их собственные поля). Первичные ключи этих таблиц будут ссылаться на первичный ключ BillingDetails. Связь здесь происходит по первичным ключам.

Мы сохраняем в базу конкретные объекты (абстрактные классы ведь не хранятся). Поэтому сохраняя BankAccount создается одна запись в BillingDetails и одна запись в BankAccount. То есть мы можем по первичному ключу их соединить.

Подытожим.

Первый шаблон - таблица для конкретного класса (абстрактные классы не хранятся).

Второй шаблон - таблица на всю иерархию.

Третий шаблон - таблица создается для каждого класса иерархии (даже для абстрактного класса).

Заключение

Например, мы считываем из базы один и тот же ряд, в итоге мы получаем один объект и второй, то есть, из двух разных запросов мы получаем два разных объекта. Представим себе, что в одном из объектов вы изменили информацию: поменяли телефон у пользователя. И пока еще ничего не сохраняли. Возникает вопрос: считать ли эти два объекта одинаковыми или нет? Если их сравнивать двумя равно, то объекты получаться разными (разные области памяти). Метод equals - смотря на то как мы его реализуем. Если начнем сравнивать логическую структуру объектов, то они опять будут разными, так как у них поменялось одно поле. Вопрос: как реализовать сравнение этих двух объектов? Ответ: суррогатный ключ. Никакого отношения к объекту этот ключ не должен иметь, его будет использовать только база данных. Тогда метод equals мы реализуем таким образом чтобы он сравнивал только этот ключ. Получается, что если ключ равен, то эти объекты одинаковые. Даже если в объектах будут меняться данные относящиеся к бизнес логике, например телефон, то при сравнении методом equals эти объекты будут равными.

Размещено на Allbest.ru


Подобные документы

  • Понятие объектов конфигурации как составных элементов, из которых складывается прикладное решение. Состав основных объектов конфигурации, поддерживаемых технологической платформой "1С: Предприятие", и их характеристика. Анализ свойств конфигурации.

    презентация [1,9 M], добавлен 12.06.2013

  • Описание компонентов сети конфиденциальной связи. Система распределения ключей на основе линейных преобразований. Описание разработанных программ. Криптостойкость алгоритма распределения ключей. Алгоритм шифрования данных в режиме обратной связи.

    курсовая работа [98,3 K], добавлен 26.09.2012

  • Учет оказываемых услуг в стоматологической клинике. Автоматизация бизнес-процессов. Технологическая платформа "1С: Предприятие". Описание конфигурации, объектов метаданных. Отображение процесса ввода данных и формирования документов. Регистры бухгалтерии.

    дипломная работа [1,9 M], добавлен 17.11.2015

  • Структура UDP пакета, максимальный размер сообщения. Структурно-функциональная схема программы, шифрование с открытым ключом. Главное окно программы, тестирование. Отображение после обновления ника, отображение при создании защищённого соединения.

    курсовая работа [843,9 K], добавлен 15.08.2012

  • Рассмотрение основных способов идентификации объектов: реккурентного; с использованием степенных полиномов; ортогональных полиномов Чебышева; методом наименьших квадратов для авторегрессионной модели. Алгоритм построения простых диагностических тестов.

    курсовая работа [1,9 M], добавлен 14.06.2012

  • Задача зеркального отражения изображения как одна из подзадач многих программ. Анализ создания программы, выполняющей зеркальное отображение изображения, который хранится в файле формата .pcx (256 цветов). Проектирование пользовательского интерфейса.

    курсовая работа [625,6 K], добавлен 17.05.2013

  • Представление о системе AutoCAD 2000, созданной фирмой Autodesk, ее назначение, запуск и графический интерфейс. Использование меню программы и технология работы с ее командами. Ввод и отображение значений координат. Управление изображением на экране.

    курсовая работа [1,3 M], добавлен 22.09.2011

  • Глобальные системы координат GDI. Отображение основных графических объектов. Основные и дополнительные средства для рисования линий. Растровые изображения и метафайлы. Обзор и создание зависимых и независимых от графического устройства битмапов.

    лекция [498,8 K], добавлен 24.06.2009

  • Группа критических и некритических работ в проекте. Установление связей и длительности работ. Оформление графика задач. Отображение на диаграмме критического пути. Отображение диаграммы Ганта с применением форматирования. Создание структуры проекта.

    лабораторная работа [326,5 K], добавлен 07.12.2013

  • Особенности работы "поисковика" дублирующихся файлов на диске. Выбор среды программирования. Разработка программного продукта. Основные требования, предъявляемые к программе, производящей поиск дублирующихся файлов на диске. Отображение скрытых файлов.

    курсовая работа [1,8 M], добавлен 28.03.2015

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.