470 likes | 650 Views
Объектно-реляционный мэпинг. 1. Обзор. Аннотации. Виды аннотаций Доступ к состоянию сущности Мэпинг сущности на таблицу Мэпинг простых типов Мэпинг первичного ключа Генерация первичных ключей Отношения. Определения Виды ассоциаций Many-to-one мэпинг One-to-one мэпинг
E N D
Обзор • Аннотации. Виды аннотаций • Доступ к состоянию сущности • Мэпинг сущности на таблицу • Мэпинг простых типов • Мэпинг первичного ключа • Генерация первичных ключей • Отношения. Определения • Виды ассоциаций • Many-to-one мэпинг • One-to-one мэпинг • One-to-Many мэпинг • Many-to-Many мэпинг • Join таблица • Однонаправленные collection-valued мэпинги • Использование коллекций • Lazy загрузка 2
Аннотации • Могут быть определены на уровне • Класса • Метода • Поля • Выделяются 2 логические группы • Логические аннотации • Физические аннотации 3
Доступ к состоянию сущности • Аннотация может быть определена на: • Поле • Методе (провайдер будет использовать метод по умолчанию) • Для доступа используется механизм Java Reflection 4
Аннотирование поля • Модификатор доступа: • protected, package, private. Неpublic • Getter и Setter игнорируются @Entity public class Employee { @Id private int id; //Не! Будет вызван провайдером public int getId() { return id; } public void setId(int id) { this.id = id; } .... 5
Аннотирование метода • Аннотируется getter • Видимость public или protected • Setter обязан присутствовать • Getter и setter должны удовлетворять соглашению JavaBeans • Если аннотация не указана, getter (не поле) будет использован провайдером @Entity public class Employee { private int id; private long wage; @Id public int getId() { return id; } public void setId(int id) { this.id = id; } public long getSalary() { return wage; } public void setSalary(long salary) { this.wage = salary; } 6
Мэпинг сущности на таблицу • @Entity определяет сущность. Обязательное поле • Название таблицы по умолчанию – имя класса • @Table(name=“EMP”, schema=“HR”, catalog=“HR.EMP” @Entity @Table(name="EMP", schema="HR") public class Employee { … } 7
Мэппинг простых типов • Поля следующих типов могут быть persisted провайдером: • Primitive Java types: byte, int, short, long, boolean, char, float, double • Wrapper classes of primitive Java types: Byte, Integer, Short, Long, Boolean, Character, Float, Double • Byte and character array types: byte[], Byte[], char[], Character[] • Large numeric types: java.math.BigInteger, java.math.BigDecimal • Strings: java.lang.String • Java temporal types: java.util.Date, java.util.Calendar • JDBC temporal types: java.sql.Date, java.sql.Time, java.sql.Timestamp • Enumerated types: Any system or user-defined enumerated type • Serializable objects: Any system or user-defined serializable type • Опциональная аннотация @Basic может использоваться для объявления поля persisted @Entity public class Employee { ... @Basic private String name; 8
Указание физического мэпинга простого типа • В дополнение к логической аннотации @Basic существует: • физическая @Column(name=“Name”); 9
Большие объекты (LOB) • Для доступа к LOB приложение должно сделать специальный вызов через JDBC • @Lob аннотация для того, чтобы указать провайдеру, что работаем с LOB • Java типы, которые мэпятся на BLOB поля в БД: • Byte[] • byte[] • Serializable объекты • @Basic и @Column опциональны 10
Мэпинг Java Enums • В БД хранится информация, позволяющая восстановить значение перечисления • Два способа хранения enum: • EnumType.STRING сохраняет строковое представление перечисления • EnumType.ORDINAL сохраняет порядковый номер перечисления 12
Transient поля • Для указания, что атрибут не persisted служит: • Аннотация @Transient • Ключевое слово transient • Поле не будет persisted, если на нем нет persisted аннотации (@Basic) или если оно не является атрибутом с правильным типом данных 13
Мэпинг первичного ключа • Каждая сущность должна иметь мэпинг первичного ключа в БД • Атрибут одного из следующих типов может быть первичным ключом: • Primitive Java types: byte, int, short, long, char • Wrapper classes of primitive Java types: Byte, Integer, Short, Long, Character • Arrays of primitive or wrapper types: Byte, Integer, Short, Long, Character • Strings: java.lang.String • Large numeric types: java.math.BigInteger • Temporal types: java.util.Date, java.sql.Date • @Column может использоваться точно так же как и при мэпинге прочих полей 14
Генерация первичных ключей • Существует 4 способа генерации ключей: • AUTO • TABLE • SEQUENCE • IDENTITY • Приложение не может закладываться на использование сгенерированного ключа до момента сохранения сущности • Для разных сущностей могут быть использованы разные стратегии генерации ключа 15
Генерация первичных ключей AUTO • Фактический способ генерации провайдер выбирает сам • Таблица или последовательность все-таки нужна • Лучше использовать для development стадии • Способ генерации по умолчанию 16
Генерация первичных ключей TABLE • Наиболее переносимый подход • Полный пример: 17
Генерация первичных ключей SEQUENCE • Не переносимый способ генерации. БД должна поддерживать объект последовательность (Oracle) 18
Генерация первичных ключей IDENTITY • Не переносимый способ генерации. БД должна поддерживать авто генерацию ключа (My SQL) • После автогенерации ключа провайдеру может потребоваться SELECT, чтобы выбрать это значение @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int id; 19
Отношения. Определения • В каждом отношении участвуют две сущности. Каждая из них выполняет роль (role) • Одна и та же сущность может играть разные роли в разных отношениях • Сущность может ссылаться на сущность, играющую противоположную роль в отношении. Эта ссылка называется направленность (directionality) • Выделяют однонаправленное и бинаправленное отношение 20
Отношения. Определения • Удобно думать о каждом двунаправленном отношении как о паре однонаправленных • Каждое такое отношение имеет сущность, выполняющую ссылающуюся роль. Sourceсущность • Так же имеет сущность, на которую ссылаются. Targetсущность 21
Отношения. Определения • Каждая роль имеет количество элеметнов отношения (cardinality), определяющее может существовать только один экземпляр сущности или много экземпляров Unidirectional many-to-one relationship Bidirectional many-to-many relationship 22
Мэпинг отношений. Обзор • Каждый мэпинг называется исходя из cardinality source и target ролей • Всего может быть 4 комбинации (4 ассоциации) cardinality “one” и “many”: • Many-to-one • One-to-one • One-to-many • Many-to-many 23
Подгруппыассоциаций • Ассоциация, где target роль имеет cardinality oneназывается single-valuedассоциацией. К ним относятся: • Many-to-one • One-to-one • Ассоциация, где target роль имеет cardinality manyназывается collection-valuedассоциацией. К ним относятся: • One-to-Many • Many-to-Many 24
Many-to-one мэпинг (1 из 3) На диаграмме: Employeeэто sourceсущность cardinality many. Departmentэто targetсущность cardinality one. • many-to-one мэпинг определяется аннотированиематрибута source сущности, ссылающегося на target сущность 25
Many-to-one мэппинг (2 из 3) • Foreign key в JPA называется join column • Обозначается физической аннотацией @JoinColumn • Роль, которая имеет join column называетсяowning side • Роль, которая не имеет join column называетсяinverse side 26
Many-to-one мэппинг (3 из 3) • many-to-one мэпинг всегда определяется на owning роли • @JoinColumn(name=“DEPT_ID”) является опциональной. Служит для явного указания вторичного ключа DEPT_ID • По умолчанию ключ будет targetEntityAttribute_ targetEntityID (DEPATRMENT_ID) • По соглашению вначале идет логические аннотации, потом физические 27
One-to-one мэпинг (1 из 2) • Можно определить точно так же как и many-to-one • Со стороны БД единственность target сущности обеспечивается уникальным индексом на foreign ключ 28
Двунаправленный оne-to-one мэпинг (2 из 2) • При one-to-one мэпингеневажно кто является owing стороной, а кто inverse. @JoinColumn может быть определена на любой роли • Inverse роль может однозначно определить owning роль. Это достигается аннотацией @OneToOne(mappedBy=“owningRoleAttribute”) 29
Collection-valuedассоциации • Ассоциация, где target роль имеет cardinality manyназывается collection-valuedассоциацией. К ним относятся: • One-to-Many • Many-to-Many 30
One-to-Many мэпинг (1 из 2) • Когда source сущность имеет произвольное количество target сущностей, нет способа определить ключи target сущности в source сущности • Поэтому пользуемся foreign ключами target сущности для ссылки назад к source сущности • Таким образом, мэпинг many-to-one обратного направления должен быть определен • Таким образом, one-to-manyмэпинг всегдадвунаправленный 31
One-to-Many мэпинг (2 из 2) • На inverse роли определяем элемент mappedBy. Его значением является имя атрибута target роли • Элемент targetEntityуказывает класс target роли. Эта роль является owning стороной (содержит @JoinColumn)отношения • Вывод: • many-to-one роль является owning, поэтому join column определяется на этой стороне • one-to-many роль является inverse, поэтому mappedBy элемент должен использоваться на этой стороне 32
Many-to-Many мэпинг • Каждая роль отношения имеет collection-valued ассоциацию, которая содержит targetсущности • Определяется указанием аннотации @ManyToManyодновременно на source и target сущностях • Join колонка отсутствует и на source и на target • Следовательно нельзя формально выделить owning сущность • Любая сущность может быть принята за owning. В этом случае противоположная будет inverse и должна содержать элемент mappedByна owning сущность 33
Join таблица • Чтобы ассоциировать сущности в many-to-many отношении всегда необходима join таблица • EMP_PROJ содержит только первичные ключи соединяемых сущностей. Они образуют compound ключ join таблицы • Для определения owing сущности, а так же конфигурации join таблицы служит аннотация @JoinTable • @JoinTableопциональна. В случае отсутствия аннотации, провайдер сделает предположения о наименовании join таблица и foreign ключей соединяемых сущностей 35
Пример 36
Однонаправленные collection-valued мэпинги • Когда сущность имеетаннотацию @OneToMany, но не указан элемент mappedBy, провайдер предполагает однонаправленное отношение с target сущностью • В этом случае всегда предполагаетсяиспользование join таблицы 37
Пример. Однонаправленный OneToMany мэпинг 38
Использование различных коллекций • При работе с collection-valued ассоциациями могут использоваться следующие интерфейсы: • Collection • Set • List • Map • Должен указываться интерфейс (не конкретный класс), так как провайдер может подменить имплементацию коллекции 39
Использование Collection,Set и List • Collection наиболее общий интерфейс, когда неважно, какая имплементация реально используется провайдером • Set не позволит работать с дублирующимися сущностями • List обеспечит некоторый порядок, который задается с помощью аннотации @OrderBy 40
Использование List (продолжение) • Значением аннотации является набор атрибутов, по которым проводится сортировка • @OrderBy("status DESC, name ASC") • Для каждого атрибута может указываться порядок сортировки (ASC или DESC). ASC по умолчанию • Если в аннотации @OrderBy ни один атрибут не указывается, то сущности сортируются по первичному ключу • Если @OrderBy не указан, сущности не сортируются • Порядок не сохраняется при вставке списка в БД 41
Использование Map • Удобно хранить коллекцию значений в карте (Map), в качестве ключа используя какой-либо атрибут target сущности • Этот ключевой атрибут должен: • Быть persistent атрибутом • Корректно переопределять hashCode() и equals() • Быть уникальным. По крайней мере в данной выборке • Для указания ключевого атрибута используется @MapKey(name=“attribute”) • Если атрибут не указан, мэпинг будет осуществляться по ключевому атрибуту 43
Lazy загрузка (Lazy Fetching) • Значение атрибута FetchType указывает провайдеру на необходимость немедленной подгрузки данных (EAGER) или отложенной (LAZY) • Lazy fetching является только подсказкой провайдеру • Почти всегда не целесообразно указывать lazy загрузку простым типам. • Для простых типов по умолчанию используется EAGER • Напротив lazy загрузка может иметь большую роль в производительности системы при загрузке отношений 45
Lazy загрузка отношений • Для single-valued отношений по умолчанию используется EAGER загрузка • Для collection-valued отношений по умолчанию используется LAZY загрузка • В двунаправленных отношениях одна сторона может использовать EAGER загрузку, другая - LAZY 46
Обзор • Аннотации. Виды аннотаций • Доступ к состоянию сущности • Мэпинг сущности на таблицу • Мэпинг простых типов • Мэпинг первичного ключа • Генерация первичных ключей • Отношения. Определения • Виды ассоциаций • Many-to-one мэпинг • One-to-one мэпинг • One-to-Many мэпинг • Many-to-Many мэпинг • Join таблица • Однонаправленные collection-valued мэпинги • Использование коллекций • Lazy загрузка 47