מיפוי ישות יחידה למספר טבלאות ב- JPA

עליון התמדה

רק הכרזתי על החדש למד אביב קורס, המתמקד ביסודות האביב 5 ומגף האביב 2:

>> בדוק את הקורס

1. הקדמה

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

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

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

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

נניח שאנחנו מנהלים מסעדה ואנחנו רוצים לאחסן נתונים על כל ארוחה שאנחנו מגישים:

  • שֵׁם
  • תיאור
  • מחיר
  • איזה סוג של אלרגנים הוא מכיל

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

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

3. יצירת ישויות מרובות

הפיתרון הברור ביותר הוא יצירת ישות לשני הכיתות.

נתחיל בהגדרת ה- ארוחה יֵשׁוּת:

@Entity @Table (name = "meal") ארוחה בכיתה {@Id @GeneratedValue (אסטרטגיה = GenerationType.IDENTITY) @Column (name = "id") מזהה ארוך; @Column (name = "name") שם מחרוזת; @Column (name = "description") תיאור מחרוזת; @Column (name = "price") מחיר BigDecimal; @OneToOne (mappedBy = "ארוחה") אלרגנים אלרגנים; // סטרים וקובעים סטנדרטיים}

לאחר מכן נוסיף את אלרגנים יֵשׁוּת:

@Entity @Table (name = "allergens") מחלקות אלרגנים {@Id @GeneratedValue (אסטרטגיה = GenerationType.IDENTITY) @Column (name = "meal_id") ארוחה ארוכה; @OneToOne @ PrimaryKeyJoinColumn (name = "meal_id") ארוחת ארוחות; @Column (name = "peanuts") בוטנים בוליאניים; @Column (name = "סלרי") סלרי בוליאני; @Column (name = "sesame_seeds") שומשום בוליאני; // סטרים וקובעים סטנדרטיים}

בדוגמה שלעיל אנו יכולים לראות זאת ארוחה_יד הוא גם המפתח הראשי וגם המפתח הזר. פירוש הדבר שעלינו להגדיר את עמודת היחסים אחד לאחד באמצעות @PrimaryKeyJoinColumn.

עם זאת, לפיתרון זה יש שתי בעיות:

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

אחת הפתרונות האפשריים לבעיה הראשונה היא להוסיף את ה- @לא ריק ביאור ל אלרגנים שדה על שלנו ארוחה יֵשׁוּת. JPA לא מרשה לנו להתמיד ב ארוחה אם יש לנו ריקאלרגנים.

עם זאת, זה לא פיתרון אידיאלי; אנו רוצים מגבלה יותר, שבה אין לנו אפילו אפשרות לנסות להתמיד ארוחה לְלֹא אלרגנים.

4. יצירת ישות יחידה עם @SecondaryTable

אנו יכולים ליצור ישות אחת המציינת שיש לנו עמודות בטבלאות שונות באמצעות ה- @SecondaryTable ביאור:

@Entity @Table (name = "meal") @SecondaryTable (name = "allergens", pkJoinColumn = @PrimaryKeyJoinColumn (name = "meal_id")) מחלקה ארוחה {@ Id @ GeneratedValue (אסטרטגיה = GenerationType.IDENTITY) @ עמודה (שם = "id") מזהה ארוך; @Column (name = "name") שם מחרוזת; @Column (name = "description") תיאור מחרוזת; @Column (name = "price") מחיר BigDecimal; @Column (שם = "בוטנים", טבלה = "אלרגנים") בוטנים בוליאניים; @Column (שם = "סלרי", טבלה = "אלרגנים") סלרי בוליאני; @Column (name = "sesame_seeds", table = "allergens") שומשום בוליאני; // סטרים וקובעים סטנדרטיים}

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

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

כמו כן, שים לב שיכולים להיות לנו מספר טבלאות משניות אם נשבץ אותן @SecondaryTables. לחלופין, מ- Java 8, אנו יכולים לסמן את היישות במספר @SecondaryTable ביאורים מכיוון שזו ביאור שניתן לחזור עליו.

5. שילוב @SecondaryTable עם @ משובץ

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

בואו נראה מה נקבל כאשר אנו משלבים @SecondaryTable עם @ משובץ ו @ ניתן להטמיעה:

@Entity @Table (name = "meal") @SecondaryTable (name = "allergens", pkJoinColumn = @PrimaryKeyJoinColumn (name = "meal_id")) מחלקה ארוחה {@ Id @ GeneratedValue (אסטרטגיה = GenerationType.IDENTITY) @ עמודה (שם = "id") מזהה ארוך; @Column (name = "name") שם מחרוזת; @Column (name = "description") תיאור מחרוזת; @Column (name = "price") מחיר BigDecimal; אלרגנים אלרגנים משובצים @ // גטרים וקובעים סטנדרטיים} @ Allergens class Embeddable {@Column (name = "peanuts", table = "allergens") בוטנים בוליאניים; @Column (שם = "סלרי", טבלה = "אלרגנים") סלרי בוליאני; @Column (name = "sesame_seeds", table = "allergens") שומשום בוליאני; // סטרים וקובעים סטנדרטיים}

זו גישה דומה למה שראינו באמצעות @אחד לאחד. עם זאת, יש לו כמה יתרונות:

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

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

ראוי להזכיר כי אם אנו רוצים לעשות שימוש חוזר ב- אלרגנים בכיתה, עדיף אם נגדיר את העמודות של הטבלה המשנית ב- ארוחה כיתה עם @ AttributeOverride.

6. מסקנה

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

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

כרגיל, הדוגמאות זמינות ב- GitHub.

תחתית התמדה

רק הכרזתי על החדש למד אביב קורס, המתמקד ביסודות האביב 5 ומגף האביב 2:

>> בדוק את הקורס

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