מיפוי ירושה בתרדמה

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

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

כדי לטפל בזה, מפרט ה- JPA מספק כמה אסטרטגיות:

  • MappedSuperclass - כיתות ההורים, לא יכולות להיות ישויות
  • שולחן יחיד - הישויות ממעמדות שונים עם אב קדמון משותף ממוקמות בטבלה אחת
  • טבלה מצטרפת - לכל מחלקה יש את הטבלה שלה ושאילתת ישות של מחלקה משנה מחייבת הצטרפות לטבלאות
  • טבלה למחלקה - כל המאפיינים של מחלקה נמצאים בטבלה שלה, ולכן אין צורך בהצטרפות

כל אסטרטגיה מביאה למבנה מסד נתונים אחר.

ירושת ישויות פירושה שנוכל להשתמש בשאילתות פולימורפיות לאחזור כל היישויות של תת-הכיתה בעת שאילתה למעמד-על.

מכיוון ש- Hibernate הוא יישום JPA, הוא מכיל את כל האמור לעיל, כמו גם כמה תכונות ספציפיות לסטנדרט הקשורות לירושה.

בסעיפים הבאים נעבור על אסטרטגיות זמינות ביתר פירוט.

2. MappedSuperclass

משתמש ב MappedSuperclass אסטרטגיה, ירושה ניכרת רק בכיתה, אך לא במודל הישות.

נתחיל ביצירת a אדם כיתה שתייצג כיתת הורים:

