דלגו לתוכן

לקשרים יש השלכות

זמין גם ב-28 שפות

English · Español · 日本語 · Português (Brasil) · Français · Deutsch · Italiano · 한국어 · 简体中文 · Português (Portugal) · 繁體中文 · Bahasa Indonesia · Türkçe · Polski · Tiếng Việt · ไทย · Nederlands · العربية · Українська · हिन्दी · Русский · Svenska · Dansk · Norsk bokmål · Suomi · Español (México) · Français (Canada) · Deutsch (Schweiz)

A brick house with a glass room built onto its side, and a separate timber garden studio across the lawn, joined to it only by a stepping-stone path.
התמונה נוצרה בבינה מלאכותית

יחידה 7 מתוך 10 בפרק ארכיטקטורת הנתונים של Salesforce, הפרק השלישי בקורס Data Architect. כל יחידה עומדת בפני עצמה. הקודם: גם שדות הם ארכיטקטורה · הבא: בעלות ומחזור חיים

השאלה שהיחידה הזו עונה עליה: מה אני באמת בוחר כשאני מחבר שני אובייקטים ב-Salesforce?

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

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

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

עכשיו קחו משלוח ואת המסלול שהוא נמצא בו. המשלוח קיים לפני שהוא משובץ במסלול, אפשר להעביר אותו למסלול אחר כשהתוכנית משתנה, ומחיקת מסלול לעולם לא צריכה למחוק את המשלוחים שבו. שני קווים של אחד-לרבים שנראים אותו דבר בתרשים, עם התנהגות שונה לגמרי. שימו לב שעדיין לא אמרנו “lookup” או “master-detail”. תארו קודם את ההתנהגות. ההגדרות מממשות אותה.

פתחו את המסך New Field ו-Salesforce מציעה לכם קומץ סוגי קשרים (Object Relationships Overview (opens in a new tab)):

  • Lookup: מקשר שני אובייקטים. הלחם והחמאה של קשרים ב-Salesforce.
  • Master-detail: קשירה של הורה-ילד שבה ההורה שולט בילד.
  • רבים-לרבים: לא סוג שדה בפני עצמו, אלא דפוס: אובייקט הצומת של Salesforce (Salesforce Junction Object), אובייקט מותאם אישית עם שני קשרי master-detail.
  • קשר עצמי (self-relationship): lookup מאובייקט לעצמו.
  • היררכי (hierarchical): lookup מיוחד שקיים רק באובייקט User, כמו המנהל של משתמש.
  • External lookup ו-indirect lookup: הקשרים אל אובייקטים חיצוניים ומהם, אובייקטי ה-__x מיחידה 4. External lookup מצביע על אובייקט חיצוני הורה; indirect lookup מצביע מאובייקט חיצוני על אובייקט סטנדרטי או מותאם אישית, בהתאמה לפי External ID ייחודי.

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

Lookup: הרשומות האלה מחוברות

Section titled “Lookup: הרשומות האלה מחוברות ”

Lookup אומר: הרשומה הזו משויכת לרשומה ההיא. הילד שומר על הזהות שלו, על הבעלים שלו ועל החיים שלו. משלוח מצביע על המסלול שלו. אם המסלול מבוטל, המשלוחים לא נעלמים; הם חוזרים לשיבוץ מחדש.

זה משעשע: שדה ה-lookup נמצא על הילד, אבל גם ההורה מקבל משהו, רשימה קשורה (related list) של הילדים שלו. אז כשיוצרים אחד, תנו שם לשני הקצוות. ה-Related List Label הוא מה שאנשים רואים על ההורה, וה-Child Relationship Name הוא מה שמפתחים ואינטגרציות משתמשים בו כדי ללכת מההורה לילדים. אל תקבלו את ברירות המחדל.

Lookup יכול להיות חובה או אופציונלי. כשהוא אופציונלי, אתם מחליטים מה קורה אם הרשומה שהוא מצביע עליה נמחקת, ויש שלוש אפשרויות (Considerations for Object Relationships (opens in a new tab)):

  • Clear the value of this field (לנקות את ערך השדה), ברירת המחדל. הילד נשאר, עם lookup ריק.
  • Don’t allow deletion (לא לאפשר מחיקה) של רשומת ה-lookup. נסו למחוק את המסלול, ו-Salesforce אומרת לא: הוא חלק מקשר.
  • Delete this record also (למחוק גם את הרשומה הזו), מחיקה מדורגת (cascade delete), כמו ב-master-detail. היא מוצעת רק עבור lookup מותאם אישית באובייקט מותאם אישית, היא מושבתת כברירת מחדל, ו-Salesforce צריכה להפעיל אותה עבור ה-org שלכם, כי מחיקה מדורגת עוקפת אבטחה ושיתוף: משתמשים יכולים למחוק רשומות שהם אפילו לא יכלו לראות.

