JavaRush /مدونة جافا /Random-AR /JPA: تقديم التكنولوجيا
Viacheslav
مستوى

JPA: تقديم التكنولوجيا

نشرت في المجموعة
عالم التطوير الحديث مليء بالمواصفات المختلفة المصممة لتسهيل الحياة. بمعرفة الأدوات، يمكنك اختيار الأداة المناسبة. دون أن تعرف، يمكنك أن تجعل حياتك أكثر صعوبة. سترفع هذه المراجعة حجاب السرية حول مفهوم JPA - Java Persistence API. آمل أنه بعد القراءة سوف ترغب في الغوص بشكل أعمق في هذا العالم الغامض.
JPA: مقدمة في التكنولوجيا - 1

مقدمة

كما نعلم، إحدى المهام الرئيسية للبرامج هي تخزين البيانات ومعالجتها. في الأيام الخوالي، كان الناس ببساطة يقومون بتخزين البيانات في ملفات. ولكن بمجرد الحاجة إلى الوصول للقراءة والتحرير في وقت واحد، عندما يكون هناك تحميل (أي وصول عدة طلبات في نفس الوقت)، يصبح تخزين البيانات ببساطة في الملفات مشكلة. لمزيد من المعلومات حول المشكلات التي تحلها قواعد البيانات وكيف تحلها، أنصحك بقراءة المقال " كيف يتم تنظيم قواعد البيانات ". هذا يعني أننا قررنا تخزين بياناتنا في قاعدة بيانات. لفترة طويلة، تمكنت Java من العمل مع قواعد البيانات باستخدام JDBC API (اتصال قاعدة بيانات Java). يمكنك قراءة المزيد عن JDBC هنا: " JDBC أو حيث يبدأ كل شيء ." لكن مر الوقت وواجه المطورون في كل مرة الحاجة إلى كتابة نفس النوع وكود "الصيانة" غير الضروري (ما يسمى برمز Boilerplate) لعمليات تافهة لحفظ كائنات Java في قاعدة البيانات والعكس صحيح، وإنشاء كائنات Java باستخدام البيانات من قاعدة البيانات. قاعدة البيانات. وبعد ذلك، لحل هذه المشاكل، ولد مفهوم مثل ORM. ORM - رسم الخرائط العلائقية للكائنات أو ترجمته إلى رسم الخرائط العلائقية للكائنات الروسية. هي تقنية برمجة تربط قواعد البيانات بمفاهيم لغات البرمجة الشيئية. للتبسيط، ORM هو الاتصال بين كائنات Java والسجلات في قاعدة البيانات: JPA: مقدمة في التكنولوجيا - 2ORM هو في الأساس المفهوم الذي يمكن من خلاله تمثيل كائن Java كبيانات في قاعدة البيانات (والعكس صحيح). تم تجسيدها في شكل مواصفات JPA - Java Persistence API. المواصفات هي بالفعل وصف لـ Java API الذي يعبر عن هذا المفهوم. تخبرنا المواصفات بالأدوات التي يجب تزويدنا بها (أي ما هي الواجهات التي يمكننا العمل من خلالها) من أجل العمل وفقًا لمفهوم ORM. وكيفية استخدام هذه الأموال. لا تصف المواصفات تنفيذ الأدوات. وهذا يجعل من الممكن استخدام تطبيقات مختلفة لمواصفات واحدة. يمكنك تبسيط الأمر والقول إن المواصفات هي وصف لواجهة برمجة التطبيقات (API). يمكن العثور على نص مواصفات JPA على موقع Oracle الإلكتروني: " JSR 338: JavaTM Persistence API ". لذلك، من أجل استخدام JPA، نحتاج إلى بعض التنفيذ الذي سنستخدم به التكنولوجيا. تُسمى تطبيقات JPA أيضًا بموفري JPA. أحد أبرز تطبيقات JPA هو السبات . ولذلك أقترح النظر فيه.
JPA: مقدمة للتكنولوجيا - 3

إنشاء مشروع

