JavaRush /وبلاگ جاوا /Random-FA /JPA: معرفی فناوری
Viacheslav
مرحله

JPA: معرفی فناوری

در گروه منتشر شد
دنیای توسعه مدرن پر از مشخصات مختلفی است که برای آسان کردن زندگی طراحی شده اند. با دانستن ابزارها، می توانید ابزار مناسب را انتخاب کنید. بدون دانستن، می توانید زندگی خود را سخت تر کنید. این بررسی حجاب رازداری بر مفهوم JPA - Java Persistence API را از بین خواهد برد. امیدوارم که پس از خواندن بخواهید حتی عمیق تر به این دنیای اسرارآمیز شیرجه بزنید.
JPA: مقدمه ای بر فناوری - 1

معرفی

همانطور که می دانیم یکی از وظایف اصلی برنامه ها ذخیره و پردازش داده ها است. در روزهای خوب گذشته، مردم به سادگی داده ها را در فایل ها ذخیره می کردند. اما به محض اینکه به دسترسی همزمان خواندن و ویرایش نیاز است، زمانی که بار وجود دارد (یعنی چندین درخواست به طور همزمان وارد می‌شوند)، ذخیره داده‌ها به سادگی در فایل‌ها مشکل ساز می‌شود. برای کسب اطلاعات بیشتر در مورد مشکلاتی که پایگاه‌های اطلاعاتی چگونه و چگونه حل می‌کنند، به شما توصیه می‌کنم مقاله « نحوه ساختاردهی پایگاه‌های داده » را مطالعه کنید. این بدان معنی است که ما تصمیم می گیریم داده های خود را در یک پایگاه داده ذخیره کنیم. برای مدت طولانی، جاوا قادر به کار با پایگاه های داده با استفاده از JDBC API (اتصال پایگاه داده جاوا) بوده است. در اینجا می توانید اطلاعات بیشتری در مورد JDBC بخوانید: " JDBC یا جایی که همه چیز شروع می شود ." اما زمان گذشت و توسعه دهندگان هر بار با نیاز به نوشتن کدهای مشابه و غیر ضروری "نگهداری" (به اصطلاح کد Boilerplate) برای عملیات بی اهمیت ذخیره اشیاء جاوا در پایگاه داده و بالعکس، ایجاد اشیاء جاوا با استفاده از داده ها از پایگاه داده و سپس، برای حل این مشکلات، مفهومی مانند ORM متولد شد. ORM - نگاشت شی-رابطه ای یا ترجمه شده به نگاشت شی-رابطه ای روسی. این یک فناوری برنامه نویسی است که پایگاه داده ها را با مفاهیم زبان های برنامه نویسی شی گرا پیوند می دهد. برای ساده تر، ORM ارتباط بین اشیاء جاوا و رکوردها در یک پایگاه داده است: JPA: مقدمه ای بر فناوری - 2ORM اساساً این مفهوم است که یک شی جاوا می تواند به عنوان داده در یک پایگاه داده نمایش داده شود (و بالعکس). این در قالب مشخصات JPA - Java Persistence API تجسم یافته است. مشخصات قبلاً شرحی از Java API است که این مفهوم را بیان می کند. مشخصات به ما می‌گوید که چه ابزارهایی باید در اختیار ما قرار گیرد (یعنی از چه رابط‌هایی می‌توانیم کار کنیم) تا بتوانیم مطابق با مفهوم ORM کار کنیم. و نحوه استفاده از این وجوه. مشخصات پیاده سازی ابزارها را توصیف نمی کند. این امکان استفاده از پیاده سازی های مختلف برای یک مشخصات را فراهم می کند. شما می توانید آن را ساده کنید و بگویید که یک مشخصات توصیفی از API است. متن مشخصات JPA را می توان در وب سایت Oracle یافت: " JSR 338: JavaTM Persistence API ". بنابراین، برای استفاده از JPA، به پیاده سازی هایی نیاز داریم که با آن از فناوری استفاده کنیم. به پیاده سازی های JPA، ارائه دهندگان JPA نیز گفته می شود. یکی از قابل توجه ترین پیاده سازی های JPA Hibernate است . بنابراین، من پیشنهاد می کنم آن را در نظر بگیرید.
JPA: مقدمه ای بر فناوری - 3

