دنیای توسعه مدرن پر از مشخصات مختلفی است که برای آسان کردن زندگی طراحی شده اند. با دانستن ابزارها، می توانید ابزار مناسب را انتخاب کنید. بدون دانستن، می توانید زندگی خود را سخت تر کنید. این بررسی حجاب رازداری بر مفهوم JPA - Java Persistence API را از بین خواهد برد. امیدوارم که پس از خواندن بخواهید حتی عمیق تر به این دنیای اسرارآمیز شیرجه بزنید.
معرفی
همانطور که می دانیم یکی از وظایف اصلی برنامه ها ذخیره و پردازش داده ها است. در روزهای خوب گذشته، مردم به سادگی داده ها را در فایل ها ذخیره می کردند. اما به محض اینکه به دسترسی همزمان خواندن و ویرایش نیاز است، زمانی که بار وجود دارد (یعنی چندین درخواست به طور همزمان وارد میشوند)، ذخیره دادهها به سادگی در فایلها مشکل ساز میشود. برای کسب اطلاعات بیشتر در مورد مشکلاتی که پایگاههای اطلاعاتی چگونه و چگونه حل میکنند، به شما توصیه میکنم مقاله «
نحوه ساختاردهی پایگاههای داده » را مطالعه کنید. این بدان معنی است که ما تصمیم می گیریم داده های خود را در یک پایگاه داده ذخیره کنیم. برای مدت طولانی، جاوا قادر به کار با پایگاه های داده با استفاده از JDBC API (اتصال پایگاه داده جاوا) بوده است. در اینجا می توانید اطلاعات بیشتری در مورد JDBC بخوانید: "
JDBC یا جایی که همه چیز شروع می شود ." اما زمان گذشت و توسعه دهندگان هر بار با نیاز به نوشتن کدهای مشابه و غیر ضروری "نگهداری" (به اصطلاح کد Boilerplate) برای عملیات بی اهمیت ذخیره اشیاء جاوا در پایگاه داده و بالعکس، ایجاد اشیاء جاوا با استفاده از داده ها از پایگاه داده و سپس، برای حل این مشکلات، مفهومی مانند ORM متولد شد.
ORM - نگاشت شی-رابطه ای یا ترجمه شده به نگاشت شی-رابطه ای روسی. این یک فناوری برنامه نویسی است که پایگاه داده ها را با مفاهیم زبان های برنامه نویسی شی گرا پیوند می دهد. برای ساده تر، ORM ارتباط بین اشیاء جاوا و رکوردها در یک پایگاه داده است:
ORM اساساً این مفهوم است که یک شی جاوا می تواند به عنوان داده در یک پایگاه داده نمایش داده شود (و بالعکس). این در قالب مشخصات JPA - Java Persistence API تجسم یافته است. مشخصات قبلاً شرحی از Java API است که این مفهوم را بیان می کند. مشخصات به ما میگوید که چه ابزارهایی باید در اختیار ما قرار گیرد (یعنی از چه رابطهایی میتوانیم کار کنیم) تا بتوانیم مطابق با مفهوم ORM کار کنیم. و نحوه استفاده از این وجوه. مشخصات پیاده سازی ابزارها را توصیف نمی کند. این امکان استفاده از پیاده سازی های مختلف برای یک مشخصات را فراهم می کند. شما می توانید آن را ساده کنید و بگویید که یک مشخصات توصیفی از API است. متن مشخصات JPA را می توان در وب سایت Oracle یافت: "
JSR 338: JavaTM Persistence API ". بنابراین، برای استفاده از JPA، به پیاده سازی هایی نیاز داریم که با آن از فناوری استفاده کنیم. به پیاده سازی های JPA، ارائه دهندگان JPA نیز گفته می شود. یکی از قابل توجه ترین پیاده سازی های JPA
Hibernate است . بنابراین، من پیشنهاد می کنم آن را در نظر بگیرید.
ایجاد یک پروژه
از آنجایی که JPA در مورد جاوا است، ما به یک پروژه جاوا نیاز خواهیم داشت. ما می توانیم به صورت دستی ساختار دایرکتوری را خودمان ایجاد کنیم و کتابخانه های لازم را خودمان اضافه کنیم. اما استفاده از سیستم ها برای مونتاژ خودکار پروژه ها بسیار راحت تر و صحیح تر است (یعنی در اصل، این فقط یک برنامه است که مونتاژ پروژه ها را برای ما مدیریت می کند. دایرکتوری ها ایجاد کنید، کتابخانه های لازم را به مسیر کلاس اضافه کنید و غیره .). یکی از این سیستم ها Gradle است. در اینجا می توانید اطلاعات بیشتری در مورد Gradle بخوانید: "
معرفی مختصر بر Gradle ". همانطور که می دانیم، عملکرد Gradle (یعنی کارهایی که می تواند انجام دهد) با استفاده از پلاگین های مختلف Gradle پیاده سازی می شود. بیایید از Gradle و پلاگین
Gradle Build Init Plugin استفاده کنیم . بیایید دستور را اجرا کنیم:
gradle init --type java-application
Gradle ساختار دایرکتوری لازم را برای ما انجام میدهد و یک توضیح اساسی از پروژه در اسکریپت ساخت ایجاد میکند
build.gradle
. بنابراین، ما یک برنامه کاربردی داریم. ما باید در مورد آنچه که می خواهیم با برنامه خود توصیف یا مدل سازی کنیم فکر کنیم. بیایید از برخی ابزارهای مدل سازی استفاده کنیم، به عنوان مثال:
app.quickdatabasediagrams.com در اینجا شایان ذکر است که آنچه ما توضیح دادیم "مدل دامنه" ما است. دامنه یک "حوزه موضوعی" است. به طور کلی، دامنه در لاتین "تصرف" است. در قرون وسطی، این نام به مناطقی بود که در اختیار پادشاهان یا فئودال ها بود. و در فرانسه به کلمه "domaine" تبدیل شد که به سادگی به عنوان "منطقه" ترجمه می شود. بنابراین ما "مدل دامنه" = "مدل موضوع" خود را توصیف کردیم. هر عنصر این مدل نوعی "جوهر" است، چیزی از زندگی واقعی. در مورد ما، اینها موجودیت ها هستند: دسته (
Category
)، موضوع (
Topic
). بیایید یک بسته جداگانه برای موجودیت ها ایجاد کنیم، به عنوان مثال با مدل نام. و بیایید کلاس های جاوا را در آنجا اضافه کنیم که موجودیت ها را توصیف می کنند. در کد جاوا، چنین موجوداتی یک
POJO معمولی هستند که ممکن است به شکل زیر باشد:
public class Category {
private Long id;
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
بیایید محتویات کلاس را کپی کنیم و یک کلاس با قیاس ایجاد کنیم
Topic
. او فقط در دانسته هایش در مورد دسته ای که به آن تعلق دارد متفاوت خواهد بود. بنابراین، بیایید
Topic
یک فیلد دسته بندی و متدهای کار با آن را به کلاس اضافه کنیم:
private Category category;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
اکنون یک برنامه جاوا داریم که مدل دامنه مخصوص به خود را دارد. اکنون زمان شروع اتصال به پروژه JPA است.
افزودن JPA
بنابراین، همانطور که به یاد داریم، JPA به این معنی است که ما چیزی را در پایگاه داده ذخیره خواهیم کرد. بنابراین ما به یک پایگاه داده نیاز داریم. برای استفاده از اتصال پایگاه داده در پروژه خود، باید یک کتابخانه وابستگی برای اتصال به پایگاه داده اضافه کنیم. همانطور که به یاد داریم، از Gradle استفاده کردیم که یک اسکریپت ساخت برای ما ایجاد کرد
build.gradle
. در آن وابستگی هایی که پروژه ما به آن نیاز دارد را شرح خواهیم داد. وابستگی ها آن دسته از کتابخانه ها هستند که بدون آنها کد ما نمی تواند کار کند. بیایید با توضیح وابستگی اتصال به پایگاه داده شروع کنیم. ما این کار را به همان روشی انجام می دهیم که اگر فقط با JDBC کار می کردیم این کار را انجام می دادیم:
dependencies {
implementation 'com.h2database:h2:1.4.199'
حالا ما یک پایگاه داده داریم. اکنون می توانیم یک لایه به برنامه خود اضافه کنیم که مسئول نگاشت اشیاء جاوا ما در مفاهیم پایگاه داده (از جاوا به SQL) است. همانطور که به یاد داریم، ما قصد داریم از یک پیاده سازی مشخصات JPA به نام Hibernate برای این کار استفاده کنیم:
dependencies {
implementation 'com.h2database:h2:1.4.199'
implementation 'org.hibernate:hibernate-core:5.4.2.Final'
اکنون باید JPA را پیکربندی کنیم. اگر مشخصات و بخش "واحد ماندگاری 8.1" را مطالعه کنیم، خواهیم فهمید که واحد ماندگاری نوعی ترکیبی از پیکربندی ها، ابرداده ها و موجودیت ها است. و برای اینکه JPA کار کند، باید حداقل یک واحد Persistence را در فایل پیکربندی توضیح دهید که به نام
persistence.xml
. مکان آن در فصل مشخصات "8.2 بسته بندی واحد پایدار" توضیح داده شده است. طبق این قسمت اگر محیط Java SE داریم باید آن را در ریشه دایرکتوری META-INF قرار دهیم.
بیایید محتوا را از مثال ارائه شده در مشخصات JPA در
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>
اما این کافی نیست. ما باید بگوییم ارائه دهنده JPA ما کیست، یعنی. کسی که مشخصات JPA را پیاده سازی می کند:
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
حالا بیایید تنظیمات (
properties
) را اضافه کنیم. برخی از آنها (با شروع با
javax.persistence
) پیکربندی استاندارد JPA هستند و در مشخصات JPA در بخش "خواص 8.2.1.9" توضیح داده شده اند. برخی از پیکربندیها مختص ارائهدهنده هستند (در مورد ما روی Hibernate بهعنوان یک ارائهدهنده Jpa تأثیر میگذارند. بلوک تنظیمات ما به این شکل خواهد بود:
<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>
اکنون یک پیکربندی سازگار با JPA داریم
persistence.xml
، یک ارائه دهنده JPA Hibernate و یک پایگاه داده H2 وجود دارد، و همچنین 2 کلاس وجود دارد که مدل دامنه ما هستند. بیایید در نهایت همه اینها کار کنند. در کاتالوگ
/test/java
، Gradle ما با مهربانی یک الگو برای تست های واحد تولید کرد و آن را AppTest نامید. از آن استفاده کنیم. همانطور که در فصل "7.1 زمینه های ماندگاری" از مشخصات JPA بیان شد، موجودیت ها در جهان JPA در فضایی به نام زمینه پایداری زندگی می کنند. اما ما مستقیماً با Persistence Context کار نمی کنیم. برای این ما
Entity Manager
از یا "entity manager" استفاده می کنیم. این اوست که از زمینه و موجودیت هایی که در آنجا زندگی می کنند می داند. ما با
Entity Manager
اوم تعامل داریم. سپس تنها چیزی که باقی می ماند این است که بفهمیم این یکی را از کجا می توانیم تهیه کنیم
Entity Manager
؟ با توجه به فصل "7.2.2 بدست آوردن مدیر نهاد مدیریت شده با برنامه" از مشخصات JPA، باید از
EntityManagerFactory
. بنابراین، بیایید خود را با مشخصات JPA مسلح کنیم و از فصل "7.3.2 به دست آوردن کارخانه مدیریت موجودیت در محیط جاوا SE" مثالی بزنیم و آن را در قالب یک تست واحد ساده قالب بندی کنیم:
@Test
public void shouldStartHibernate() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
EntityManager entityManager = emf.createEntityManager();
}
این آزمایش قبلاً خطای "Unrecognized JPA persistence.xml XSD version" را نشان می دهد. دلیل آن این است که
persistence.xml
همانطور که در مشخصات JPA در بخش "8.3 persistence.xml Schema" آمده است، باید طرح مورد استفاده را به درستی مشخص کنید:
<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">
علاوه بر این، ترتیب عناصر مهم است. بنابراین،
provider
قبل از لیست کردن کلاس ها باید مشخص شود. پس از این، آزمون با موفقیت اجرا خواهد شد. ما اتصال مستقیم JPA را تکمیل کردیم. قبل از اینکه به ادامه مطلب برویم، بیایید به تست های باقی مانده فکر کنیم. هر یک از آزمایشات ما نیاز خواهد داشت
EntityManager
. بیایید مطمئن شویم که هر تست
EntityManager
در ابتدای اجرا تست های خود را دارد. علاوه بر این، ما می خواهیم پایگاه داده هر بار جدید باشد. با توجه به اینکه ما
inmemory
از گزینه استفاده می کنیم کافی است بسته شود
EntityManagerFactory
. ایجاد
Factory
یک عملیات پرهزینه است. اما برای آزمایش ها توجیه دارد. JUnit به شما اجازه می دهد تا روش هایی را مشخص کنید که قبل از (قبل) و بعد (پس از) اجرای هر تست اجرا شوند:
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();
}
حال قبل از اجرای هر تست، تست جدیدی ایجاد می شود
EntityManagerFactory
که مستلزم ایجاد یک پایگاه داده جدید است، زیرا
hibernate.hbm2ddl.auto
معنی دارد
create
. و از کارخانه جدید ما یک مورد جدید دریافت خواهیم کرد
EntityManager
.
موجودیت ها
همانطور که به یاد داریم، قبلاً کلاس هایی ایجاد کردیم که مدل دامنه ما را توصیف می کند. قبلاً گفتیم که اینها «ذات» ما هستند. این نهادی است که ما با استفاده از آن مدیریت خواهیم کرد
EntityManager
. بیایید یک تست ساده بنویسیم تا ماهیت یک دسته را حفظ کنیم:
@Test
public void shouldPersistCategory() {
Category cat = new Category();
cat.setTitle("new category");
em.persist(cat);
}
اما این آزمایش فوراً جواب نمی دهد، زیرا ... ما خطاهای مختلفی دریافت خواهیم کرد که به ما کمک می کند تا بفهمیم موجودیت ها چیست:
-
Unknown entity: hibernate.model.Category
چرا Hibernate نمی فهمد Category
این چیست entity
؟ موضوع این است که نهادها باید طبق استاندارد JPA توصیف شوند.
طبقات نهاد باید با حاشیه نویسی @Entity
، همانطور که در فصل "2.1 کلاس موجودیت" از مشخصات JPA بیان شده است، حاشیه نویسی شود.
-
No identifier specified for entity: hibernate.model.Category
موجودیت ها باید یک شناسه منحصر به فرد داشته باشند که بتوان از آن برای تشخیص یک رکورد از دیگری استفاده کرد.
با توجه به فصل "2.4 کلیدهای اولیه و هویت نهاد" از مشخصات JPA، "هر موجودیت باید یک کلید اصلی داشته باشد"، به عنوان مثال. هر موجودیتی باید یک "کلید اصلی" داشته باشد. چنین کلید اولیه باید توسط حاشیه نویسی مشخص شود@Id
-
ids for this class must be manually assigned before calling save()
شناسنامه باید از جایی بیاید. می توان آن را به صورت دستی مشخص کرد، یا می توان آن را به صورت خودکار دریافت کرد.
بنابراین، همانطور که در فصل های "11.2.3.3 GeneratedValue" و "11.1.20 GeneratedValue Annotation" اشاره شده است، می توانیم حاشیه نویسی را مشخص کنیم @GeneratedValue
.
بنابراین برای اینکه کلاس دسته به یک موجودیت تبدیل شود باید تغییرات زیر را اعمال کنیم:
@Entity
public class Category {
@Id
@GeneratedValue
private Long id;
علاوه بر این، حاشیه نویسی
@Id
نشان می دهد که از کدام یک استفاده شود
Access Type
. می توانید اطلاعات بیشتری در مورد نوع دسترسی در مشخصات JPA در بخش "2.3 نوع دسترسی" بخوانید. به طور خلاصه، زیرا ...
@Id
در بالای فیلد ( ) مشخص کردیم
field
، سپس نوع دسترسی پیش فرض خواهد بود
field-based
، نه
property-based
. بنابراین، ارائه دهنده JPA مقادیر را مستقیماً از فیلدها می خواند و ذخیره می کند.
@Id
اگر بالای گیرنده قرار دهیم ،
property-based
از دسترسی استفاده می شود، یعنی. از طریق گیرنده و تنظیم کننده هنگام اجرای تست، ما همچنین می بینیم که چه درخواست هایی به پایگاه داده ارسال می شود (به لطف گزینه
hibernate.show_sql
).
insert
اما هنگام ذخیره، ما هیچ علامتی را نمی بینیم . معلوم می شود که ما در واقع چیزی را ذخیره نکردیم؟ JPA به شما این امکان را می دهد که زمینه پایداری و پایگاه داده را با استفاده از روش همگام سازی کنید
flush
:
entityManager.flush();
اما اگر اکنون آن را اجرا کنیم، با خطا مواجه خواهیم شد:
هیچ تراکنشی در حال انجام نیست . و اکنون زمان آن رسیده است که در مورد نحوه استفاده JPA از تراکنش ها بیاموزیم.
معاملات JPA
همانطور که به یاد داریم، JPA مبتنی بر مفهوم زمینه تداوم است. این مکانی است که موجودیت ها در آن زندگی می کنند. و ما نهادها را از طریق مدیریت می کنیم
EntityManager
. هنگامی که دستور را اجرا می کنیم
persist
، موجودیت را در متن قرار می دهیم. به طور دقیق تر، ما به
EntityManager
'y می گوییم که این کار باید انجام شود. اما این زمینه فقط بخشی از فضای ذخیره سازی است. حتی گاهی اوقات "حافظه پنهان سطح اول" نامیده می شود. اما باید به دیتابیس متصل شود. دستوری
flush
که قبلاً با یک خطا ناموفق بود، دادههای موجود در زمینه پایداری را با پایگاه داده همگامسازی میکند. اما این نیاز به حمل و نقل دارد و این حمل و نقل یک معامله است. معاملات در JPA در بخش "7.5 کنترل معاملات" مشخصات توضیح داده شده است. یک API ویژه برای استفاده از تراکنش ها در JPA وجود دارد:
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
ما باید مدیریت تراکنش را به کد خود اضافه کنیم که قبل و بعد از آزمایش اجرا می شود:
@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();
}
پس از افزودن، در insert log عبارتی در SQL خواهیم دید که قبلاً وجود نداشت:
تغییرات انباشته شده در
EntityManager
تراکنش در پایگاه داده انجام شد (تأیید و ذخیره شد). بیایید اکنون سعی کنیم جوهر خود را پیدا کنیم. بیایید یک آزمایش برای جستجوی یک موجودیت با شناسه آن ایجاد کنیم:
@Test
public void shouldFindCategory() {
Category cat = new Category();
cat.setTitle("test");
em.persist(cat);
Category result = em.find(Category.class, 1L);
assertNotNull(result);
}
در این صورت، موجودی را که قبلاً ذخیره کرده بودیم دریافت می کنیم، اما پرس و جوهای SELECT را در گزارش نخواهیم دید. و همه چیز بر اساس چیزی است که ما می گوییم: "مدیر نهاد، لطفاً موجودیت رده را با ID=1 برای من پیدا کنید." و entity manager ابتدا در زمینه آن جستجو می کند (از نوعی حافظه پنهان استفاده می کند) و فقط اگر آن را پیدا نکرد، به جستجو در پایگاه داده می رود. ارزش دارد شناسه را به 2 تغییر دهید (چنین چیزی وجود ندارد، ما فقط 1 نمونه را ذخیره کردیم) و خواهیم دید که
SELECT
درخواست ظاهر می شود. چون هیچ موجودی در متن یافت نشد و
EntityManager
پایگاه داده در تلاش برای یافتن موجودیت است دستورات مختلفی وجود دارد که می توانیم از آنها برای کنترل وضعیت یک موجود در متن استفاده کنیم. انتقال یک موجود از یک حالت به حالت دیگر چرخه حیات موجودیت نامیده می شود -
lifecycle
.
چرخه حیات موجودیت
چرخه عمر موجودیت ها در مشخصات JPA در فصل "3.2 چرخه حیات نمونه موجودیت" توضیح داده شده است. زیرا موجودیت ها در یک زمینه زندگی می کنند و توسط کنترل می شوند
EntityManager
، سپس می گویند موجودیت ها کنترل می شوند، یعنی. اداره می شود. بیایید به مراحل زندگی یک موجودیت نگاه کنیم:
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);
و در اینجا یک نمودار برای تثبیت آن وجود دارد:
نقشه برداری
در JPA می توانیم روابط موجودیت ها را بین یکدیگر توصیف کنیم. بیایید به یاد داشته باشیم که وقتی با مدل دامنه خود سروکار داشتیم، قبلاً به روابط موجودات بین یکدیگر نگاه کردیم.
سپس از منبع quickdatabasediagrams.com استفاده کردیم :
ایجاد ارتباط بین موجودیت ها را نگاشت یا تداعی (Association Mappings) می گویند. انواع انجمن هایی که می توان با استفاده از JPA ایجاد کرد در زیر ارائه شده است:
بیایید به موجودی نگاه کنیم
Topic
که یک موضوع را توصیف می کند.
Topic
در مورد نگرش چه می توانیم بگوییم
Category
؟ بسیاری از آنها
Topic
به یک دسته تعلق خواهند داشت. بنابراین، ما نیاز به یک انجمن داریم
ManyToOne
. بیایید این رابطه را در JPA بیان کنیم:
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
برای یادآوری اینکه کدام حاشیهنویسی را قرار دهید، میتوانید به یاد داشته باشید که قسمت آخر مربوط به قسمتی است که در بالای آن حاشیهنویسی نشان داده شده است.
ToOne
- نمونه خاص
ToMany
- مجموعه ها. الان ارتباط ما یک طرفه است. بیایید آن را به یک ارتباط دو طرفه تبدیل کنیم. بیایید به
Category
دانش درباره همه افرادی
Topic
که در این دسته قرار می گیرند اضافه کنیم. باید به پایان برسد
ToMany
، زیرا ما یک لیست داریم
Topic
. یعنی نگرش "به بسیاری" موضوعات. سوال باقی می ماند -
OneToMany
یا
ManyToMany
:
یک پاسخ خوب در مورد همان موضوع را میتوانید در اینجا بخوانید: "
روابط ORM oneToMany، manyToMany مانند I'm five را توضیح دهید ". اگر یک دسته با موضوعات ارتباط داشته باشد ، هر یک از این موضوعات می تواند تنها یک دسته داشته باشد، در غیر این صورت
ToMany
خواهد بود . بنابراین لیست همه موضوعات به شکل زیر خواهد بود:
One
Many
Category
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "topic_id")
private Set<Topic> topics = new HashSet<>();
و فراموش نکنیم که اساساً
Category
یک گیرنده بنویسیم تا لیستی از همه موضوعات را دریافت کنیم:
public Set<Topic> getTopics() {
return this.topics;
}
ردیابی خودکار روابط دو طرفه بسیار دشوار است. بنابراین، JPA این مسئولیت را به توسعه دهنده منتقل می کند. معنای این موضوع برای ما این است که زمانی که ما یک
Topic
رابطه با نهاد برقرار می کنیم
Category
، باید خودمان از سازگاری داده ها اطمینان حاصل کنیم. این به سادگی انجام می شود:
public void setCategory(Category category) {
category.getTopics().add(this);
this.category = category;
}
بیایید یک تست ساده برای بررسی بنویسیم:
@Test
public void shouldPersistCategoryAndTopics() {
Category cat = new Category();
cat.setTitle("test");
Topic topic = new Topic();
topic.setTitle("topic");
topic.setCategory(cat);
em.persist(cat);
}
نقشه برداری یک موضوع کاملا جداگانه است. هدف از این بررسی، درک ابزاری است که از طریق آن به این امر دست مییابد. در اینجا می توانید اطلاعات بیشتری در مورد نقشه برداری بخوانید:
JPQL
JPA ابزار جالبی را معرفی می کند - کوئری ها در زبان Java Persistence Query. این زبان شبیه SQL است، اما از مدل شی جاوا به جای جداول SQL استفاده می کند. بیایید به یک مثال نگاه کنیم:
@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());
}
همانطور که می بینیم، در پرس و جو از ارجاع به یک موجودیت
Category
و نه جدول استفاده کردیم. و همچنین در زمینه این نهاد
title
. JPQL بسیاری از ویژگی های مفید را ارائه می دهد و شایسته مقاله خود است. جزئیات بیشتر را می توان در بررسی یافت:
Criteria API
و در نهایت، من می خواهم به Criteria API دست بزنم. JPA یک ابزار ایجاد پرس و جو پویا را معرفی می کند. مثالی از استفاده از Criteria API:
@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());
}
این مثال معادل اجرای درخواست "
SELECT c FROM Category c
" است.
Criteria API یک ابزار قدرتمند است. در اینجا شما میتوانید اطلاعات بیشتری راجع به آن بخوانید:
نتیجه
همانطور که می بینیم، JPA تعداد زیادی ویژگی و ابزار را فراهم می کند. هر کدام از آنها به تجربه و دانش نیاز دارند. حتی در چارچوب بررسی برنامه مشترک، نمیتوان همه چیز را ذکر کرد و به غواصی مفصل اشاره نکرد. اما امیدوارم پس از مطالعه آن مشخص شده باشد که ORM و JPA چیست و چگونه کار می کند و با آن چه می توان کرد. خوب، برای یک میان وعده مواد مختلفی را ارائه می دهم:
#ویاچسلاو
GO TO FULL VERSION