JPA סוגי הצטרפות

1. סקירה כללית

במדריך זה נבחן סוגי הצטרפות שונים הנתמכים על ידי JPA.

לשם כך נשתמש ב- JPQL, שפת שאילתה עבור JPA.

2. מודל נתונים לדוגמא

בואו נסתכל על מודל הנתונים לדוגמא שבו נשתמש בדוגמאות.

ראשית, ניצור עוֹבֵד יֵשׁוּת:

עובד בכיתה ציבורית @Entity {@Id @GeneratedValue (אסטרטגיה = GenerationType.IDENTITY) מזהה ארוך פרטי; שם מחרוזת פרטי; גיל פרטי פרטי; מחלקת מחלקה פרטית @ManyToOne; @OneToMany (mappedBy = "עובד") טלפונים פרטיים ברשימה; // גטרים וקובעים ...}

כל אחד עוֹבֵד יוקצה לאחד בלבד מַחלָקָה:

מחלקת המחלקה הציבורית @Entity {@Id @GeneratedValue (אסטרטגיה = GenerationType.AUTO) מזהה פרטי פרטי; שם מחרוזת פרטי; @OneToMany (mappedBy = "מחלקה") עובדים ברשימה פרטית; // גטרים וקובעים ...}

לבסוף, כל אחד עוֹבֵד יהיה מרובה מכשיר טלפוןs:

@Entity בכיתה ציבורית טלפון {@Id @GeneratedValue (אסטרטגיה = GenerationType.IDENTITY) מזהה פרטי פרטי; מספר מחרוזת פרטי; עובד עובד פרטי @ManyToOne; // גטרים וקובעים ...}

3. הצטרפות פנימית

נתחיל בהצטרפות פנימית. כאשר שתי ישויות או יותר מחוברות פנימיות, רק הרשומות התואמות את תנאי ההצטרפות נאספות בתוצאה.

3.1. הצטרפות פנימית מרומזת עם ניווט אגודות חד-ערכי

הצטרפות פנימית יכולה להיות משתמע. כשמו כן הוא, היזם אינו מציין צירופים פנימיים מרומזים. בכל פעם שאנחנו מנווטים באסוציאציה חד-ערכית, JPA יוצר אוטומטית צירוף מרומז:

@ מבחן ציבורי בטל כאשר PathExpressionIsUsedForSingleValuedAssociation_thenCreatesImplicitInnerJoin () {TypedQuery query = entityManager.createQuery ("SELECT e.department FROM Employee e", Department.class); רשימת resultList = query.getResultList (); // קביעות ...}

הנה ה עוֹבֵד לישות יש יחסים רבים לאחד עם מַחלָקָה יֵשׁוּת. אם ננווט מ- עוֹבֵד ישות אליה מַחלָקָה - מפרט מחלקה אלקטרונית - ננווט בעמותה חד ערכית. כתוצאה מכך, JPA תיצור צירוף פנימי. יתר על כן, תנאי ההצטרפות ייגזר ממיפוי מטא-נתונים.

3.2. הצטרפות פנימית מפורשת עם העמותה בעלת ערך יחיד

לאחר מכן, נסתכל על מְפוֹרָשׁ מצטרף פנימי לאן אנו משתמשים במילת המפתח JOIN בשאילתת JPQL שלנו:

@ מבחן ציבורי בטל כאשרJoinKeywordIsUsed_thenCreatesExplicitInnerJoin () {TypedQuery query = entityManager.createQuery ("בחר d מעובד e JOIN e.department d", Department.class); רשימת resultList = query.getResultList (); // קביעות ...}

בשאילתה זו, ציינו מילת מפתח JOIN והמשויכת אליה מַחלָקָה ישות בסעיף FROMואילו בקודם הם לא צוינו כלל. עם זאת, פרט להבדל התחבירי הזה, שאילתות ה- SQL המתקבלות יהיו דומות מאוד.

אנו יכולים גם לציין מילת מפתח פנימית אופציונלית:

@ מבחן ציבורי בטל כאשרInnerJoinKeywordIsUsed_thenCreatesExplicitInnerJoin () {TypedQuery query = entityManager.createQuery ("בחר d מעובד e INNER JOIN e.department d", Department.class); רשימת resultList = query.getResultList (); // קביעות ...}

אז מכיוון ש- JPA יהיה מרומז בהצטרפות פנימית, מתי נצטרך להיות מפורשים?

קוֹדֶם כֹּל, JPA יוצר צירוף פנימי מרומז רק כאשר אנו מציינים ביטוי נתיב. לדוגמא, כאשר אנו רוצים לבחור רק ב- עוֹבֵדיש להם מַחלָקָה ואנחנו לא משתמשים בביטוי נתיב - מחלקה אלקטרונית -עלינו להשתמש במילת המפתח JOIN בשאילתה שלנו.

שנית, כשאנחנו מפורשים, יכול להיות קל יותר לדעת מה קורה.

3.3. הצטרפות פנימית מפורשת עם אגודות בעלות ערך אוסף

מקום אחר עלינו להיות מפורשים זה עם אסוציאציות בעלות ערך אוסף.

אם נסתכל על מודל הנתונים שלנו, ה- עוֹבֵד מקיים קשר אחד לרבים עם מכשיר טלפון. כמו בדוגמה קודמת, אנו יכולים לנסות לכתוב שאילתה דומה:

בחר e.phones מטעם עובד e

אבל זה לא ממש יעבוד כמו שאולי התכוונו. מאז העמותה שנבחרה - e.phones - מוערך על גבייה, נקבל רשימה של אוסףs, במקום מכשיר טלפון ישויות:

@ מבחן ציבורי בטל כאשר CollectionValuedAssociationIsSpecifiedInSelect_ThenReturnsCollections () {TypedQuery query = entityManager.createQuery ("SELECT e.phones FROM Employee e", Collection.class); רשימת resultList = query.getResultList (); // טענות}

יתר על כן, אם אנחנו רוצים לסנן מכשיר טלפון ישויות בסעיף WHERE, JPA לא תאפשר זאת. זה בגלל ש ביטוי נתיב אינו יכול להמשיך מאסוציאציה המוערכת באוסף. אז למשל, מספר e.phones אינו תקף.

במקום זאת, עלינו ליצור צירוף פנימי מפורש וליצור כינוי עבור ה- מכשיר טלפון יֵשׁוּת. אז נוכל לציין את מכשיר טלפון ישות בסעיף SELECT או WHERE:

@ מבחן ציבורי בטל כאשר CollectionValuedAssociationIsJoined_ThenCanSelect () {TypedQuery query = entityManager.createQuery ("בחר PH מתוך עובד ו הצטרף e.phones ph WHERE ph LIKE '1%'", Phone.class); רשימת resultList = query.getResultList (); // קביעות ...}

4. הצטרפות חיצונית

כאשר שתי ישויות או יותר מחוברות חיצוניות, התוצאות העומדות בתנאי ההצטרפות וגם הרשומות בגוף השמאלי נאספות בתוצאה:

@ מבחן ציבורי בטל כאשר LeftKeywordIsSpecified_thenCreatesOuterJoinAndIncludesNonMatched () {TypedQuery query = entityManager.createQuery ("בחר DISTINCT מתוך מחלקה D LINK JOIN d. עובדים e", מחלקה. קלאס); רשימת resultList = query.getResultList (); // קביעות ...}

הנה, התוצאה תכיל מַחלָקָהים שקשורים עוֹבֵדs וגם אלה שאין להם.

זה מכונה גם צירוף חיצוני שמאלי. JPA אינו מספק הצטרפות נכונה שם אנו אוספים גם רשומות שאינן תואמות מהישות הנכונה. אם כי אנו יכולים לדמות הצטרפות נכונה על ידי החלפת ישויות בסעיף FROM.

5. מצטרף לסעיף WHERE

5.1. עם תנאי

אנו יכולים לרשום שתי ישויות בסעיף FROM ו-ואז ציין את תנאי ההצטרפות בסעיף WHERE.

זה יכול להיות שימושי במיוחד כאשר מפתחות זרים ברמת מסד הנתונים אינם במקום:

@ מבחן ציבורי בטל כאשרEntitiesAreListedInFromAndMatchedInWhere_ThenCreatesJoin () {TypedQuery query = entityManager.createQuery ("בחר d מתוך עובד e, מחלקה d WHERE e.department = d", Department.class); רשימת resultList = query.getResultList (); // קביעות ...}

הנה, אנחנו מצטרפים עוֹבֵד ו מַחלָקָה ישויות, אך הפעם מציין תנאי בסעיף WHERE.

5.2. ללא תנאי (מוצר קרטזיאני)

בדומה לכך, אנו יכולים לרשום שתי ישויות בסעיף FROM מבלי לציין תנאי הצטרפות כלשהו. במקרה הזה, נקבל מוצר קרטזי. פירוש הדבר שכל רשומה ביישות הראשונה משויכת לכל רשומה אחרת ביישות השנייה:

@ מבחן ציבורי בטל כאשרEntitiesAreListedInFrom_ThenCreatesCartesianProduct () {TypedQuery query = entityManager.createQuery ("בחר D מתוך עובד e, מחלקה d", Department.class); רשימת resultList = query.getResultList (); // קביעות ...}

כפי שאנו יכולים לנחש, שאילתות מסוג זה לא יניבו ביצועים טובים.

6. מספר צירופים

עד כה השתמשנו בשתי ישויות לביצוע הצטרפות, אך זה לא כלל. אנו יכולים גם להצטרף למספר ישויות בשאילתת JPQL אחת:

@ מבחן ציבורי בטל כאשר MultipleEntitiesAreListedWithJoin_ThenCreatesMultipleJoins () {TypedQuery query = entityManager.createQuery ("בחר ph מתוך עובד ו הצטרף e. מחלקה d הצטרף e.phones ph איפה שם שם אינו אפס"; טלפון.class) רשימת resultList = query.getResultList (); // קביעות ...}

הנה, אנו בוחרים הכל טלפונים מכל עובדים שיש להם מַחלָקָה. בדומה לצירופים פנימיים אחרים, איננו מציינים תנאים מכיוון ש- JPA מחלץ מידע זה ממיפוי מטא נתונים.

7. להביא הצטרפות

עכשיו, בואו נדבר על הצטרפות אחזור. השימוש העיקרי בו הוא להביא לאסוציאציות עמוסות עצלן בשקיקה לשאילתה הנוכחית.

הנה, נטען בשקיקה עוֹבֵדהעמותה:

@ מבחן ציבורי בטל כאשר FetchKeywordIsSpecified_ThenCreatesFetchJoin () {TypedQuery query = entityManager.createQuery ("בחר d ממחלקה d JOIN FETCH ד. עובדים", מחלקת.קלאס); רשימת resultList = query.getResultList (); // קביעות ...}

למרות שאילתה זו נראית דומה מאוד לשאילתות אחרות, יש הבדל אחד, והוא זה ה עוֹבֵדהם נטענים בשקיקה. זה אומר שברגע שאנחנו מתקשרים getResultList במבחן לעיל, מַחלָקָה לגופים יהיה את שלהם עובדים שדה טעון, וכך נחסך לנו נסיעה נוספת למסד הנתונים.

אבל היה מודע לפיזור הזיכרון. אנו עשויים להיות יעילים יותר מכיוון שביצענו שאילתה אחת בלבד, אך גם טעינו הכל מַחלָקָהs ועובדיהם בזיכרון בבת אחת.

אנחנו יכולים גם לבצע את ההצטרפות לאחזור החיצוני באופן דומה לצירופים החיצוניים, שם אנו אוספים רשומות מהישות השמאלית שאינם תואמים לתנאי ההצטרפות. בנוסף, היא טוענת בשקיקה את השיוך שצוין:

@Test ציבורי בטל כאשרLeftAndFetchKeywordsAreSpecified_ThenCreatesOuterFetchJoin () {TypedQuery query = entityManager.createQuery ("בחר ד ממחלקה d שמאל להצטרף לדף עובדים", מחלקה.קלאס); רשימת resultList = query.getResultList (); // קביעות ...}

8. סיכום

במאמר זה סקרנו את סוגי ההצטרפות ל- JPA.

כמו תמיד, אתה יכול לבדוק את כל הדוגמאות עבור הדרכות אחרות ואחרות על GitHub.


$config[zx-auto] not found$config[zx-overlay] not found