זו החלטת מחזור חיים שמתחבאת במסך הגדרות.

Lookup filters (מסנני lookup) מצמצמים את מה שמשתמש יכול לבחור. נגיד שלמשלוח יש lookup בשם Installer לאיש קשר, ומתקינים הם סוג רשומה אחד של איש קשר מתוך רבים. מסנן lookup מציג רק מתקינים, והוא יכול לסנן לפי הרשומה הנוכחית, לפי הרשומה שמחפשים, ולפי המשתמש: הפרופיל, התפקיד או ההרשאות שלו (Lookup Filters (opens in a new tab)). זו דרך זולה לשמור על lookup ישר.

Master-Detail: הילד הזה שייך להורה ההוא

Section titled “Master-Detail: הילד הזה שייך להורה ההוא ”

Master-detail אומר משהו הרבה יותר חזק. בכיתה אני קורא לזה קשירה הדוקה מאוד. אי אפשר שיהיה detail בלי ה-master שלו; שדה ה-master הוא חובה. ה-detail מאבד את שדה ה-Owner שלו ויורש את הבעלים של ההורה שלו. אין טבלת שיתוף נפרדת ל-detail, ולכן אי אפשר לשתף ילד בפני עצמו; הוא יורש את השיתוף של ההורה שלו. בגלל זה לאובייקט detail לא יכולים להיות כללי שיתוף, שיתוף ידני או תורים: כולם צריכים שדה Owner (Object Relationships Overview (opens in a new tab)). ב-Setup הגדרת השיתוף שלו היא Controlled by Parent (בשליטת ההורה). ובשדה ה-master-detail עצמו בוחרים Sharing Setting: האם משתמש צריך גישת Read Only או Read/Write ל-master כדי ליצור, לערוך או למחוק את רשומות ה-detail שלו. מחיקת ה-master מוחקת את רשומות ה-detail שלו. וה-master מקבל שדות סיכום מצטבר (roll-up summary).

אז אם פריט משלוח הוא detail של משלוח, אני אומר: הפריט הזה שייך למשלוח הזה לכל חייו. זו השאלה שאני רוצה שתקבל תשובה לפני שמישהו בוחר Master-Detail Relationship ב-Setup.

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

לשותף קמעונאי יש מאות אלפי משלוחים היסטוריים. מישהו מוחק את השותף. האם המשלוחים צריכים להיעלם? כמעט בוודאות לא: התביעות, החיוב וההיסטוריה כולם תלויים בהם. אולי בכלל לא צריך לאפשר מחיקה של שותף, ובמקום זה להפוך אותו ללא פעיל. ב-master-detail, מחיקת ה-master מתגלגלת לרשומות ה-detail ולרשומות ה-detail שלהן; שחזור ה-master מחזיר אותן (Considerations for Object Relationships (opens in a new tab)). אז כשמישהו אומר “master-detail נותן לנו roll-ups”, התשובה שלי היא: מצוין. למה עוד הסכמתם עכשיו?

ב-lookup, לילד יכולים להיות בעלים משלו. ב-master-detail, לא; הגישה הולכת אחרי ה-master. זה בדיוק נכון אם ה-detail באמת חלק מההורה. אבל אם הילד צריך בעלים משלו, שיתוף משלו או מחזור חיים משלו, המודל אומר לכם ש-master-detail הוא הבחירה הלא נכונה. היחידה הבאה נכנסת לעומק הבעלות, והקורס Sharing and Visibility הולך עוד יותר רחוק. בינתיים: תכנון קשרים ותכנון אבטחה הם לא שיחות נפרדות. מודל הנתונים מעצב את מודל האבטחה לפני שמישהו כותב כלל שיתוף.

הורה חובה, או אופציונלי?

Section titled “הורה חובה, או אופציונלי? ”

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

האם הילד יכול להחליף הורים?

Section titled “האם הילד יכול להחליף הורים? ”

כברירת מחדל, אי אפשר להעביר ילד ב-master-detail להורה אחר. אפשר לאפשר את זה, על ידי בחירה ב-Allow reparenting בקשר (Considerations for Object Relationships (opens in a new tab)). האינסטינקט שלי שמרני: אם העסק אומר שהילד שייך להורה אחד לכל החיים, אני לא הופך את ההעברה שלו לקלה. פריט שעובר ממשלוח אחד לאחר צריך להיות אירוע עסקי מכוון, לא עריכת שדה. שוב, ההגדרה היא לא הארכיטקטורה. כלל מחזור החיים הוא הארכיטקטורה, וההגדרה מממשת אותו.

עוד שני דברים שתופסים צוותים בהמשך. אי אפשר ליצור קשר master-detail באובייקט שכבר יש בו נתונים; יוצרים lookup, ממלאים אותו בכל רשומה, ואז ממירים. ואפשר להמיר חזרה ל-lookup רק אם אין שדות roll-up summary על ה-master. שימו לב גם למה שההמרה עושה לאבטחה: הפיכת lookup ל-master-detail מגדירה את השיתוף של הילד ל-Controlled by Parent, והפיכת master-detail חזרה ל-lookup מגדירה את ברירת המחדל הארגונית (organization-wide default) של הילד ל-Public Read/Write (Considerations for Object Relationships (opens in a new tab)). רשומות שהיו פרטיות אתמול פתוחות היום, עד שמישהו שם לב. בחרו מוקדם.

Roll-ups שימושיים, אבל הם לא בחינם

Section titled “Roll-ups שימושיים, אבל הם לא בחינם ”

אני אוהב roll-ups. לספור את הפריטים במשלוח, לסכם את סכומי השורות בחשבונית, למצוא את התאריך האחרון: מובנה, בלי קוד. שדה ה-master-detail נמצא על הילד, אבל ה-roll-up נמצא על ההורה. אבל יש להם אותיות קטנות (Roll-Up Summary Field (opens in a new tab)):

  • חישוב ערכי roll-up אחרי שינויים מסוימים (שדה roll-up חדש, נוסחה שהוא תלוי בה שהשתנתה, חישוב מחדש כפוי) יכול לקחת עד 30 דקות, תלוי בכמה רשומות מושפעות. ראיתי אנשים תוהים למה המספר על ההורה עוד לא השתנה.
  • הם לא יכולים לסכם הכול. Auto number לא יכול להיות השדה שמצרפים. ו-roll-up יכול לסכם שדה נוסחה רק אם הנוסחה הזו לא מגיעה לאובייקט אחר ולא משתמשת בפונקציה שמשתנה מעצמה, כמו NOW() או TODAY(). נוסחת “ימי איחור” שבנויה על TODAY() משתנה כל לילה בלי שאף אחד שומר רשומה, כך שאין ל-roll-up ממה לחשב מחדש. מספר כזה צריך flow מתוזמן, או דוח.
  • גם למסנן יש מגבלות: בלי long text area, רשימת בחירה מרובה, Description, שדות מערכת כמו Last Activity, נוסחאות בין-אובייקטיות או שדות lookup.
  • Roll-ups לא נמצאים בעמודי עריכה, כך שכלל אימות יכול להשתמש באחד אבל לא יכול להציג שם את השגיאה שלו.

ואל תהפכו את סדר ההחלטה. אל תגידו “אנחנו צריכים roll-up, אז זה חייב להיות master-detail.” תגידו “הילד הזה באמת שייך להורה הזה, הבעלות ומחזור החיים מתאימים, ואחד היתרונות הוא roll-ups מובנים.” אם הסמנטיקה לא מתאימה, פתרו את החישוב בדרך אחרת. אל תעוותו את מודל הנתונים כדי לקבל יכולת.

אז מה הדרך האחרת? בונים את ה-roll-up בעצמכם: שדה על ההורה שמחזיק את הערך המחושב, ואוטומציה ששומרת אותו עדכני. נגיד ששותף קמעונאי הוא lookup ממשלוח, כמו שצריך, והעסק רוצה Open Deliveries (משלוחים פתוחים) על השותף. הוסיפו לשותף שדה מספר, Open Deliveries. ואז record-triggered flow, או Apex trigger כשהנפח או הלוגיקה דורשים קוד, מחשב אותו מחדש בכל פעם שמשלוח משתנה. זה עובד מעל lookup, אפשר לסנן לפי כל דבר, ואפשר להשתמש בתאריכים ובנוסחאות שה-roll-up המובנה לא יכול.

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

שלוש רמות עומק: ערימת master-details

Section titled “שלוש רמות עומק: ערימת master-details ”

לפלטפורמה יש צורה, ול-master-detail יש שני ממדים שלה. הראשון הוא עומק.

אפשר לערום master-details לעומק של שלוש רמות detail מותאמות אישית, וזה הקרקעית (Considerations for Object Relationships (opens in a new tab)). בכיתה אני מצייר את זה כחשבון עם הזמנה (אחת), ההזמנה עם הפריטים שלה (שתיים), והפריטים עם הפרטים שלהם (שלוש), ואז אני מנסה להוסיף רביעית ו-Salesforce לא נותנת לי. ב-Steve Trucking זה יכול להיראות כך: משלוח (Delivery) הוא ה-master; פריטי המשלוח (Delivery Items) שלו הם הרמה הראשונה; משימות ההתקנה (Install Tasks) של פריט הן השנייה; ושלבי המשימה (Task Steps) של כל משימה הם השלישית. רמה רביעית, נגיד Step Note (הערת שלב), חייבת להיות lookup.

שלוש רמות של master-detail שלושה קשרי master-detail מוערמים ב-Steve Trucking, משורטטים בקווים עבים. משלוח הוא ה-master. פריט משלוח הוא detail ברמה 1, משימת התקנה ברמה 2, ושלב במשימה ברמה 3. הערת שלב תלויה על שלב במשימה בקו lookup דק, כי רמה רביעית חייבת להיות lookup. מתחת: בעלות, שיתוף ומחיקה זורמים מהמשלוח למטה לכל רמה. רמה 1 רמה 2 רמה 3 רמה רביעית היא lookup משלוח Delivery__c · master פריט משלוח Delivery_Item__c משימת התקנה Install_Task__c שלב במשימה Task_Step__c הערת שלב Step_Note__c בעלות, שיתוף ומחיקה זורמים מהמשלוח למטה לכל רמה. בדיוק אחד אפס או אחד אחד או רבים אפס או רבים master-detail lookup © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

כמה כללים מגיעים עם הערימה:

  • אובייקטים סטנדרטיים לא יכולים להיות בצד ה-detail של אובייקט מותאם אישית. אובייקט מותאם אישית יכול להיות detail של Account; Account לא יכול להיות detail של האובייקט שלכם.
  • אובייקט יכול להופיע רק פעם אחת בערימה רב-שכבתית. Salesforce לא רוצה שתסתובבו חזרה לעצמכם: תת-detail לא יכול להיות גם ה-master של ה-master שלו.
  • ה-master לא יכול לעשות roll-up לרמה התחתונה ישירות. אם המשלוח רוצה את מספר שלבי המשימה, משימת ההתקנה עושה roll-up לשלבים שלה, פריט המשלוח עושה roll-up ל-roll-ups האלה, והמשלוח עושה roll-up לפריטים: רמה אחת בכל פעם.
  • בעלות ושיתוף מגיעים מלמעלה. כל רמה יורשת את הבעלים ואת הגישה של ה-master.
  • מחיקת ה-master מוחקת את כל מה שמתחתיו, ושחזורו מחזיר הכול.

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

לשבור את השרשרת עם lookup אותם חמישה אובייקטים של Steve Trucking כמו בערימה של שלוש רמות, עם lookup באמצע. משלוח הוא master, ופריט משלוח הוא ה-detail שלו בקו master-detail עבה. פריט משלוח מקושר למשימת התקנה בקו lookup דק ששובר את השרשרת. משימת התקנה היא master חדש: שלב במשימה הוא ה-detail שלה, והערת שלב היא detail של שלב במשימה, שניהם בקווי master-detail עבים. מתחת: למשימת ההתקנה יש עכשיו בעלים ושיתוף משלה, ומחיקת משלוח כבר לא מוחקת את משימות ההתקנה שלו. רמה 1 lookup שובר את השרשרת רמה 1 רמה 2 משלוח Delivery__c · master פריט משלוח Delivery_Item__c משימת התקנה Install_Task__c · master חדש שלב במשימה Task_Step__c הערת שלב Step_Note__c למשימת ההתקנה יש עכשיו בעלים ושיתוף משלה, ומחיקת משלוח כבר לא מוחקת את משימות ההתקנה שלו. בדיוק אחד אפס או אחד אחד או רבים אפס או רבים master-detail lookup © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

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

שני הורים לרוחב: אובייקט הצומת של Salesforce

Section titled “שני הורים לרוחב: אובייקט הצומת של Salesforce ”

קודם, מילה על מילים, כי ל-”junction object” יש שתי משמעויות, ואני מלמד את שתיהן.

בפרק 2 מצאנו את אובייקט הצומת הלוגי: הצומת של שני רעיונות מפתח שהופך לדבר בפני עצמו, עם מאפיינים משלו. כלב יודע הרבה תרגילים, תרגיל ידוע להרבה כלבים, והתרגיל של הכלב (Dog Trick) יושב ביניהם ומחזיק את רמת המיומנות ואת התאריך. זה אובייקט צומת לוגי, במודל הלוגי, הרבה לפני שמישהו מחליט lookup או master-detail.

Salesforce משתמשת במונח בצורה צרה יותר. כש-Salesforce אומרת junction object, היא מתכוונת לאובייקט מותאם אישית עם שני קשרי master-detail (Create a Many-to-Many Object Relationship (opens in a new tab)). לזה אקרא אובייקט הצומת של Salesforce (Salesforce Junction Object). כל אובייקט צומת של Salesforce הוא אובייקט צומת לוגי, אבל לא כל אובייקט צומת לוגי הופך לאובייקט צומת של Salesforce: בנו אחד עם master-detail ו-lookup, או עם שני lookups, והוא עדיין אובייקט צומת לוגי, רק לא מהסוג של Salesforce. (Salesforce עצמה לא עקבית לגמרי: ה-object reference שלה קורא לכמה אובייקטים סטנדרטיים שבנויים על lookups “junction objects”. במבחן, הניחו את ההגדרה הצרה.)

ידע למבחן. אובייקט הצומת של Salesforce הוא אובייקט מותאם אישית עם שני קשרי master-detail, וזה מה ש-Salesforce מתכוונת אליו כשהיא אומרת “junction object”. אובייקט הצומת הלוגי הוא רעיון המידול הרחב יותר: כל אובייקט שמחבר שני אובייקטים אחרים בקשר רבים-לרבים ונושא מאפיינים משלו, איך שלא ייבנה.

הממד השני הוא רוחב. האם לילד יכולים להיות שני הורי master-detail? כן. שלושה? לא. לכל אובייקט מותאם אישית יכולים להיות עד שני קשרי master-detail (Considerations for Object Relationships (opens in a new tab)). שני הורי master-detail הם הדרך לבנות אובייקט צומת של Salesforce לקשר רבים-לרבים. צוות ומשאית נפגשים בשיבוץ צוות (Crew Assignment), וכמו שמצאנו בפרק 2, זה לא צנרת: יש לו תאריך, מסלול, אולי סטטוס. הצומת הוא המקום שבו הקשר הופך למושג עסקי. הטיפים של Salesforce לבניית אחד: תנו לו שם שאומר מה הוא, הפכו את שם הרשומה שלו ל-auto number, ושנו את שם הרשימה הקשורה של כל master לשם ה-master האחר, כך שבעמוד של הצוות מופיע “Trucks” ובעמוד של המשאית מופיע “Crews” (Create a Many-to-Many Object Relationship (opens in a new tab)).

הנה המורכבות. אחד משני ההורים הוא הראשי (primary), וזה ההורה ששדה ה-master-detail שלו נוצר ראשון. אין שום סימן חזותי שמראה איזה מהם זה, אז זו שאלת מבחן קלאסית, והפתעה קלאסית.

מה הראשי קובע? שלושה דברים (Create a Many-to-Many Object Relationship (opens in a new tab)):

  • מראה ותחושה. העמודים של הצומת משתמשים בצבע ובאייקון של ה-master הראשי.
  • בעלים. רשומות הצומת יורשות את הבעלים של רשומת ה-master הראשית. אתם אף פעם לא רואים את זה, כי ל-detail אין שדה Owner; זה חשוב רק אם בהמשך תסירו את שני קשרי ה-master-detail.
  • Division (חטיבה), אם ה-org שלכם משתמש בחטיבות, באותה צורה.

והשני הוא המשני (secondary). מה זה אומר?

  • הוא בתור להפוך לראשי. מחקו את שדה ה-master-detail הראשי או המירו אותו ל-lookup, והמשני הופך לראשי.
  • הוא קובע את היקף הדוחות. Salesforce נותנת לכם שני סוגי דוחות: “Primary master with junction object and secondary master” ו-”Secondary master with junction object and primary master”. ה-master שמופיע ראשון קובע אילו רשומות הדוח יכול להציג.
  • הוא נחשב בדיוק באותה מידה לגישה. כך אני מנסח את זה: בעלות מהראשי, גישה משניהם, והמגביל ביותר מנצח. לצומת, כמו לכל detail, אין טבלת שיתוף משלו. Salesforce בודקת את הגישה של המשתמש לשתי רשומות ה-master, דרך ה-Sharing Setting של כל שדה master-detail. אם שניהם מוגדרים ל-Read/Write, המשתמש צריך Read/Write על הצוות וגם על המשאית כדי לערוך את שיבוץ הצוות (Considerations for Object Relationships (opens in a new tab)).
  • הוא מוחק בדיוק באותה מידה. מחקו כל אחד מה-masters, הצוות או המשאית, ורשומות הצומת שלו הולכות לסל המיחזור (Recycle Bin). מחקו את שניהם והן נעלמות לתמיד.
הראשי והמשני של אובייקט צומת אובייקט צומת מתחת לשני הורי ה-master-detail שלו, משורטט בקווים עבים. צוות, למעלה משמאל, הוא הראשי, כי שדה ה-master-detail שלו נוצר ראשון; הוא נותן לשיבוץ הצוות את הבעלים ואת המראה. משאית, למעלה מימין, היא המשנית; היא קובעת את ההיקף של סוג הדוח השני והופכת לראשית אם הקשר הראשון מוסר. שיבוץ צוות יושב ביניהם ומתחתם. מתחת: גישה דורשת את שני ההורים, והמגביל ביותר מנצח; מחקו אחד מההורים, והשיבוץ נעלם גם הוא. בעלים ומראה היקף הדוח צוות Crew__c · ראשי: נוצר ראשון משאית Truck__c · משני שיבוץ צוות Crew_Assignment__c גישה דורשת את שני ההורים: המגביל ביותר מנצח. מחקו אחד מההורים, והשיבוץ נעלם גם הוא. בדיוק אחד אפס או אחד אחד או רבים אפס או רבים master-detail © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

עוד כמה כללים: לשני ה-masters יכולים להיות roll-up summaries מהצומת, והנוסחאות וכללי האימות של הצומת יכולים להגיע לשדות בשניהם. אבל צומת לא יכול להיות master של שום דבר אחר, כך שהוא לא יכול לשבת באמצע ערימה, ושני ה-masters לא יכולים להיות אותו אובייקט; קשר רבים-לרבים מאובייקט לעצמו דורש תכנון אחר. ואם להורה יש יותר מ-200 רשומות צומת והצומת עושה roll-up להורה האחר, Salesforce לא תיתן לכם למחוק את ההורה הזה עד שתסירו מספיק מהן.

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

אחרי כל זה, בסוף אין לי הרבה אובייקטי צומת של Salesforce. בדרך כלל לאובייקט יש הורה master-detail אחד, והוא מאותו סוג נתונים: נתוני לקוח תחת נתוני לקוח, נתוני תנועות תחת נתוני תנועות (זכרו את סוגי הנתונים מפרק 2: לקוח, תנועות, ייחוס). כשההורה האחר שלו הוא מסוג אחר, בדרך כלל אובייקט ייחוס, הקשר הזה הוא lookup. פריט משלוח שייך למשלוח שלו: master-detail, שניהם נתוני תנועות. הוא מצביע על המוצר שהוא נושא עם lookup, כי מוצר הוא נתוני ייחוס עם חיים משלו, ואף אחד לא רוצה שמחיקת מוצר תיקח איתה שנים של היסטוריית משלוחים. פריט משלוח הוא עדיין אובייקט צומת לוגי בין משלוח לבין המוצרים שבו; הוא פשוט לא אובייקט צומת של Salesforce.

קשרים עצמיים: כשהקו חוזר

Section titled “קשרים עצמיים: כשהקו חוזר ”

אובייקט יכול להתקשר לעצמו: חשבון אם, מנהל, מרכז הפצה שכפוף למוקד אזורי. Salesforce בונה מראש שניים שתפגשו כמעט בכל org: Account ל-Account, השדה Parent Account שבונה את היררכיית החשבונות, ו-Case ל-Case, ה-Parent Case מיחידה 2 שמקבץ פניות קשורות. קשר עצמי חייב להיות lookup, ורשומה לא יכולה להצביע על עצמה, אם כי שתי רשומות יכולות להצביע זו על זו (Considerations for Object Relationships (opens in a new tab)). באובייקט User זה סוג מיוחד משלו, הקשר ההיררכי, שמשמש לדברים כמו המנהל של משתמש. המכניקה קלה; השם הוא מה שחשוב. Lookup ממרכז הפצה למרכז הפצה שנקרא Distribution_Center__c לא עוזר לאף אחד. הורה? גיבוי? עודף? תנו לקשר שם לפי התפקיד, לא לפי האובייקט שהוא מצביע עליו.

קשרים עצמיים שלושה אובייקטים, לכל אחד lookup לעצמו. חשבון, דרך השדה ParentId שלו, מצביע על חשבון הורה, וכך נבנית היררכיית החשבונות. פנייה, דרך השדה ParentId שלה, מצביעה על פניית הורה. מרכז הפצה, אובייקט מותאם אישית, מצביע על הרכזת האזורית שלו דרך שדה בשם Regional_Hub__c. מתחת: תמיד lookup, אף פעם לא לאותה רשומה, ונקרא על שם התפקיד שהוא ממלא. חשבון הורה פניית הורה רכזת אזורית חשבון Account · ParentId פנייה Case · ParentId מרכז הפצה Distribution_Center__c · Regional_Hub__c תמיד lookup, אף פעם לא לאותה רשומה, ונקרא על שם התפקיד שהוא ממלא. בדיוק אחד אפס או אחד אחד או רבים אפס או רבים lookup © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

היררכי: הקשר הייחודי של האובייקט User

Section titled “היררכי: הקשר הייחודי של האובייקט User ”

זה קטן, וזה בדיוק סוג העובדה הייחודית והלא מוכרת שהייתי מצפה שמבחן ישתמש בה. Hierarchical (היררכי) הוא lookup מיוחד שקיים רק באובייקט User. הוא מקשר משתמש אחד למשתמש אחר, ו-Salesforce לא נותנת לשרשרת לחזור על עצמה: משתמש לא יכול להצביע על עצמו, ישירות או בעקיפין (Object Relationships Overview (opens in a new tab)). אם המנהל של Maria הוא Dev, המנהל של Dev לא יכול להיות Maria, או מישהו שכפוף ל-Maria.

זה ההבדל מהקשרים העצמיים שלמעלה. ב-Account או באובייקט מותאם אישית, שתי רשומות יכולות להצביע זו על זו. ב-User, ההיררכיה חייבת להישאר היררכיה. וזו הדרך היחידה לקשר User ל-User: lookup רגיל מ-User לעצמו לא מוצע.

כבר יש לכם אחד. השדה הסטנדרטי Manager ב-User הוא קשר היררכי, ותהליכי אישור יכולים להשתמש בו: לשלוח את הבקשה הזו למנהל של מי שהגיש אותה. אפשר גם ליצור משלכם, נגיד Escalation Contact או Backup Approver, ותהליך אישור יכול לנתב לאורכו באותה צורה (ApprovalProcess, Metadata API (opens in a new tab)). אל תבלבלו אותו עם היררכיית התפקידים, שמניעה גישה לרשומות. שדה היררכי הוא רק קשר בין משתמשים; הוא לא משתף אף רשומה.

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

לכל אובייקט יכולים להיות לכל היותר שני קשרי master-detail. שדות lookup ו-master-detail ביחד נספרים כשדות קשר: 40 לאובייקט כברירת מחדל, 50 לכל היותר לפי בקשה. שדות roll-up summary: 25 לאובייקט כברירת מחדל, 40 לכל היותר (Increase the Maximum Relationships Allowed per Object (opens in a new tab); Increase the Maximum Limit of Roll-Up Summary Fields (opens in a new tab)). Salesforce מוסיפה שהגדלת כל אחת מהמגבלות יכולה להשפיע על הביצועים.

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

ואז יש את ההורה עם יותר מדי ילדים. ההנחיה של Salesforce עצמה היא לא לעבור בערך 10,000 רשומות ילד להורה master-detail אחד (Considerations for Object Relationships (opens in a new tab)), והמדריך שלה לגישה לרשומות בקנה מידה גדול אומר אותו דבר על קשרי הורה-ילד באופן כללי (Parent-Child Data Skew (opens in a new tab)). רשומה 10,001 לא שוברת את ה-org. אבל מעבר לנקודה הזו, שמירת ילד יכולה לנעול את ההורה, ושינויי שיתוף בהורה מתגלגלים דרך כל ילד.

אז כשאני רואה הורה אחד, מספרים עצומים של ילדים, אני שואל: למה כולם תחת אותו הורה, מי הבעלים שלהם, איך שואלים עליהם, ואיזו אוטומציה נוגעת בהורה? כל משלוח תחת חשבון “Steve Trucking” יחיד היה עובר את 10,000 תוך כמה ימים. קשר אחד-לרבים תמים הופך לבעיית skew. היחידה הבאה נותנת הצצה ל-skew, וחלק 2 נכנס לעומק.

אל תתכננו את הקו לפי יכולת

Section titled “אל תתכננו את הקו לפי יכולת ”

זה ההרגל שאני רוצה מהיחידה הזו. אל תתחילו מ”אני צריך roll-up”, “אני צריך שזה יהיה חובה”, “אני רוצה שיתוף בירושה”. אלה רמזים למימוש. התחילו מהעסק: האם לילד יש חיים משלו, מי הבעלים שלו, האם הוא יכול להתקיים לבד, האם הוא יכול לזוז, מה קורה כשההורה הולך, האם הקשר נושא נתונים, וכמה גדול כל צד יכול להיות? ואז בחרו את הקשר שמממש את התשובות.

Lookup, master-detail או צומת? מטריצה של שלושה דפוסי קשר מול שש שאלות עסקיות. Lookup: הצאצא יכול להתקיים לבד, יש לו בעלים משלו, הוא יכול להחליף הורה, והוא מתמודד עם יותר מ-10,000 צאצאים להורה, אם כי עדיין צריך לשים לב ל-skew; כברירת מחדל הוא לא הולך עם ההורה (השדה מתרוקן או שהמחיקה נחסמת) ומחזיק הורה אחד לכל שדה. המשמעות: מחובר. Master-detail: ההורה חובה, הצאצא יורש את הבעלים של ההורה, הוא נמחק במחיקה מדורגת עם ההורה, הוא מחליף הורה רק אם החלפת הורה מותרת, ויותר מ-10,000 צאצאים מביאים נעילות הורה וחישוב מחדש. המשמעות: שייך ל. אובייקט הצומת של Salesforce (Salesforce Junction Object): צריך את שני ההורים, לוקח את הבעלים מהראשי, נמחק עם כל אחד מההורים, והוא הדפוס היחיד לרבים בשני הצדדים. המשמעות: מושג עסקי. מתחת: ענו קודם על השאלות העסקיות; סוג הקשר נובע מהן. קיים לבד בעלים משלו הולך עם ההורה מחליף הורה רבים בשני הצדדים 10,000+ להורה המשמעות Lookup משלוח ← מסלול ריקון או חסימה, כברירת מחדל הורה אחד לכל שדה עדיין לשים לב ל-skew מחובר Master-detail משלוח ← פריט משלוח הורה חובה יורש מההורה מחיקה מדורגת רק אם החלפת הורה מופעלת מקור אב אחד לכל שדה נעילות הורה, חישובים מחדש שייך ל אובייקט הצומת של Salesforce צוות + משאית ← שיבוץ צוות צריך את שני ההורים מהראשי כל אחד מההורים מוחק אותו רק אם החלפת הורה מופעלת זה התפקיד שלו אותה הנחיה של 10,000 מושג עסקי ענו קודם על השאלות העסקיות. סוג הקשר נובע מהן; אל תתחילו מהתכונה שאתם רוצים. © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

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

  • האם לילד יש מחזור חיים משלו או שהוא באמת שייך להורה, והאם הבעלות והגישה צריכות להיות שלו או בירושה.
  • האם הילד יכול להתקיים בלי הורה, לעבור בין הורים, או לשרוד את מחיקת ההורה.
  • מה כל lookup עושה כשההורה שלו נמחק: מנקה, חוסם, או מוחק בדירוג.
  • האם קשר רבים-לרבים הוא צנרת או מושג עסקי, האם אובייקט הצומת הלוגי הופך לאובייקט צומת של Salesforce, איזה הורה הוא הראשי, ומה שני ההורים אומרים לגבי גישה.
  • האם המודל מתאים לצורה של הפלטפורמה: שלוש רמות detail מותאמות אישית לעומק, שני הורי master-detail לרוחב, מגבלות הקשרים וה-roll-ups.
  • האם המספר וההתפלגות הצפויים של הילדים יוצרים סיכון skew שצריך לשנות את התכנון.

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