В мире реляционных баз данных
существуют четыре типа связей,
которые так же имеют место быть и в hibernate.
Перечислим их:
1. One-to-one - Один
к одному
2. Many-to-one -
Многие к одному.
3. One-to-many - Один
ко многим.
4. Many-to-many -
Многие ко многим.
Если связь представлена в одном направлении
между двумя сущностями, т. е. только из
одной сущности можно получить зависимые
объекты, то такая связь называется, однонаправленной ассоциацией (Unidirectional Association). Если из любой сущности можно получить
зависимые объекты, то такая связь называется двунаправленной (Bidirectional Association). Эта и последующие главы будут представлены
как описание кратких и законченных шаблонов примеров, результаты выполнения этих примеров будут представлять или схему базы данных
которая подходит под описание конкретного примера или sql запросы которые генерирует hibernate. И так давайте приступим к рассмотрению самой простой связи один к одному. Пусть у нас есть сущность Event, дата рождения, событие которое может произойти один раз в жизни у каждого человека, описанного сущностью Person. Связь Person(one) -> Event(one) однонаправленная, описывается через аннотацию @OneToOne() в сущности Person, связываем через foreign-key две таблицы, поможет нам в этом аннотация @JoinColumn(name = "idF",referencedColumnName = "idE1"), где name = "idF" – имя поля в таблице Prersons, referencedColumnName = "idE1" – имя поля на которое ссылаемся в таблице Events:
которая подходит под описание конкретного примера или sql запросы которые генерирует hibernate. И так давайте приступим к рассмотрению самой простой связи один к одному. Пусть у нас есть сущность Event, дата рождения, событие которое может произойти один раз в жизни у каждого человека, описанного сущностью Person. Связь Person(one) -> Event(one) однонаправленная, описывается через аннотацию @OneToOne() в сущности Person, связываем через foreign-key две таблицы, поможет нам в этом аннотация @JoinColumn(name = "idF",referencedColumnName = "idE1"), где name = "idF" – имя поля в таблице Prersons, referencedColumnName = "idE1" – имя поля на которое ссылаемся в таблице Events:
@Entity @Table(name="Events")
public class Event {
@Id @GeneratedValue(strategy =
GenerationType.IDENTITY)
private long idE;
@Temporal(value =
TemporalType.TIMESTAMP)
private Date birthDate;
…
}
@Entity @Table(name = "Prersons")
public class Person implements Serializable {
@Id @GeneratedValue(strategy =
GenerationType.IDENTITY)
private Long idP;
@OneToOne() @JoinColumn(name =
"idF",referencedColumnName = "idE1")
private Event event;
…
}
Доступ к объекту происходит посредством кода person.getEvent().getBirthDate().toString(), при этом генерируется такой sql код:
create table Events (idE1 bigint identity not null, birthDate datetime,
primary key (idE1));
create table Prersons (idP bigint identity not null, MyName
varchar(255), idF bigint, primary key (idP));
alter table Prersons add constraint FKB7BA4BF0A99263A0 foreign key (idF)
references Events;
полный код
можно посмотреть в примере С8. Хотелось бы поговорить еще о двух вещах,
которые нужно вам знать. Первое есть такая аннотация @Fetch(value =
FetchMode.SELECT) которая задает стратегию sql запроса выборки, т.е. как выбрать данные,
одним запросом через join или используя подзапросы выборки select для каждого отдельной сущности, FetchMode.SELECT генерирует
два sql:
select person0_.idP as idP0_0_, person0_.idF as idF0_0_, person0_.MyName
as MyName0_0_ from Prersons person0_ where person0_.idP=?
select event0_.idE1 as idE1_1_0_, event0_.birthDate as birthDate1_0_
from Events event0_ where event0_.idE1=?
FetchMode.JOIN генерирует один sql запрос через outer join:
select person0_.idP as idP0_1_, person0_.idF as idF0_1_, person0_.MyName
as MyName0_1_, event1_.idE1 as idE1_1_0_, event1_.birthDate as birthDate1_0_
from Prersons person0_ left outer join Events event1_ on
person0_.idF=event1_.idE1 where person0_.idP=?
И вторая вещь, о которой нужно упомянуть, все
ассоциации можно сделать “ленивыми”, если к полю применена аннотация OneToOne с
выставленным атрибутом в fetch =
FetchType.LAZY, и стратегия выборки FetchMode.SELECT:
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name =
"idF",referencedColumnName = "idE1")
@Fetch(value = FetchMode. SELECT)
private Event event;
Приступим к следующему примеру, рассмотрим ту же связь
Person1(one) -> Event(one) однонаправленную, которая так же описывается через аннотацию @OneToOne() в сущности Person1. Связываем через primary key две таблицы, поможет нам в
этом аннотация @PrimaryKeyJoinColumn(name = "idP",referencedColumnName = "idE1"), где name = "idP" – имя primary
key поля в таблице
Prersons1,
referencedColumnName = "idE1"
– имя primary key
поля
на которое ссылаемся в таблице Events:
@Entity @Table(name = "Persons1")
public class Person1 {
@Id @GeneratedValue(strategy =
GenerationType.IDENTITY)
private Long idP;
@OneToOne(fetch =
FetchType.LAZY) @Fetch(value = FetchMode.SELECT)
@PrimaryKeyJoinColumn(name =
"idP",referencedColumnName = "idE1")
private Event event;
…
при этом генерируется такая схема:
create table Events (idE1 bigint identity not null, birthDate datetime,
primary key (idE1));
create table Prersons1 (idP bigint identity not null, MyName
varchar(255), primary key (idP));
Следующий пример, рассматриваем ту же связь one-to-one, но связаны сущности через таблицу связи (join table) Persons2Events , описать такую связь помогает нам аннотация @JoinTable( name = "Persons2Events" , joinColumns=
@JoinColumn(name = "idP2"), inverseJoinColumns = @JoinColumn(name =
"idE2") ) , где имя таблицы описывается в атрибуте name =
"Persons2Events", и два поля связи "idP2" и "idE2" посредством которых связываются две сущности:
@Entity @Table(name = "Persons2")
public class Person2 implements Serializable{
@Id @GeneratedValue(strategy =
GenerationType.IDENTITY)
private Long idP;
@OneToOne(fetch =
FetchType.LAZY) @Fetch(value = FetchMode.SELECT)
@JoinTable(name =
"Persons2Events"
,joinColumns= @JoinColumn(name
= "idP2")
,inverseJoinColumns =
@JoinColumn(name = "idE2"))
private Event event;
…
При этом формируются такие три таблицы и два
ключа foreign key:
create table Events (idE1 bigint identity not null, birthDate datetime,
primary key (idE1);
create table Persons2 (idP bigint identity not null, MyName
varchar(255), primary key (idP));
create table Persons2Events (idE2 bigint, idP2 bigint not null, primary
key (idP2));
alter table Persons2Events add constraint FK1BA3CA8DA9C20BBD foreign key
(idE2) references Events;
alter table Persons2Events add constraint FK1BA3CA8DB25E3F35 foreign key
(idP2) references Persons2;
Двунаправленная связь (Bidirectional
Association), имеет место быть искусственно
создано только в ORM, и Hibernate
не исключение, он поддерживает такие
связи но, в реляционных базах данных, стандартом такое не предусмотрено. Рассмотрим
следующий пример, связь Person(one) <-> Event(one) через foreign-key, сущность Person3
осталось неизменной приведем её:
@Entity @Table(name = "Persons3")
public class Person3 implements Serializable {
@Id @GeneratedValue(strategy =
GenerationType.IDENTITY)
private Long idP;
@OneToOne(fetch =
FetchType.LAZY) @JoinColumn(name = "idF",referencedColumnName =
"idE1")
@Fetch(value =
FetchMode.SELECT)
private Event3 event3;
…
Для получения обратной связи нужно в сущности Event3 объявить
переменную типа Person3 с
аннотацией @OneToOne(mappedBy = "event3"), где атрибутом mappedBy
описываем обратную связь к полю "event3"
сущности Person3:
@Entity @Table(name="Events3")
public class Event3 {
@Id @GeneratedValue(strategy =
GenerationType.IDENTITY)
@Column(name =
"idE1")
private long idE;
@OneToOne(mappedBy =
"event3")
private Person3 person3;
….
Комментариев нет:
Отправить комментарий