@MappedSuperclass אדם בכיתה ציבורית {@ Id פרטי אדם ארוך; שם מחרוזת פרטי; // קונסטרוקטור, גטרס, סטרים}

שימו לב שלכיתה זו כבר אין @יֵשׁוּת ביאור, מכיוון שהוא לא יישמר במסד הנתונים בפני עצמו.

לאחר מכן, בואו להוסיף עוֹבֵד תת מחלקה:

מחלקה ציבורית @Entity MyEmployee מרחיב את האדם {חברת מחרוזת פרטית; // קונסטרוקטור, גטרס, סטרים}

במאגר המידע זה יתאים לאחד "העובד שלי" טבלה עם שלוש עמודות עבור השדות המוצהרים והירושה של תת-המחלקה.

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

3. שולחן יחיד

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

אנו יכולים להגדיר את האסטרטגיה בה אנו רוצים להשתמש על ידי הוספת ה- @יְרוּשָׁה ביאור למעמד העל:

@Entity @ Inheritance (אסטרטגיה = InheritanceType.SINGLE_TABLE) מחלקה ציבורית MyProduct {@Id פרטי מוצר ארוך; שם מחרוזת פרטי; // קונסטרוקטור, גטרס, סטרים}

המזהה של הישויות מוגדר גם במעמד העל.

לאחר מכן נוכל להוסיף את ישויות המשנה:

@Entity class class ספר מרחיב את MyProduct {מחבר מחרוזות פרטי; }
@Entity מחלקה ציבורית עט מרחיב את MyProduct {צבע מחרוזת פרטי; }

3.1. ערכי מפלה

מכיוון שהרשומות לכל הגופים יהיו באותה טבלה, תרדמת שינה צריכה דרך להבדיל ביניהם.

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

כדי להתאים אישית את העמודה המפלה, אנו יכולים להשתמש ב- @DiscriminatorColumn ביאור:

@Entity (name = "products") @ Inheritance (strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn (name = "product_type", discriminatorType = DiscriminatorType.INTEGER) MyProduct בכיתה ציבורית {// ...}

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

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

@Entity @DiscriminatorValue ("1") מחלקה ציבורית ספר מרחיב את MyProduct {// ...}
@Entity @DiscriminatorValue ("2") מעמד ציבורי עט מאריך את MyProduct {// ...}

Hibernate מוסיף שני ערכים אחרים שהוגדרו מראש שהביאור יכול לקחת: "ריק"ו"לא ריק“:

  • @DiscriminatorValue ("null") - פירושו שכל שורה ללא ערך מפלה תמופה למחלקת הישות עם הערה זו; ניתן ליישם זאת על מחלקת השורש של ההיררכיה
  • @DiscriminatorValue ("לא ריק") - כל שורה עם ערך מפלה שאינה תואמת את אחת משתי ההגדרות של ישויות תמופה למחלקה עם הערה זו

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

@Entity @Inheritance (אסטרטגיה = InheritanceType.SINGLE_TABLE) @DiscriminatorFormula ("מקרה כאשר המחבר אינו ריק אז 1 אחר 2 מסתיים") MyProduct בכיתה ציבורית {...}

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

4. שולחן מצטרף

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

בואו ניצור מעמד-על שמשתמש באסטרטגיה זו:

@Entity @ Inheritance (אסטרטגיה = InheritanceType.JOINED) מעמד ציבורי בעלי חיים {@ Id פרטי בעלי חיים ארוך; מיני מיתרים פרטיים; // קונסטרוקטור, גטרס, סטרים}

לאחר מכן, אנו יכולים פשוט להגדיר תת-מחלקה:

מחלקה ציבורית @Entity חיית מחמד מרחיבה בעלי חיים {שם מחרוזת פרטי; // קונסטרוקטור, גטרס, סטרים}

בשני השולחנות יהיה animalId עמודת מזהה. המפתח העיקרי של חיית מחמד לישות יש גם מגבלת מפתח זר למפתח העיקרי של הישות האם שלה. כדי להתאים אישית עמודה זו, אנו יכולים להוסיף את ה- @PrimaryKeyJoinColumn ביאור:

@Entity @PrimaryKeyJoinColumn (name = "petId") מחלקה ציבורית חיית מחמד מרחיבה בעלי חיים {// ...}

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

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

5. טבלה לכיתה

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

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

כדי להשתמש באסטרטגיה זו, עלינו רק להוסיף את ה- @יְרוּשָׁה ביאור למחלקת הבסיס:

@Entity @ Inheritance (אסטרטגיה = InheritanceType.TABLE_PER_CLASS) רכב ברמה ציבורית {@Id רכב ארוך פרטי; יצרן מיתרים פרטי; // קונסטרוקטור סטנדרטי, גטרים, סטרים}

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

זה לא שונה במיוחד ממיפוי של כל ישות ללא ירושה. ההבחנה ניכרת בשאילתת מחלקת הבסיס, שתחזיר גם את כל הרשומות של מחלקות המשנה באמצעות הִתאַחֲדוּת הצהרה ברקע.

השימוש של הִתאַחֲדוּת יכול להוביל גם לביצועים נחותים בבחירת אסטרטגיה זו. נושא נוסף הוא שאנחנו כבר לא יכולים להשתמש בייצור מפתח זהות.

6. שאילתות פולימורפיות

כאמור, שאילתת מחלקת בסיס תאחזר גם את כל הגופים המשניים.

בואו נראה התנהגות זו בפעולה עם מבחן JUnit:

@ מבט פומבי בטל שניתן Subclasses_whenQuerySuperclass_thenOk () {ספר ספר = ספר חדש (1, "1984", "ג'ורג 'אורוול"); session.save (ספר); עט עט = עט חדש (2, "העט שלי", "כחול"); session.save (עט); assertThat (session.createQuery ("מ- MyProduct") .getResultList ()). hasSize (2); }

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

מצב שינה יכול גם לשאול על ממשקים או מחלקות בסיס שאינן ישויות אך מורחבות או מיושמות על ידי מחלקות ישויות. בואו נראה מבחן JUnit באמצעות שלנו @MappedSuperclass דוגמא:

@ מבט בטל ציבורי givenSubclasses_whenQueryMappedSuperclass_thenOk () {MyEmployee emp = MyEmployee new (1, "john", "baeldung"); session.save (emp); assertThat (session.createQuery ("מתוך com.baeldung.hibernate.pojo.inheritance.Person") .getResultList ()) .hasSize (1); }

שים לב שהדבר עובד גם עבור כל מעמד-על או ממשק, בין אם זה @MappedSuperclass או שלא. ההבדל משאילתת HQL רגילה הוא שעלינו להשתמש בשם המוסמך לחלוטין מכיוון שהם אינם ישויות המנוהלות על ידי שינה.

אם איננו מעוניינים להחזיר תת מחלקה על ידי שאילתה מסוג זה, עלינו להוסיף רק את מצב שינה @רב צורתיות ביאור להגדרתו, עם סוג מְפוֹרָשׁ:

@Entity @Polymorphism (type = PolymorphismType.EXPLICIT) יישומי תיק בכיתה ציבורית פריט {...}

במקרה זה, בעת שאילתה עבור פריטים, ה תיק רשומות לא יוחזרו.

7. מסקנה

במאמר זה, הראינו את האסטרטגיות השונות למיפוי ירושה במצב שינה.

קוד המקור המלא של הדוגמאות ניתן למצוא באתר GitHub.


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