Zamonaviy rivojlanish dunyosi hayotni osonlashtirish uchun mo'ljallangan turli xil xususiyatlarga to'la. Asboblarni bilib, siz to'g'ri tanlashingiz mumkin. Bilmasdan, hayotingizni qiyinlashtirasiz. Ushbu sharh JPA - Java Persistence API kontseptsiyasi ustidan maxfiylik pardasini olib tashlaydi. Umid qilamanki, o'qiganingizdan so'ng siz ushbu sirli dunyoga yanada chuqurroq sho'ng'ishni xohlaysiz.
Kirish
Ma'lumki, dasturlarning asosiy vazifalaridan biri ma'lumotlarni saqlash va qayta ishlashdir. Qadimgi yaxshi kunlarda odamlar shunchaki ma'lumotlarni fayllarda saqlashgan. Ammo bir vaqtning o'zida o'qish va tahrirlash uchun ruxsat zarur bo'lishi bilanoq, yuk bo'lganda (ya'ni, bir vaqtning o'zida bir nechta so'rovlar keladi), ma'lumotlarni oddiygina fayllarda saqlash muammoga aylanadi.
Ma'lumotlar bazasi qanday muammolarni hal qilishi va qanday qilib echilishi haqida ko'proq ma'lumot olish uchun sizga " Ma'lumotlar bazalari qanday tuzilgan " maqolasini o'qishni maslahat beraman . Bu shuni anglatadiki, biz ma'lumotlarimizni ma'lumotlar bazasida saqlashga qaror qildik. Uzoq vaqt davomida Java JDBC API (The Java Database Connectivity) yordamida maʼlumotlar bazalari bilan ishlay oldi. JDBC haqida ko'proq ma'lumotni bu erda o'qishingiz mumkin: "
JDBC yoki hammasi qaerdan boshlanadi ". Ammo vaqt o'tdi va ishlab chiquvchilar har safar ma'lumotlar bazasida Java ob'ektlarini saqlash va aksincha, Java ob'ektlarini yaratish uchun bir xil turdagi va keraksiz "xizmat ko'rsatish" kodini (Boilerplate kodi deb ataladi) yozish zarurligiga duch kelishdi. ma'lumotlar bazasi. Va keyin, bu muammolarni hal qilish uchun ORM kabi tushuncha paydo bo'ldi.
ORM - Ob'ekt bilan bog'liq xaritalash yoki rus tiliga tarjima qilingan ob'ekt bilan bog'liq xaritalash. Bu ma'lumotlar bazalarini ob'ektga yo'naltirilgan dasturlash tillari tushunchalari bilan bog'laydigan dasturlash texnologiyasidir. Soddalashtirish uchun, ORM Java ob'ektlari va ma'lumotlar bazasidagi yozuvlar o'rtasidagi bog'liqlikdir:
ORM mohiyatan Java ob'ekti ma'lumotlar bazasida ma'lumotlar sifatida taqdim etilishi mumkin bo'lgan tushunchadir (va aksincha). U JPA spetsifikatsiyasi - Java Persistence API ko'rinishida mujassamlangan. Spetsifikatsiya allaqachon ushbu kontseptsiyani ifodalovchi Java API tavsifidir. Spetsifikatsiya bizga ORM kontseptsiyasiga muvofiq ishlash uchun qanday vositalar bilan ta'minlanishi kerakligini (ya'ni, qanday interfeyslar orqali ishlashimiz mumkinligini) aytadi. Va bu mablag'lardan qanday foydalanish kerak. Spetsifikatsiya asboblarni amalga oshirishni tavsiflamaydi. Bu bitta spetsifikatsiya uchun turli ilovalardan foydalanish imkonini beradi. Siz uni soddalashtirishingiz va spetsifikatsiya API tavsifi ekanligini aytishingiz mumkin. JPA spetsifikatsiyasining matnini Oracle veb-saytida topish mumkin: "
JSR 338: JavaTM Persistence API ". Shuning uchun, JPA-dan foydalanish uchun biz texnologiyadan foydalanamiz. JPA ilovalari JPA Provayderlari deb ham ataladi. Eng mashhur JPA ilovalaridan biri bu
Hibernate . Shuning uchun men buni ko'rib chiqishni taklif qilaman.
Loyiha yaratish
JPA Java haqida bo'lgani uchun bizga Java loyihasi kerak bo'ladi. Biz o'zimiz katalog tuzilmasini qo'lda yaratishimiz va kerakli kutubxonalarni o'zimiz qo'shishimiz mumkin edi. Ammo loyihalarni yig'ishni avtomatlashtirish tizimlaridan foydalanish ancha qulayroq va to'g'ri (ya'ni, aslida bu biz uchun loyihalarni yig'ishni boshqaradigan dastur. Kataloglar yaratish, sinf yo'liga kerakli kutubxonalarni qo'shish va h.k. .). Shunday tizimlardan biri Gradle. Gradle haqida ko'proq ma'lumotni bu erda o'qishingiz mumkin: "
Gradle haqida qisqacha kirish ". Ma'lumki, Gradle funksionalligi (ya'ni, u qila oladigan narsalar) turli Gradle plaginlari yordamida amalga oshiriladi.
Keling, Gradle va " Gradle Build Init Plugin " plaginidan foydalanamiz . Keling, buyruqni bajaramiz:
gradle init --type java-application
Gradle biz uchun kerakli katalog tuzilmasini amalga oshiradi va qurilish skriptida loyihaning asosiy deklarativ tavsifini yaratadi
build.gradle
. Shunday qilib, bizda ariza bor. Biz ilovamiz bilan nimani tasvirlash yoki modellashtirish haqida o'ylashimiz kerak. Keling, ba'zi modellashtirish vositalaridan foydalanamiz, masalan:
app.quickdatabasediagrams.com Bu erda biz ta'riflagan narsa bizning "domen modelimiz" ekanligini aytish kerak. Domen - bu "mavzu sohasi". Umuman olganda, domen lotincha "egalik" degan ma'noni anglatadi. Oʻrta asrlarda qirollar yoki feodallarga tegishli boʻlgan hududlar shunday nomlangan. Va frantsuz tilida bu "domen" so'ziga aylandi, bu shunchaki "maydon" deb tarjima qilinadi. Shunday qilib, biz "domen modelimiz" = "mavzu modeli" ni tasvirlab berdik. Ushbu modelning har bir elementi haqiqiy hayotdan qandaydir "mohiyat" dir. Bizning holatlarimizda bu ob'ektlar: Turkum (
Category
), Mavzu (
Topic
). Keling, ob'ektlar uchun alohida paket yarataylik, masalan, nom modeli bilan. Keling, u erda ob'ektlarni tavsiflovchi Java sinflarini qo'shamiz. Java kodida bunday ob'ektlar oddiy
POJO bo'lib , u quyidagicha ko'rinishi mumkin:
public class Category {
private Long id;
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Keling, sinf tarkibini ko'chiramiz va analogiya bo'yicha sinf yaratamiz
Topic
. U faqat o'zi tegishli bo'lgan toifa haqida bilgan narsasi bilan farq qiladi.
Topic
Shuning uchun sinfga kategoriya maydoni va u bilan ishlash usullarini qo'shamiz :
private Category category;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
Endi bizda o'z domen modeliga ega Java ilovasi mavjud. Endi JPA loyihasiga ulanishni boshlash vaqti keldi.
JPA qo'shish
Shunday qilib, biz eslaganimizdek, JPA ma'lumotlar bazasida biror narsani saqlashimizni anglatadi. Shuning uchun bizga ma'lumotlar bazasi kerak. Loyihamizda ma'lumotlar bazasi ulanishidan foydalanish uchun biz ma'lumotlar bazasiga ulanish uchun bog'liqlik kutubxonasini qo'shishimiz kerak. Esda tutganimizdek, biz Gradle-dan foydalanganmiz, u biz uchun qurilish skriptini yaratdi
build.gradle
. Unda biz loyihamizga kerak bo'lgan bog'liqliklarni tasvirlab beramiz. Bog'liqlar - bu bizning kodimiz ishlamaydigan kutubxonalar. Keling, ma'lumotlar bazasiga ulanishga bog'liqlik tavsifidan boshlaylik. Agar biz JDBC bilan ishlagan bo'lsak, buni xuddi shunday qilamiz:
dependencies {
implementation 'com.h2database:h2:1.4.199'
Endi bizda ma'lumotlar bazasi mavjud. Endi biz ilovamizga Java obyektlarimizni ma'lumotlar bazasi tushunchalariga (Java'dan SQLgacha) solishtirish uchun mas'ul bo'lgan qatlamni qo'shishimiz mumkin. Esda tutganimizdek, biz buning uchun Hibernate deb nomlangan JPA spetsifikatsiyasining amalga oshirilishidan foydalanmoqchimiz:
dependencies {
implementation 'com.h2database:h2:1.4.199'
implementation 'org.hibernate:hibernate-core:5.4.2.Final'
Endi biz JPA ni sozlashimiz kerak. Agar biz spetsifikatsiyani va "8.1 Doimiylik birligi" bo'limini o'qib chiqsak, biz Persistent birligi konfiguratsiyalar, metama'lumotlar va ob'ektlarning qandaydir kombinatsiyasi ekanligini bilib olamiz. Va JPA ishlashi uchun konfiguratsiya faylida kamida bitta Doimiylik Birligini tavsiflash kerak, bu
persistence.xml
. Uning joylashuvi "8.2 Persistence Unit Packaging" spetsifikatsiya bo'limida tasvirlangan. Ushbu bo'limga ko'ra, agar bizda Java SE muhiti bo'lsa, uni META-INF katalogining ildiziga qo'yishimiz kerak.
Keling, " " bobidagi JPA spetsifikatsiyasida keltirilgan misoldan tarkibni ko'chirib olaylik
8.2.1 persistence.xml file
:
<persistence>
<persistence-unit name="JavaRush">
<description>Persistence Unit For test</description>
<class>hibernate.model.Category</class>
<class>hibernate.model.Topic</class>
</persistence-unit>
</persistence>
Lekin bu yetarli emas. JPA provayderimiz kimligini aytishimiz kerak, ya'ni. JPA spetsifikatsiyasini amalga oshiruvchi:
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
Endi sozlamalarni qo'shamiz (
properties
). Ulardan ba'zilari (dan boshlab
javax.persistence
) standart JPA konfiguratsiyalari bo'lib, JPA spetsifikatsiyasida "8.2.1.9 xususiyatlari" bo'limida tasvirlangan. Ba'zi konfiguratsiyalar provayderga xosdir (bizning holimizda ular Jpa provayderi sifatida Kutish rejimiga ta'sir qiladi. Bizning sozlamalar blokimiz quyidagicha ko'rinadi:
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
Endi bizda JPA-mos keladigan konfiguratsiya mavjud
persistence.xml
, JPA provayderi Hibernate va H2 ma'lumotlar bazasi mavjud, shuningdek, bizning domen modelimiz bo'lgan 2 ta sinf mavjud. Keling, nihoyat, bularning barchasini bajaraylik. Katalogda
/test/java
bizning Gradle birlik testlari uchun shablonni yaratdi va uni AppTest deb nomladi. Keling, undan foydalanaylik. JPA spetsifikatsiyasining "7.1 Doimiylik kontekstlari" bo'limida aytilganidek, JPA dunyosidagi ob'ektlar Doimiylik konteksti deb nomlangan bo'shliqda yashaydi. Lekin biz Persistence Context bilan bevosita ishlamaymiz. Buning uchun biz yoki "ob'ekt menejeri" dan foydalanamiz
Entity Manager
. U kontekst va u erda qanday shaxslar yashashi haqida biladi. Biz
Entity Manager
om bilan muloqot qilamiz. Keyin qolgan narsa buni qaerdan olishimiz mumkinligini tushunishdir
Entity Manager
? JPA spetsifikatsiyasining "7.2.2 Ilova tomonidan boshqariladigan ob'ekt menejerini olish" bo'limiga muvofiq biz dan foydalanishimiz kerak
EntityManagerFactory
. Shuning uchun, keling, JPA spetsifikatsiyasi bilan qurollanamiz va "7.3.2 Java SE muhitida ob'ekt menejeri zavodini olish" bo'limidan misol keltiramiz va uni oddiy birlik testi shaklida formatlaymiz:
@Test
public void shouldStartHibernate() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
EntityManager entityManager = emf.createEntityManager();
}
Bu test allaqachon xatoni ko'rsatadi "Notanish JPA persistence.xml XSD versiyasi". Buning sababi,
persistence.xml
JPA spetsifikatsiyasida "8.3 persistence.xml sxemasi" bo'limida aytilganidek, foydalanish uchun sxemani to'g'ri belgilashingiz kerak:
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">
Bundan tashqari, elementlarning tartibi muhim ahamiyatga ega. Shuning uchun,
provider
sinflarni ro'yxatga olishdan oldin uni ko'rsatish kerak. Shundan so'ng, test muvaffaqiyatli o'tadi. To'g'ridan-to'g'ri JPA ulanishini yakunladik. Davom etishdan oldin, qolgan testlar haqida o'ylab ko'raylik. Bizning har bir testimiz talab qiladi
EntityManager
.
EntityManager
Keling , bajarilish boshida har bir testning o'ziga xos xususiyati borligiga ishonch hosil qilaylik . Bundan tashqari, biz ma'lumotlar bazasi har safar yangi bo'lishini xohlaymiz. Variantdan foydalanganimiz sababli
inmemory
, yopish kifoya
EntityManagerFactory
. Yaratish
Factory
qimmat operatsiya. Ammo sinovlar uchun bu oqlanadi. JUnit sizga har bir testni bajarishdan oldin (oldin) va keyin (keyin) bajariladigan usullarni belgilash imkonini beradi:
public class AppTest {
private EntityManager em;
@Before
public void init() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
em = emf.createEntityManager();
}
@After
public void close() {
em.getEntityManagerFactory().close();
em.close();
}
Endi, har qanday testni o'tkazishdan oldin, yangisi yaratiladi
EntityManagerFactory
, bu yangi ma'lumotlar bazasini yaratishga olib keladi, chunki
hibernate.hbm2ddl.auto
ma'noga ega
create
. Va yangi zavoddan biz yangisini olamiz
EntityManager
.
Ob'ektlar
Esda tutganimizdek, biz ilgari domen modelimizni tavsiflovchi sinflarni yaratgan edik. Biz allaqachon aytgan edik, bu bizning "mohiyatlarimiz". Bu biz boshqaradigan ob'ekt
EntityManager
. Kategoriyaning mohiyatini saqlash uchun oddiy test yozamiz:
@Test
public void shouldPersistCategory() {
Category cat = new Category();
cat.setTitle("new category");
em.persist(cat);
}
Ammo bu test darhol ishlamaydi, chunki ... Biz ob'ektlar nima ekanligini tushunishimizga yordam beradigan turli xil xatolarni olamiz:
-
Unknown entity: hibernate.model.Category
Category
Nega Hibernate bu nima ekanligini tushunmaydi entity
? Gap shundaki, ob'ektlar JPA standartiga muvofiq tavsiflanishi kerak. JPA spetsifikatsiyasining "2.1 Ob'ektlar klassi" bobida aytilganidek,
ob'ektlar sinflari izoh bilan izohlanishi kerak .@Entity
-
No identifier specified for entity: hibernate.model.Category
Tashkilotlar bitta yozuvni boshqasidan ajratish uchun ishlatilishi mumkin bo'lgan noyob identifikatorga ega bo'lishi kerak.
JPA spetsifikatsiyasining "2.4 Asosiy kalitlar va ob'ekt identifikatori" bo'limiga ko'ra, "Har bir ob'ektda birlamchi kalit bo'lishi kerak", ya'ni. Har bir ob'ektda "asosiy kalit" bo'lishi kerak. Bunday asosiy kalit izoh bilan ko'rsatilishi kerak@Id
-
ids for this class must be manually assigned before calling save()
ID biror joydan kelishi kerak. U qo'lda ko'rsatilishi yoki avtomatik ravishda olinishi mumkin.
Shuning uchun, "11.2.3.3 GeneratedValue" va "11.1.20 GeneratedValue Izoh" boblarida ko'rsatilganidek, biz izohni belgilashimiz mumkin @GeneratedValue
.
Shunday qilib, toifa sinfi ob'ekt bo'lishi uchun biz quyidagi o'zgarishlarni amalga oshirishimiz kerak:
@Entity
public class Category {
@Id
@GeneratedValue
private Long id;
Bundan tashqari, izoh
@Id
qaysi birini ishlatishni ko'rsatadi
Access Type
. Kirish turi haqida ko'proq JPA spetsifikatsiyasining "2.3 Kirish turi" bo'limida o'qishingiz mumkin. Qisqacha aytganda, chunki... biz
@Id
yuqorida maydonni (
field
), keyin kirish turi standart bo'ladi
field-based
, emas
property-based
. Shuning uchun JPA provayderi qiymatlarni to'g'ridan-to'g'ri maydonlardan o'qiydi va saqlaydi. Agar biz
@Id
oluvchining ustiga joylashtirsak, u holda
property-based
kirish foydalaniladi, ya'ni. oluvchi va sozlagich orqali. Sinovni o'tkazishda biz ma'lumotlar bazasiga qanday so'rovlar yuborilganligini ham ko'ramiz (variant tufayli
hibernate.show_sql
). Lekin saqlashda biz hech qanday 'sni ko'rmaymiz
insert
. Ma'lum bo'lishicha, biz aslida hech narsani saqlamaganmiz? JPA sizga quyidagi usul yordamida qat'iylik konteksti va ma'lumotlar bazasini sinxronlashtirish imkonini beradi
flush
:
entityManager.flush();
Ammo agar biz uni hozir bajarsak, xatoga duch kelamiz:
hech qanday tranzaksiya bajarilmaydi . Va endi JPA tranzaktsiyalardan qanday foydalanishi haqida bilib olish vaqti keldi.
JPA operatsiyalari
Esda tutganimizdek, JPA qat'iylik konteksti kontseptsiyasiga asoslanadi. Bu ob'ektlar yashaydigan joy. Va biz ob'ektlarni orqali boshqaramiz
EntityManager
. Buyruqni bajarganimizda
persist
, ob'ektni kontekstga joylashtiramiz. Aniqrog'i, biz
EntityManager
buni qilish kerakligini aytamiz. Ammo bu kontekst faqat ba'zi saqlash joyidir. U hatto ba'zan "birinchi darajadagi kesh" deb ataladi. Lekin u ma'lumotlar bazasiga ulanishi kerak. Ilgari xato bilan muvaffaqiyatsiz bo'lgan buyruq
flush
ma'lumotlar bazasi bilan qat'iylik kontekstidagi ma'lumotlarni sinxronlashtiradi. Ammo bu transportni talab qiladi va bu transport tranzaksiyadir. JPAdagi operatsiyalar spetsifikatsiyaning "7.5 Nazorat qiluvchi operatsiyalar" bo'limida tasvirlangan. JPA-da tranzaktsiyalardan foydalanish uchun maxsus API mavjud:
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
Testlardan oldin va keyin ishlaydigan kodimizga tranzaksiya boshqaruvini qo'shishimiz kerak:
@Before
public void init() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
em = emf.createEntityManager();
em.getTransaction().begin();
}
@After
public void close() {
if (em.getTransaction().isActive()) {
em.getTransaction().commit();
}
em.getEntityManagerFactory().close();
em.close();
}
Qo'shgandan so'ng, biz qo'shish jurnalida SQLda ilgari bo'lmagan ifodani ko'ramiz:
Tranzaktsiyada to'plangan o'zgarishlar
EntityManager
ma'lumotlar bazasida amalga oshirildi (tasdiqlandi va saqlangan). Keling, o'z mohiyatimizni topishga harakat qilaylik. Ob'ektni identifikatori bo'yicha qidirish uchun test yarataylik:
@Test
public void shouldFindCategory() {
Category cat = new Category();
cat.setTitle("test");
em.persist(cat);
Category result = em.find(Category.class, 1L);
assertNotNull(result);
}
Bunday holda, biz avval saqlangan ob'ektni olamiz, lekin jurnalda SELECT so'rovlarini ko'rmaymiz. Va hamma narsa biz aytganlarimizga asoslanadi: "Shaxs menejeri, iltimos, menga ID=1 bo'lgan toifadagi ob'ektni toping." Va ob'ekt menejeri birinchi navbatda uning kontekstiga qaraydi (bir turdagi keshdan foydalanadi) va agar uni topa olmasa, u ma'lumotlar bazasiga kirishga ketadi. Identifikatorni 2 ga o'zgartirishga arziydi (bunday narsa yo'q, biz faqat 1 nusxani saqladik) va biz
SELECT
so'rov paydo bo'lishini ko'ramiz. Chunki kontekstda ob'ektlar topilmadi va
EntityManager
ma'lumotlar bazasi ob'ektni topishga harakat qilmoqda.Biz kontekstdagi ob'ekt holatini boshqarish uchun foydalanishimiz mumkin bo'lgan turli xil buyruqlar mavjud. Ob'ektning bir holatdan ikkinchi holatga o'tishi ob'ektning hayot aylanishi deb ataladi -
lifecycle
.
Ob'ektning hayot aylanishi
Ob'ektlarning hayot aylanishi JPA spetsifikatsiyasida "3.2 Entity Instance hayotiy tsikli" bo'limida tasvirlangan. Chunki ob'ektlar kontekstda yashaydi va tomonidan nazorat qilinadi
EntityManager
, keyin ular sub'ektlar nazorat qilinadi, deyishadi, ya'ni. boshqargan. Keling, mavjudlik hayotining bosqichlarini ko'rib chiqaylik:
Category cat = new Category();
cat.setTitle("new category");
entityManager.persist(cat);
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
entityManager.detach(cat);
Category managed = entityManager.merge(cat);
entityManager.remove(managed);
Va uni birlashtirish uchun diagramma:
Xaritalash
JPA da biz ob'ektlarning bir-biri o'rtasidagi munosabatlarini tasvirlashimiz mumkin. Keling, domen modelimiz bilan shug'ullanganimizda, biz allaqachon ob'ektlarning bir-birlari o'rtasidagi munosabatlarini ko'rib chiqqanimizni eslaylik.
Keyin biz quickdatabasediagrams.com resursidan foydalandik :
Ob'ektlar o'rtasida aloqalarni o'rnatish xaritalash yoki assotsiatsiya (Association Mappings) deb ataladi. JPA yordamida tashkil etilishi mumkin bo'lgan uyushmalar turlari quyida keltirilgan:
Topic
Keling , mavzuni tavsiflovchi ob'ektni ko'rib chiqaylik .
Topic
Unga bo'lgan munosabat haqida nima deyishimiz mumkin
Category
? Ko'pchilik
Topic
bir toifaga tegishli bo'ladi. Shuning uchun bizga uyushma kerak
ManyToOne
. Keling, ushbu munosabatni JPAda ifodalaymiz:
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
Qaysi izohlarni qo'yish kerakligini eslab qolish uchun oxirgi qism yuqorida izoh ko'rsatilgan maydon uchun javobgar ekanligini yodda tutishingiz mumkin.
ToOne
- aniq misol.
ToMany
- to'plamlar. Endi bizning aloqamiz bir tomonlama. Keling, buni ikki tomonlama aloqaga aylantiraylik. Keling , ushbu toifaga kiritilgan
Category
har bir kishi haqidagi bilimlarni qo'shaylik .
Topic
Bu bilan tugashi kerak
ToMany
, chunki bizda ro'yxat bor
Topic
. Ya'ni, "Ko'p" mavzularga munosabat. Savol qoladi -
OneToMany
yoki
ManyToMany
:
Xuddi shu mavzu bo'yicha yaxshi javobni bu erda o'qishingiz mumkin: "
ORM oneToMany, manyToMany munosabatlarini men besh yoshdaman kabi tushuntiring ". Agar toifa mavzular bilan bog'liq bo'lsa
ToMany
, bu mavzularning har biri faqat bitta toifaga ega bo'lishi mumkin, keyin u bo'ladi
One
, aks holda
Many
. Shunday qilib,
Category
barcha mavzular ro'yxati quyidagicha ko'rinadi:
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "topic_id")
private Set<Topic> topics = new HashSet<>();
Category
Va keling , barcha mavzular ro'yxatini olish uchun asosan oluvchi yozishni unutmang :
public Set<Topic> getTopics() {
return this.topics;
}
Ikki tomonlama munosabatlarni avtomatik kuzatish juda qiyin narsa. Shuning uchun JPA bu mas'uliyatni ishlab chiquvchiga o'tkazadi.
Topic
Bu biz uchun shuni anglatadiki, biz bilan ob'ekt munosabatlarini o'rnatganimizda
Category
, ma'lumotlar izchilligini o'zimiz ta'minlashimiz kerak. Bu oddiygina amalga oshiriladi:
public void setCategory(Category category) {
category.getTopics().add(this);
this.category = category;
}
Tekshirish uchun oddiy test yozamiz:
@Test
public void shouldPersistCategoryAndTopics() {
Category cat = new Category();
cat.setTitle("test");
Topic topic = new Topic();
topic.setTitle("topic");
topic.setCategory(cat);
em.persist(cat);
}
Xarita yaratish butunlay alohida mavzu. Ushbu ko'rib chiqishning maqsadi bunga erishish usullarini tushunishdir. Bu yerda xaritalash haqida ko'proq o'qishingiz mumkin:
JPQL
JPA qiziqarli vositani taqdim etadi - Java Persistence Query Language so'rovlari. Bu til SQL tiliga o'xshaydi, lekin SQL jadvallaridan ko'ra Java ob'ekt modelidan foydalanadi. Keling, bir misolni ko'rib chiqaylik:
@Test
public void shouldPerformQuery() {
Category cat = new Category();
cat.setTitle("query");
em.persist(cat);
Query query = em.createQuery("SELECT c from Category c WHERE c.title = 'query'");
assertNotNull(query.getSingleResult());
}
Ko'rib turganimizdek, so'rovda biz jadvalga
Category
emas, balki ob'ektga havoladan foydalandik. Va shuningdek, ushbu shaxs sohasida
title
. JPQL ko'plab foydali xususiyatlarni taqdim etadi va o'z maqolasiga loyiqdir. Batafsil ma'lumotni sharhda topishingiz mumkin:
Criteria API
Va nihoyat, Criteria API-ga tegmoqchiman. JPA dinamik so'rovlar yaratish vositasini taqdim etadi. Criteria API dan foydalanishga misol:
@Test
public void shouldFindWithCriteriaAPI() {
Category cat = new Category();
em.persist(cat);
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Category> query = cb.createQuery(Category.class);
Root<Category> c = query.from(Category.class);
query.select(c);
List<Category> resultList = em.createQuery(query).getResultList();
assertEquals(1, resultList.size());
}
Bu misol " " so'rovini bajarishga teng
SELECT c FROM Category c
.
Criteria API kuchli vositadir. Bu haqda ko'proq ma'lumotni bu yerda o'qishingiz mumkin:
Xulosa
Ko'rib turganimizdek, JPA juda ko'p xususiyatlar va vositalarni taqdim etadi. Ularning har biri tajriba va bilim talab qiladi. Hatto JPA tekshiruvi doirasida ham hamma narsani eslatib o'tishning iloji bo'lmadi, batafsil sho'ng'in haqida gapirmaslik kerak. Ammo umid qilamanki, uni o'qib chiqqandan so'ng, ORM va JPA nima ekanligi, ular qanday ishlashi va u bilan nima qilish mumkinligi aniq bo'ldi. Xo'sh, aperatif uchun men turli xil materiallarni taklif qilaman:
#Viacheslav
GO TO FULL VERSION