نظرًا لأن JPA يتعلق بـ Java، فسنحتاج إلى مشروع Java. يمكننا إنشاء بنية الدليل يدويًا بأنفسنا وإضافة المكتبات الضرورية بأنفسنا. ولكن من الأكثر ملاءمة وصحة استخدام أنظمة أتمتة تجميع المشاريع (أي، في جوهرها، هذا مجرد برنامج سيدير ​​تجميع المشاريع لنا. قم بإنشاء الدلائل، وأضف المكتبات الضرورية إلى مسار الفصل، وما إلى ذلك) .). أحد هذه الأنظمة هو 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). لنقم بإنشاء حزمة منفصلة للكيانات، على سبيل المثال باستخدام نموذج الاسم. ودعنا نضيف فئات Java التي تصف الكيانات. في كود Java، هذه الكيانات هي 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;
}
الآن لدينا تطبيق Java له نموذج المجال الخاص به. حان الوقت الآن لبدء الاتصال بمشروع JPA.
JPA: مقدمة في التكنولوجيا - 5

إضافة JPA

لذا، كما نتذكر، فإن JPA يعني أننا سنحفظ شيئًا ما في قاعدة البيانات. ولذلك، نحن بحاجة إلى قاعدة بيانات. لاستخدام اتصال قاعدة البيانات في مشروعنا، نحتاج إلى إضافة مكتبة تبعية للاتصال بقاعدة البيانات. كما نتذكر، استخدمنا Gradle، الذي أنشأ لنا برنامج نصي للبناء build.gradle. سنصف فيه التبعيات التي يحتاجها مشروعنا. التبعيات هي تلك المكتبات التي بدونها لا يمكن أن يعمل الكود الخاص بنا. لنبدأ بوصف التبعية عند الاتصال بقاعدة البيانات. نحن نفعل ذلك بنفس الطريقة التي كنا نفعلها إذا كنا نعمل فقط مع JDBC:

dependencies {
	implementation 'com.h2database:h2:1.4.199'
الآن لدينا قاعدة بيانات. يمكننا الآن إضافة طبقة إلى تطبيقنا تكون مسؤولة عن تعيين كائنات Java الخاصة بنا إلى مفاهيم قاعدة البيانات (من Java إلى 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.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". بعض التكوينات خاصة بالمزود (في حالتنا، تؤثر على السبات كموفر 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، وهناك أيضًا فئتان تمثلان نموذج المجال الخاص بنا. دعونا أخيرا نجعل كل هذا يعمل. في الكتالوج /test/java، قام Gradle الخاص بنا بإنشاء قالب لاختبارات الوحدة وأطلق عليه اسم AppTest. دعونا استخدامه. كما هو مذكور في فصل "7.1 سياقات الثبات" من مواصفات JPA، تعيش الكيانات في عالم JPA في مساحة تسمى سياق الثبات. لكننا لا نعمل بشكل مباشر مع سياق الثبات. لهذا نستخدم Entity Managerأو "مدير الكيان". هو الذي يعرف السياق وما هي الكيانات التي تعيش هناك. نحن نتفاعل مع Entity Manager'أوم. ثم كل ما تبقى هو أن نفهم من أين يمكننا الحصول على هذا Entity Manager؟ وفقًا للفصل "7.2.2 الحصول على مدير كيان مُدار بالتطبيق" من مواصفات JPA، يجب علينا استخدام EntityManagerFactory. لذلك، دعونا نتسلح بمواصفات JPA ونأخذ مثالاً من الفصل "7.3.2 الحصول على Entity Manager Factory في بيئة Java SE" ونقوم بتنسيقه في شكل اختبار وحدة بسيط:
@Test
public void shouldStartHibernate() {
	EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
	EntityManager entityManager = emf.createEntityManager();
}
سيُظهر هذا الاختبار بالفعل الخطأ "إصدار غير معروف من JPA Persence.xml XSD". والسبب هو أنك persistence.xmlتحتاج إلى تحديد المخطط الذي تريد استخدامه بشكل صحيح، كما هو مذكور في مواصفات JPA في القسم "8.3 مخطط الثبات.xml":
<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
    لماذا لا يفهم السبات ما 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فوق getter، property-basedفسيتم استخدام الوصول، أي. عبر getter و setter. عند إجراء الاختبار، نرى أيضًا الطلبات التي يتم إرسالها إلى قاعدة البيانات (بفضل الخيار hibernate.show_sql). ولكن عند الحفظ، لا نرى أي insertشيء. اتضح أننا في الواقع لم نحفظ أي شيء؟ يسمح لك JPA بمزامنة سياق الثبات وقاعدة البيانات باستخدام الطريقة flush:
entityManager.flush();
ولكن إذا قمنا بتنفيذها الآن، فسوف نحصل على خطأ: لا توجد معاملة قيد التقدم . والآن حان الوقت للتعرف على كيفية استخدام JPA للمعاملات.
JPA: مقدمة في التكنولوجيا - 8

معاملات JPA

كما نتذكر، يعتمد JPA على مفهوم سياق الثبات. هذا هو المكان الذي تعيش فيه الكيانات. ونقوم بإدارة الكيانات من خلال EntityManager. عندما ننفذ الأمر persist، نضع الكيان في السياق. وبشكل أكثر دقة، نقول EntityManagerلك أن هذا يجب القيام به. لكن هذا السياق هو مجرد مساحة تخزين. حتى أنه يطلق عليه أحيانًا "ذاكرة التخزين المؤقت للمستوى الأول". ولكن يجب أن تكون متصلا بقاعدة البيانات. يقوم الأمر flush، الذي فشل سابقًا بسبب خطأ، بمزامنة البيانات من سياق الثبات مع قاعدة البيانات. ولكن هذا يحتاج إلى النقل وهذا النقل معاملة. تم وصف المعاملات في JPA في قسم "7.5 معاملات التحكم" في المواصفات. هناك واجهة برمجة تطبيقات خاصة لاستخدام المعاملات في 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();
}
بعد الإضافة، سنرى في سجل الإدراج تعبيرًا في 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 في السجل. وكل شيء يعتمد على ما نقوله: "مدير الكيان، من فضلك ابحث لي عن كيان الفئة بالمعرف=1." ويبحث مدير الكيان أولاً في سياقه (يستخدم نوعًا من ذاكرة التخزين المؤقت)، وفقط إذا لم يجده، فإنه يذهب للبحث في قاعدة البيانات. يجدر تغيير المعرف إلى 2 (لا يوجد شيء من هذا القبيل، لقد حفظنا حالة واحدة فقط)، وسنرى أن 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 يمكننا وصف علاقات الكيانات بين بعضها البعض. دعونا نتذكر أننا نظرنا بالفعل إلى علاقات الكيانات فيما بينها عندما تعاملنا مع نموذج المجال الخاص بنا. ثم استخدمنا مورد fastdatabasediagrams.com :
JPA: مقدمة للتكنولوجيا - 13
يُطلق على إنشاء الاتصالات بين الكيانات اسم التعيين أو الارتباط (تعيينات الارتباط). يتم عرض أنواع الجمعيات التي يمكن إنشاؤها باستخدام 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 وكأنني في الخامسة من عمري ". إذا كانت الفئة مرتبطة بالموضوعات 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);
}
رسم الخرائط هو موضوع منفصل تماما. والغرض من هذه المراجعة هو فهم الوسائل التي يتم من خلالها تحقيق ذلك. يمكنك قراءة المزيد عن رسم الخرائط هنا:
JPA: مقدمة للتكنولوجيا - 16

جي بي كيو إل

تقدم JPA أداة مثيرة للاهتمام - الاستعلامات بلغة Java Persistence Query Language. تشبه هذه اللغة SQL، ولكنها تستخدم نموذج كائن Java بدلاً من جداول 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

معايير 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 عددًا كبيرًا من الميزات والأدوات. كل واحد منهم يتطلب الخبرة والمعرفة. حتى في إطار مراجعة JPA، لم يكن من الممكن ذكر كل شيء، ناهيك عن الغوص التفصيلي. لكني آمل أنه بعد قراءته، أصبح أكثر وضوحًا ما هو ORM وJPA وكيف يعمل وما يمكن فعله به. حسنًا ، لتناول وجبة خفيفة أقدم مواد مختلفة: # فياتشيسلاف
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION