2.1 Таблицалар деңгээлинде байланыштыруу
Hibernate'тин коллекцияларды коштоочу таблицаларда кантип сактай тургандыгы менен тааныштык. Эми толук кандуу таблицаларда, чыныгы Entity-класстарды сактаган таблицаларда байланышты кантип уюштурууну карап чыгабыз.
Entity-класстар ортосунда Hibernate'те төрт түрдүү мамиле бар:
- one-to-one
- one-to-many
- many-to-one
- many-to-many
Биз эң жөнөкөй вариантыңан баштайбыз – many-to-one.
SQL таблицалары ортосундагы мындай мамилеге сен буга чейин кезигип калдың. Бул адатта мындай көрүнөт:
id | name | occupation | salary | age | join_date |
---|---|---|---|---|---|
1 | Иванов Иван | Программист | 100000 | 25 | 2012-06-30 |
2 | Петров Петр | Программист | 80000 | 23 | 2013-08-12 |
3 | Иванов Сергей | Тестировщик | 40000 | 30 | 2014-01-01 |
4 | Рабинович Мойша | Директор | 200000 | 35 | 2015-05-12 |
5 | Кириенко Анастасия | Офис-менеджер | 40000 | 25 | 2015-10-10 |
6 | Васька | Кот | 1000 | 3 | 2018-11-11 |
employee таблицасы:
Бул таблицада мындай колонкалар бар:
- id INT
- name VARCHAR
- occupation VARCHAR
- salary INT
- age INT
- join_date DATE
Ал эми мындай көрүнөт task таблицасы, ал кызматкерлерге арналган тапшырмаларды камтыйт:
id | employee_id | name | deadline |
---|---|---|---|
1 | 1 | Фронтендтеги баганы оңдоо | 2022-06-01 |
2 | 2 | Бэкендтеги баганы оңдоо | 2022-06-15 |
3 | 5 | Кофе сатып алуу | 2022-07-01 |
4 | 5 | Кофе сатып алуу | 2022-08-01 |
5 | 5 | Кофе сатып алуу | 2022-09-01 |
6 | (NULL) | Офисти тазалоо | (NULL) |
7 | 4 | Жашоодон ырахат алуу | (NULL) |
8 | 6 | Жашоодон ырахат алуу | (NULL) |
Бул таблицада болгону 4 колонка бар:
- id – тапшырманын уникалдуу номери (жана таблицадагы катар);
- employee_id – employee таблицасындагы кызматкердин ID, тапшырма ага таандык;
- name – тапшырманын аталышы жана сүрөттөлүшү;
- deadline – тапшырманы аткаруу үчүн берилген убакыт.
Биз көрүп турабыз, task таблицасындагы көптөгөн катарлар employee таблицасындагы бир жазууга шилтеме жасай алышат. Таблицалар деңгээлинде мындай байланыш көптөн-бирге (many-to-one) деп аталат.
2.2 Java-класстар деңгээлинде байланыштыруу
Таблицалар деңгээлинде байланыштыруу менен кошо, Hibernate'те Entity-класстар деңгээлинде дагы байланыштырып уюштурууга болот. Бул @ManyToOne
аннотациясы аркылуу жасалат.
Бирок башында жөн гана эки класс түзүп алабыз: Employee жана EmployeeTask:
@Entity @Table(name="employee")
class Employee {
@Column(name="id")
public Integer id;
@Column(name="name")
public String name;
@Column(name="occupation")
public String occupation;
@Column(name="salary")
public Integer salary;
@Column(name="join_date")
public Date join;
}
Ал эми кызматкерлердин тапшырмаларын сактоо үчүн экинчи класс:
@Entity @Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@Column(name="employee_id")
public Integer employeeId;
@Column(name="deadline")
public Date deadline;
}
Бул класстар менен баары жакшы, бирок алар ортосунда эч кандай байланыш жок, ал кээ бир талаалар бири-бирине шилтеме жасаган фактты чагылдырса болмок. Эми аны оңдоп алабыз.
2.3 @ManyToOne аннотациясы.
Биринчи кезекте, Java'да биз объекттер (жана объекттерге шилтемелер) менен иштешүүгө көнүп калганбыз, алардын id'лери менен эмес. Андыктан, эң биринчи ишибиз EmployeeTask классындагы employeeId талаасынын ордуна, Employee типтеги объектке шилтемени көрсөтөбүз. Биздин жаңы класс ушундай көрүнөт:
@Entity @Table(name="task")
class EmployeeTask {
@Column(name="id")
public Integer id;
@Column(name="name")
public String description;
@ManyToOne @JoinColumn(name = "employee_id")
public Employee employee;
@Column(name="deadline")
public Date deadline;
}
Аннотациясын @ManyToOne
колдонуп, биз көптөгөн EmployeeTask объекттери бир Employee типтеги объектке шилтеме жасай ала турганын көрсөттүк. Ошондой эле аннотациясынын @JoinColumn
жардамы менен Employee объекттеринин id'и таблицанын кайсыл колонкасында сакталарын белгиледик.
2.4 Сурамжылоолор мисалдары
Эми бир нече мисал көрсөтүп берейин, Hibernate мындай байланыштырылган класстар менен кандайча иштей аларын.
Биринчи сценарий
Белгилүү бир колдонуучуга тапшырылган бардык тапшырмаларды билиш үчүн сурам жазалы. Бул кантип HQL'де көрүнөрүн карагыла:
from EmployeeTask where employee.name = "Иван Иванович"
Сен жөн гана такталары класстардын талаалары аркылуу чакырып өтүп кетсең болот. Бул абдан ыңгайлуу. Бирок да сурамды Java-код түрүндө жазып көрөлү:
String hql = "from EmployeeTask where employee.name = :username";
Query<EmployeeTask> query = session.createQuery( hql, EmployeeTask.class);
query.setParameter("username", "Иван Иванович");
List<EmployeeTask> resultLIst = query.list();
Экинчи сценарий
Просроченные тапшырмалары бар кызматкерлердин тизмесин кайтарган сурам жазалы. Эгерде тапшырманын deadline убактысы өткөн болсо, анда ал тапшырма просроченный. Бул сурам SQL'де кантип көрүнөөрүн карагыла:
SELECT DISTINCT employee.*
FROM task JOIN employee ON task.employee_id = employee.id
WHERE task.deadline < CURDATE();
DISTINCT
колдонулат, анткени бир колдонуучуга көп тапшырма берилген болушу мүмкүн.
Эми бул сурамды HQL'де жазалы:
select distinct employee from EmployeeTask where deadline < CURDATE();
Employee сурамында – бул EmployeeTask классынын талаасы
Үчүнчү ситуация
Бардык дайындалбаган тапшырмаларды директорго дайындап койолу. SQL боюнча сурам мындай көрүнөт:
UPDATE task SET employee_id = 4 WHERE employee_id IS NULL
Эми бул сурамды HQL'де жазалы:
update EmployeeTask set employee = :user where employee is null
Акыркы сурам татаалыраак. Бизге директордун ID'ин берүү керек, бирок EmployeeTask классы id жазуу үчүн талаа камтыбайт, анын ордуна Employee объектине шилтеме жасай турган талаа камтыйт.
Employee director = session.get(Employee.class, 4);
String hql = "update EmployeeTask set employee = :user where employee is null";
Query<EmployeeTask> query = session.createQuery(hql, EmployeeTask.class);
query.setParameter("user", director);
query.executeUpdate();
GO TO FULL VERSION