ایجاد یک پروژه

از آنجایی که JPA در مورد جاوا است، ما به یک پروژه جاوا نیاز خواهیم داشت. ما می توانیم به صورت دستی ساختار دایرکتوری را خودمان ایجاد کنیم و کتابخانه های لازم را خودمان اضافه کنیم. اما استفاده از سیستم ها برای مونتاژ خودکار پروژه ها بسیار راحت تر و صحیح تر است (یعنی در اصل، این فقط یک برنامه است که مونتاژ پروژه ها را برای ما مدیریت می کند. دایرکتوری ها ایجاد کنید، کتابخانه های لازم را به مسیر کلاس اضافه کنید و غیره .). یکی از این سیستم ها Gradle است. در اینجا می توانید اطلاعات بیشتری در مورد Gradle بخوانید: " معرفی مختصر بر Gradle ". همانطور که می دانیم، عملکرد Gradle (یعنی کارهایی که می تواند انجام دهد) با استفاده از پلاگین های مختلف Gradle پیاده سازی می شود. بیایید از Gradle و پلاگین Gradle Build Init Plugin استفاده کنیم . بیایید دستور را اجرا کنیم:

gradle init --type java-application
Gradle ساختار دایرکتوری لازم را برای ما انجام می‌دهد و یک توضیح اساسی از پروژه در اسکریپت ساخت ایجاد می‌کند build.gradle. بنابراین، ما یک برنامه کاربردی داریم. ما باید در مورد آنچه که می خواهیم با برنامه خود توصیف یا مدل سازی کنیم فکر کنیم. بیایید از برخی ابزارهای مدل سازی استفاده کنیم، به عنوان مثال: app.quickdatabasediagrams.com JPA: مقدمه ای بر فناوری - 4 در اینجا شایان ذکر است که آنچه ما توضیح دادیم "مدل دامنه" ما است. دامنه یک "حوزه موضوعی" است. به طور کلی، دامنه در لاتین "تصرف" است. در قرون وسطی، این نام به مناطقی بود که در اختیار پادشاهان یا فئودال ها بود. و در فرانسه به کلمه "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: مقدمه ای بر فناوری - 5

افزودن 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: مقدمه ای بر فناوری - 6
بیایید محتوا را از مثال ارائه شده در مشخصات 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.
JPA: مقدمه ای بر فناوری - 7

موجودیت ها

همانطور که به یاد داریم، قبلاً کلاس هایی ایجاد کردیم که مدل دامنه ما را توصیف می کند. قبلاً گفتیم که اینها «ذات» ما هستند. این نهادی است که ما با استفاده از آن مدیریت خواهیم کرد EntityManager. بیایید یک تست ساده بنویسیم تا ماهیت یک دسته را حفظ کنیم:
@Test
public void shouldPersistCategory() {
	Category cat = new Category();
	cat.setTitle("new category");
	// JUnit обеспечит тест свежим EntityManager'ом
	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: مقدمه ای بر فناوری - 8

معاملات 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 خواهیم دید که قبلاً وجود نداشت:
JPA: مقدمه ای بر فناوری - 9
تغییرات انباشته شده در 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: مقدمه ای بر فناوری - 10

چرخه حیات موجودیت

چرخه عمر موجودیت ها در مشخصات JPA در فصل "3.2 چرخه حیات نمونه موجودیت" توضیح داده شده است. زیرا موجودیت ها در یک زمینه زندگی می کنند و توسط کنترل می شوند EntityManager، سپس می گویند موجودیت ها کنترل می شوند، یعنی. اداره می شود. بیایید به مراحل زندگی یک موجودیت نگاه کنیم:
// 1. New or Transient (временный)
Category cat = new Category();
cat.setTitle("new category");
// 2. Managed or Persistent
entityManager.persist(cat);
// 3. Транзакция завершена, все сущности в контексте detached
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
// 4. Сущность изымаем из контекста, она становится detached
entityManager.detach(cat);
// 5. Сущность из detached можно снова сделать managed
Category managed = entityManager.merge(cat);
// 6. И можно сделать Removed. Интересно, что cat всё равно detached
entityManager.remove(managed);
و در اینجا یک نمودار برای تثبیت آن وجود دارد:
JPA: مقدمه ای بر فناوری - 11
JPA: مقدمه ای بر فناوری - 12

نقشه برداری

در JPA می توانیم روابط موجودیت ها را بین یکدیگر توصیف کنیم. بیایید به یاد داشته باشیم که وقتی با مدل دامنه خود سروکار داشتیم، قبلاً به روابط موجودات بین یکدیگر نگاه کردیم. سپس از منبع quickdatabasediagrams.com استفاده کردیم :
JPA: مقدمه ای بر فناوری - 13
ایجاد ارتباط بین موجودیت ها را نگاشت یا تداعی (Association Mappings) می گویند. انواع انجمن هایی که می توان با استفاده از JPA ایجاد کرد در زیر ارائه شده است:
JPA: مقدمه ای بر فناوری - 14
بیایید به موجودی نگاه کنیم Topicکه یک موضوع را توصیف می کند. Topicدر مورد نگرش چه می توانیم بگوییم Category؟ بسیاری از آنها Topicبه یک دسته تعلق خواهند داشت. بنابراین، ما نیاز به یک انجمن داریم ManyToOne. بیایید این رابطه را در JPA بیان کنیم:
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
برای یادآوری اینکه کدام حاشیه‌نویسی را قرار دهید، می‌توانید به یاد داشته باشید که قسمت آخر مربوط به قسمتی است که در بالای آن حاشیه‌نویسی نشان داده شده است. ToOne- نمونه خاص ToMany- مجموعه ها. الان ارتباط ما یک طرفه است. بیایید آن را به یک ارتباط دو طرفه تبدیل کنیم. بیایید به Categoryدانش درباره همه افرادی Topicکه در این دسته قرار می گیرند اضافه کنیم. باید به پایان برسد ToMany، زیرا ما یک لیست داریم Topic. یعنی نگرش "به بسیاری" موضوعات. سوال باقی می ماند - OneToManyیا ManyToMany:
JPA: مقدمه ای بر فناوری - 15
یک پاسخ خوب در مورد همان موضوع را می‌توانید در اینجا بخوانید: " روابط ORM oneToMany، manyToMany مانند I'm five را توضیح دهید ". اگر یک دسته با موضوعات ارتباط داشته باشد ، هر یک از این موضوعات می تواند تنها یک دسته داشته باشد، در غیر این صورت ToManyخواهد بود . بنابراین لیست همه موضوعات به شکل زیر خواهد بود: OneManyCategory
@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);
}
نقشه برداری یک موضوع کاملا جداگانه است. هدف از این بررسی، درک ابزاری است که از طریق آن به این امر دست می‌یابد. در اینجا می توانید اطلاعات بیشتری در مورد نقشه برداری بخوانید:
JPA: مقدمه ای بر فناوری - 16

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 بسیاری از ویژگی های مفید را ارائه می دهد و شایسته مقاله خود است. جزئیات بیشتر را می توان در بررسی یافت:
JPA: مقدمه ای بر فناوری - 17

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 چیست و چگونه کار می کند و با آن چه می توان کرد. خوب، برای یک میان وعده مواد مختلفی را ارائه می دهم: #ویاچسلاو
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION