ความสัมพันธ์มีผลตามมา
มีให้อ่านอีก 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)

โมดูลที่ 7 จาก 10 ในบท สถาปัตยกรรมข้อมูล Salesforce บทที่ 3 ของหลักสูตร Data Architect แต่ละโมดูลอ่านแยกกันได้ ก่อนหน้า: ฟิลด์ก็คือสถาปัตยกรรม · ถัดไป: ความเป็นเจ้าของและวงจรชีวิต
คำถามที่โมดูลนี้ตอบ: ฉันกำลังเลือกอะไรจริงๆ เมื่อเชื่อมออบเจกต์ Salesforce สองตัวเข้าด้วยกัน?
การวาดความสัมพันธ์นั้นง่าย ในบทที่ 2 เราวาดเส้นและตั้งชื่อมัน: พันธมิตรค้าปลีกส่งใบรายการสินค้าหลายใบ การจัดส่งหนึ่งรายการขนสินค้าหลายรายการ ทีมจัดส่งและรถบรรทุกมาพบกันในการมอบหมายทีม เราคุยเรื่อง cardinality ความเป็นทางเลือก และประวัติ ตอนนี้เรา implement เส้นเหล่านั้นบน Salesforce และเส้นบนไดอะแกรมก็เริ่มแบกน้ำหนักมากขึ้นมาก
เมื่อผมเลือกประเภทความสัมพันธ์บน Salesforce ผมไม่ได้แค่บอกว่า สองเรกคอร์ดนี้เชื่อมกัน ผมอาจกำลังตัดสินด้วยว่าใครเป็นเจ้าของลูก ลูกมีอยู่ได้โดยไม่มีแม่ไหม ใครเห็นมันได้ จะเกิดอะไรขึ้นเมื่อแม่ถูกลบ มันย้ายไปอยู่กับแม่ตัวอื่นได้ไหม ผมสรุปยอดมันขึ้นไปที่แม่ได้ไหม และจะเกิดอะไรขึ้นเมื่อมีลูกหลายแสนรายการ ความสัมพันธ์ไม่ใช่แค่เส้น มันแบกพฤติกรรม
เริ่มจากความสัมพันธ์ทางธุรกิจ
หัวข้อที่มีชื่อว่า “เริ่มจากความสัมพันธ์ทางธุรกิจ ”ก่อนจะพูดถึง lookup หรือ master-detail ให้กลับไปที่ธุรกิจ ลองดูการจัดส่งกับรายการจัดส่งของมัน: ตู้เย็น การติดตั้ง การขนของเก่าทิ้ง รายการหนึ่งมีอยู่ได้โดยไม่มีการจัดส่งของมันไหม? ไม่ได้ ถ้าการจัดส่งถูกลบ รายการของมันควรถูกลบไปด้วยไหม? ควร รายการต้องการเจ้าของหรือความปลอดภัยของตัวเองไหม? ไม่จริง ควรมีใครย้ายรายการจากการจัดส่งหนึ่งไปอีกการจัดส่งไหม? หวังว่าจะไม่เกิดโดยบังเอิญ
ทีนี้ลองดูการจัดส่งกับเส้นทางที่มันอยู่ การจัดส่งมีอยู่ก่อนถูกจัดเส้นทาง ย้ายไปเส้นทางอื่นได้เมื่อแผนเปลี่ยน และการลบเส้นทางไม่ควรลบการจัดส่งบนนั้นเลย สองเส้นแบบหนึ่งต่อหลายที่ดูเหมือนกันบนไดอะแกรม แต่พฤติกรรมต่างกันโดยสิ้นเชิง สังเกตว่าเรายังไม่ได้พูดว่า “lookup” หรือ “master-detail” อธิบายพฤติกรรมก่อน การตั้งค่าจะ implement มัน
ประเภทของความสัมพันธ์
หัวข้อที่มีชื่อว่า “ประเภทของความสัมพันธ์ ”เปิดหน้าจอ New Field แล้ว Salesforce จะเสนอประเภทความสัมพันธ์ให้คุณจำนวนหนึ่ง (Object Relationships Overview (opens in a new tab) ภาษาอังกฤษ):
- Lookup: เชื่อมสองออบเจกต์ เป็นข้าวปลาอาหารหลักของความสัมพันธ์ใน Salesforce
- Master-detail: การผูกแม่กับลูก โดยแม่ควบคุมลูก
- Many-to-many (หลายต่อหลาย): ไม่ใช่ประเภทฟิลด์ของตัวเอง แต่เป็นรูปแบบ: Junction Object ของ Salesforce (ออบเจกต์ที่กำหนดเองที่มีความสัมพันธ์ master-detail สองชุด)
- Self-relationship (ความสัมพันธ์กับตัวเอง): lookup จากออบเจกต์หนึ่งไปหาตัวมันเอง
- Hierarchical (ตามลำดับชั้น): lookup แบบพิเศษที่มีเฉพาะบนออบเจกต์ User เช่นผู้จัดการของผู้ใช้
- External lookup และ indirect lookup: ความสัมพันธ์ไปและมาจากออบเจกต์ภายนอก คือออบเจกต์
__xจากโมดูลที่ 4 external lookup ชี้ไปที่ออบเจกต์ภายนอกที่เป็นแม่ ส่วน indirect lookup ชี้จากออบเจกต์ภายนอกไปยังออบเจกต์มาตรฐานหรือออบเจกต์ที่กำหนดเอง โดยจับคู่ตาม External ID ที่ไม่ซ้ำ
เวลาออกแบบส่วนใหญ่ของคุณจะหมดไปกับสามแบบแรก มาดูทีละแบบกัน
Lookup: เรกคอร์ดเหล่านี้เชื่อมกัน
หัวข้อที่มีชื่อว่า “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 filter (ตัวกรอง lookup) จำกัดสิ่งที่ผู้ใช้เลือกได้ สมมติว่าการจัดส่งมี lookup ชื่อ Installer ไปที่ผู้ติดต่อ และช่างติดตั้งเป็นประเภทเรกคอร์ดหนึ่งในผู้ติดต่อหลายประเภท ตัวกรอง lookup จะแสดงเฉพาะช่างติดตั้ง และกรองได้ตามเรกคอร์ดปัจจุบัน ตามเรกคอร์ดที่ถูก lookup และตามผู้ใช้: โปรไฟล์ บทบาท หรือสิทธิ์ของเขา (Lookup Filters (opens in a new tab) ภาษาอังกฤษ) เป็นวิธีราคาถูกที่ทำให้ lookup ซื่อตรง
Master-Detail: ลูกนี้เป็นของแม่นั้น
หัวข้อที่มีชื่อว่า “Master-Detail: ลูกนี้เป็นของแม่นั้น ”master-detail ประกาศสิ่งที่หนักแน่นกว่ามาก ในคลาสผมเรียกมันว่าการผูกที่แน่นมาก คุณมี detail โดยไม่มี master ไม่ได้ ฟิลด์ master บังคับกรอก detail สูญเสียฟิลด์ Owner ของตัวเอง และสืบทอดเจ้าของของแม่ ไม่มี share table แยกสำหรับ detail คุณจึงแชร์ลูกแยกเดี่ยวไม่ได้ มันสืบทอดการแชร์ของแม่ นั่นคือเหตุผลที่ออบเจกต์ detail มีกฎการแชร์ การแชร์ด้วยตนเอง หรือคิวไม่ได้: ทั้งหมดต้องใช้ฟิลด์ Owner (Object Relationships Overview (opens in a new tab) ภาษาอังกฤษ) ในการตั้งค่า การตั้งค่าการแชร์ของมันจะแสดงว่า 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 ของ detail การกู้คืน master จะนำพวกมันกลับมา (Considerations for Object Relationships (opens in a new tab) ภาษาอังกฤษ) ดังนั้นเมื่อมีคนพูดว่า “master-detail ให้ roll-up กับเรา” คำตอบของผมคือ: เยี่ยม แล้วคุณเพิ่งตกลงอะไรอีกบ้าง?
ความเป็นเจ้าของติดมาด้วย
หัวข้อที่มีชื่อว่า “ความเป็นเจ้าของติดมาด้วย ”ด้วย lookup ลูกมีเจ้าของของตัวเองได้ ด้วย master-detail ไม่ได้ การเข้าถึงตาม master นั่นถูกต้องพอดีถ้า detail เป็นส่วนหนึ่งของแม่จริงๆ แต่ถ้าลูกต้องการเจ้าของของตัวเอง การแชร์ของตัวเอง หรือวงจรชีวิตของตัวเอง โมเดลกำลังบอกคุณว่า master-detail เป็นตัวเลือกที่ผิด โมดูลถัดไปลงลึกเรื่องความเป็นเจ้าของ และหลักสูตร Sharing and Visibility ไปไกลกว่านั้นอีก สำหรับตอนนี้: การออกแบบความสัมพันธ์และการออกแบบความปลอดภัยไม่ใช่การพูดคุยที่แยกกัน โมเดลข้อมูลกำหนดรูปโมเดลความปลอดภัยก่อนที่ใครจะเขียนกฎการแชร์
แม่บังคับ หรือเป็นทางเลือก?
หัวข้อที่มีชื่อว่า “แม่บังคับ หรือเป็นทางเลือก? ”ลูกมีอยู่ได้ก่อนที่เราจะรู้ว่าแม่ของมันคือใครไหม? เรื่องนี้สำคัญกว่าที่ฟัง ถ้าการจัดส่งมาถึงในใบรายการสินค้าตั้งแต่คืนก่อน และเส้นทางถูกสร้างทีหลัง การบังคับให้มีเส้นทางบนการจัดส่งก็หมายความว่าต้องจัดเส้นทางก่อนจะสร้างเรกคอร์ดได้ด้วยซ้ำ ความสัมพันธ์เชิงกายภาพต้องรองรับวงจรชีวิตจริง ดังนั้นผมจึงไม่ออกแบบความสัมพันธ์จากไดอะแกรมนิ่งๆ อย่างเดียว ผมอยากรู้ว่า: มันเกิดอย่างไร อยู่เดี่ยวได้ไหม ย้ายได้ไหม และตายอย่างไร?
ลูกเปลี่ยนแม่ได้ไหม?
หัวข้อที่มีชื่อว่า “ลูกเปลี่ยนแม่ได้ไหม? ”โดยค่าเริ่มต้น ลูกแบบ master-detail ย้ายไปอยู่กับแม่ตัวอื่นไม่ได้ คุณอนุญาตได้โดยเลือก Allow reparenting บนความสัมพันธ์ (Considerations for Object Relationships (opens in a new tab) ภาษาอังกฤษ) สัญชาตญาณของผมคือระมัดระวัง: ถ้าธุรกิจบอกว่าลูกเป็นของแม่ตัวเดียวตลอดชีวิต ผมไม่ทำให้การย้ายมันง่าย รายการที่ย้ายจากการจัดส่งหนึ่งไปอีกการจัดส่งควรเป็นเหตุการณ์ทางธุรกิจที่ตั้งใจ ไม่ใช่การแก้ไขฟิลด์ อีกครั้ง การตั้งค่าไม่ใช่สถาปัตยกรรม กฎของวงจรชีวิตต่างหากที่ใช่ และการตั้งค่า implement มัน
มีอีกสองเรื่องที่ทีมมักเจอทีหลัง คุณสร้างความสัมพันธ์ master-detail บนออบเจกต์ที่มีข้อมูลอยู่แล้วไม่ได้ คุณต้องสร้าง lookup กรอกค่าในทุกเรกคอร์ด แล้วจึงแปลง และคุณแปลงกลับเป็น lookup ได้ก็ต่อเมื่อไม่มีฟิลด์สรุปยอดบน 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-up มีประโยชน์ แต่ไม่ได้ฟรี
หัวข้อที่มีชื่อว่า “roll-up มีประโยชน์ แต่ไม่ได้ฟรี ”ผมชอบ roll-up นับรายการในการจัดส่ง รวมยอดเงินของบรรทัดในใบแจ้งหนี้ หาวันที่ล่าสุด: เป็นของในตัว ไม่ต้องเขียนโค้ด ฟิลด์ 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 จึงไม่มีอะไรให้คำนวณใหม่ ตัวเลขแบบนั้นต้องใช้ scheduled flow หรือรายงาน - ตัวกรองก็มีข้อจำกัด: ใช้ฟิลด์ข้อความยาว multi-select picklist, Description ฟิลด์ระบบอย่าง Last Activity สูตรข้ามออบเจกต์ หรือฟิลด์ lookup ไม่ได้
- roll-up ไม่อยู่บนหน้าแก้ไข กฎการตรวจสอบความถูกต้องจึงใช้มันได้ แต่แสดงข้อผิดพลาดตรงนั้นไม่ได้
และอย่ากลับลำดับการตัดสินใจ อย่าพูดว่า “เราต้องการ roll-up ดังนั้นนี่ต้องเป็น master-detail” ให้พูดว่า “ลูกนี้เป็นของแม่นี้จริงๆ ความเป็นเจ้าของและวงจรชีวิตเข้ากัน และหนึ่งในประโยชน์คือ roll-up ในตัว” ถ้าความหมายไม่เข้ากัน ให้แก้เรื่องการคำนวณด้วยวิธีอื่น อย่าบิดโมเดลข้อมูลเพื่อให้ได้ฟีเจอร์
แล้ววิธีอื่นคืออะไร? คุณสร้าง roll-up เอง: ฟิลด์บนแม่ที่เก็บค่าที่คำนวณแล้ว และระบบอัตโนมัติที่ทำให้มันเป็นปัจจุบันอยู่เสมอ สมมติว่าพันธมิตรค้าปลีกเป็น lookup จากการจัดส่ง อย่างที่ควรเป็น และธุรกิจต้องการ Open Deliveries (การจัดส่งที่ยังเปิดอยู่) บนพันธมิตร เพิ่มฟิลด์ตัวเลข Open Deliveries ให้พันธมิตร แล้วให้ record-triggered flow หรือ Apex trigger เมื่อปริมาณหรือตรรกะต้องใช้โค้ด คำนวณมันใหม่ทุกครั้งที่การจัดส่งเปลี่ยน มันทำงานข้าม lookup ได้ กรองตามอะไรก็ได้ และใช้วันที่และสูตรที่ roll-up ในตัวใช้ไม่ได้
แต่ตอนนี้การทำให้ถูกเป็นหน้าที่ของคุณ และนั่นคือจุดที่สิ่งเหล่านี้มักผิดพลาด ระบบอัตโนมัติต้องทำงานในทุกการเปลี่ยนแปลงที่สำคัญ: ลูกใหม่ ลูกที่ถูกแก้ไข ลูกที่ถูกลบ ลูกที่ถูกกู้คืน และลูกที่ย้ายไปอยู่กับแม่คนอื่น ซึ่งหมายถึงต้องคำนวณใหม่ทั้งแม่เก่าและแม่ใหม่ มันต้องรับการโหลดข้อมูลทีละ 200 เรกคอร์ดได้โดยไม่ชนขีดจำกัด นับใหม่ทั้งหมดแทนการบวกลบ เพื่อที่เหตุการณ์ที่หลุดไปครั้งเดียวจะไม่ทำให้ตัวเลขผิดไปตลอดกาล วางแผนวิธีคำนวณใหม่ทั้งหมด สำหรับการโหลดครั้งแรกและสำหรับวันที่ตัวเลขเพี้ยน และจำไว้ว่าการบันทึกลูกทุกครั้งตอนนี้จะอัปเดตแม่ด้วย แม่ที่มีลูกหลายพันรายการจึงนำปัญหาการล็อกที่เราจะได้เห็นในอีกสักครู่กลับมา roll-up ในตัวทำทั้งหมดนั้นให้คุณ ส่วน roll-up ที่สร้างเองคือซอฟต์แวร์ชิ้นเล็กๆ ที่คุณต้องดูแล
ลึกสามชั้น: การซ้อน master-detail
หัวข้อที่มีชื่อว่า “ลึกสามชั้น: การซ้อน master-detail ”แพลตฟอร์มมีรูปร่างของมัน และ master-detail มีรูปร่างนั้นอยู่สองมิติ มิติแรกคือความลึก
คุณซ้อน master-detail ได้ลึกสามชั้น detail ที่กำหนดเอง และนั่นคือก้นบึ้ง (Considerations for Object Relationships (opens in a new tab) ภาษาอังกฤษ) ในคลาสผมวาดเป็นบัญชีที่มีคำสั่งซื้อ (หนึ่ง) คำสั่งซื้อที่มีรายการสินค้า (สอง) และรายการสินค้าที่มีรายละเอียด (สาม) แล้วผมก็ลองเพิ่มชั้นที่สี่ และ Salesforce ไม่ยอม ใน Steve Trucking อาจหน้าตาแบบนี้: การจัดส่ง (Delivery) คือ master รายการจัดส่ง (Delivery Item) ของมันคือชั้นแรก งานติดตั้ง (Install Task) ของรายการคือชั้นที่สอง และขั้นตอนงาน (Task Step) ของแต่ละงานคือชั้นที่สาม ชั้นที่สี่ เช่นบันทึกขั้นตอน (Step Note) ต้องเป็น lookup
การซ้อนมาพร้อมกฎสองสามข้อ:
- ออบเจกต์มาตรฐานอยู่ฝั่ง detail ของออบเจกต์ที่กำหนดเองไม่ได้ ออบเจกต์ที่กำหนดเองเป็น detail ของบัญชีได้ แต่บัญชีเป็น detail ของออบเจกต์ของคุณไม่ได้
- ออบเจกต์หนึ่งปรากฏได้เพียงครั้งเดียวในการซ้อนหลายชั้น Salesforce ไม่อยากให้คุณวนกลับมาที่ตัวเอง: subdetail เป็น master ของ master ของตัวเองไม่ได้
- master ทำ roll-up จากชั้นล่างสุดโดยตรงไม่ได้ ถ้าการจัดส่งต้องการจำนวนขั้นตอนงาน งานติดตั้งต้อง roll-up ขั้นตอนของมัน รายการจัดส่งต้อง roll-up ค่า roll-up เหล่านั้น แล้วการจัดส่งจึง roll-up รายการ: ทีละชั้น
- ความเป็นเจ้าของและการแชร์มาจากชั้นบนสุด ทุกชั้นสืบทอดเจ้าของและสิทธิ์เข้าถึงของ master
- การลบ master จะลบทุกอย่างที่อยู่ใต้มัน และการกู้คืนมันก็นำทุกอย่างกลับมา
สามชั้นมักเพียงพอแล้ว ถ้าการออกแบบของคุณอยากได้ชั้นที่สี่อยู่เรื่อยๆ ให้ถามว่าทุกชั้นเป็นของชั้นที่อยู่เหนือมันไปตลอดชีวิตจริงหรือ และจำไว้ว่าคุณเลือกได้ว่าจะให้ลิงก์ไหนตัดสายโซ่ ชั้นที่สี่ไม่จำเป็นต้องเป็น lookup: บางทีงานติดตั้งอาจไม่ได้เป็นของรายการจัดส่งจริงๆ มันถูกจัดตารางและมอบหมายเป็นของตัวเอง ลิงก์นั้นจึงกลายเป็น lookup และตอนนี้งานติดตั้งก็เริ่มสายโซ่ใหม่ โดยมีขั้นตอนงานและบันทึกขั้นตอนอยู่ใต้มัน เลือกลิงก์ที่ลูกมีชีวิตของตัวเองจริงๆ แล้วให้ลิงก์นั้นเป็น lookup
ตอนนี้งานติดตั้งมีเจ้าของและการแชร์ของตัวเอง การจัดส่งถูกลบได้โดยไม่พางานติดตั้งไปด้วย และงานติดตั้งมีชั้นอยู่ใต้มันได้อีกสองชั้น นั่นคือการแลกเปลี่ยน: สายโซ่สั้นลง และชีวิตของงานติดตั้งเป็นของมันเอง
กว้างสองแม่: Junction Object ของ Salesforce
หัวข้อที่มีชื่อว่า “กว้างสองแม่: Junction Object ของ Salesforce ”ก่อนอื่น ขอพูดเรื่องคำศัพท์สักหน่อย เพราะ “junction object” มีสองความหมาย และผมสอนทั้งสองอย่าง
ในบทที่ 2 เราพบออบเจกต์เชื่อมเชิงตรรกะ (logical junction object): จุดเชื่อมของสองแนวคิดหลักที่กลายเป็นสิ่งของตัวเอง มีแอตทริบิวต์ของตัวเอง สุนัขตัวหนึ่งรู้หลายท่า ท่าหนึ่งเป็นที่รู้จักของสุนัขหลายตัว และท่าของสุนัขอยู่ระหว่างทั้งสอง ถือระดับทักษะและวันที่ไว้ นั่นคือออบเจกต์เชื่อมเชิงตรรกะ ในโมเดลเชิงตรรกะ นานก่อนที่ใครจะตัดสินว่าเป็น lookup หรือ master-detail
Salesforce ใช้คำนี้ในความหมายที่แคบกว่า เมื่อ Salesforce พูดว่า junction object มันหมายถึงออบเจกต์ที่กำหนดเองที่มีความสัมพันธ์ master-detail สองชุด (Create a Many-to-Many Object Relationship (opens in a new tab) ภาษาอังกฤษ) ผมจะเรียกมันว่า Junction Object ของ Salesforce ทุก Junction Object ของ Salesforce เป็นออบเจกต์เชื่อมเชิงตรรกะ แต่ไม่ใช่ทุกออบเจกต์เชื่อมเชิงตรรกะจะกลายเป็น Junction Object ของ Salesforce: สร้างมันด้วย master-detail หนึ่งชุดกับ lookup หนึ่งชุด หรือ lookup สองชุด มันก็ยังเป็นออบเจกต์เชื่อมเชิงตรรกะ แค่ไม่ใช่แบบของ Salesforce (Salesforce เองก็ไม่ได้สม่ำเสมอเสียทีเดียว: เอกสารอ้างอิงออบเจกต์ของมันเรียกออบเจกต์มาตรฐานบางตัวที่สร้างบน lookup ว่า “junction object” ในข้อสอบ ให้ถือตามนิยามแบบแคบ)
ความรู้ที่ออกสอบ Junction Object ของ Salesforce คือออบเจกต์ที่กำหนดเองที่มีความสัมพันธ์ master-detail สองชุด และนั่นคือสิ่งที่ Salesforce หมายถึงเมื่อพูดว่า “junction object” ส่วนออบเจกต์เชื่อมเชิงตรรกะคือแนวคิดการสร้างโมเดลที่กว้างกว่า: ออบเจกต์ใดก็ตามที่เชื่อมอีกสองตัวในความสัมพันธ์หลายต่อหลายและมีแอตทริบิวต์ของตัวเอง ไม่ว่าจะสร้างแบบไหน
มิติที่สองคือความกว้าง ลูกหนึ่งตัวมีแม่แบบ master-detail สองตัวได้ไหม? ได้ สามตัวล่ะ? ไม่ได้ ออบเจกต์ที่กำหนดเองแต่ละตัวมีความสัมพันธ์ master-detail ได้ไม่เกินสองชุด (Considerations for Object Relationships (opens in a new tab) ภาษาอังกฤษ) แม่แบบ master-detail สองตัวคือวิธีที่คุณสร้าง Junction Object ของ Salesforce สำหรับความสัมพันธ์หลายต่อหลาย ทีมจัดส่งและรถบรรทุกมาพบกันในการมอบหมายทีม (Crew Assignment) และอย่างที่เราพบในบทที่ 2 มันไม่ใช่แค่ท่อเชื่อม: มันมีวันที่ เส้นทาง และอาจมีสถานะ junction คือที่ที่ความสัมพันธ์กลายเป็นแนวคิดทางธุรกิจ เคล็ดลับของ 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) ภาษาอังกฤษ):
- หน้าตา หน้าของ junction ใช้สีและไอคอนของ master ตัวหลัก
- เจ้าของ เรกคอร์ด junction สืบทอดเจ้าของของเรกคอร์ด master ตัวหลัก คุณไม่เคยเห็นมัน เพราะ detail ไม่มีฟิลด์ Owner มันสำคัญก็ต่อเมื่อคุณลบความสัมพันธ์ master-detail ทั้งสองชุดทิ้งในภายหลัง
- Division (แผนก) ถ้า org ของคุณใช้ division ก็แบบเดียวกัน
และอีกตัวคือตัวรอง (secondary) มันหมายถึงอะไร?
- มันอยู่ในลำดับถัดไปที่จะเป็นตัวหลัก ลบฟิลด์ master-detail ตัวหลักหรือแปลงเป็น lookup แล้วตัวรองจะกลายเป็นตัวหลัก
- มันกำหนดขอบเขตของรายงาน Salesforce ให้ประเภทรายงานคุณสองแบบ: “Primary master with junction object and secondary master” และ “Secondary master with junction object and primary master” master ที่อยู่ลำดับแรกเป็นตัวตัดสินว่ารายงานแสดงเรกคอร์ดไหนได้
- มันมีน้ำหนักเท่ากันในเรื่องสิทธิ์เข้าถึง ผมพูดแบบนี้: ความเป็นเจ้าของมาจากตัวหลัก สิทธิ์เข้าถึงมาจากทั้งสองตัว และตัวที่เข้มงวดที่สุดชนะ junction ก็เหมือน detail ทั่วไป ไม่มี share table ของตัวเอง Salesforce ตรวจสิทธิ์เข้าถึงของผู้ใช้บนเรกคอร์ด master ทั้งสอง ผ่าน Sharing Setting บนฟิลด์ master-detail แต่ละฟิลด์ ถ้าทั้งสองตั้งเป็น Read/Write ผู้ใช้ต้องมี Read/Write ทั้งบนทีมจัดส่งและบนรถบรรทุก จึงจะแก้ไขการมอบหมายทีมได้ (Considerations for Object Relationships (opens in a new tab) ภาษาอังกฤษ)
- มันลบได้เท่ากัน ลบ master ตัวใดตัวหนึ่ง ทีมจัดส่งหรือรถบรรทุก แล้วเรกคอร์ด junction ของมันจะไปอยู่ในถังรีไซเคิล ลบทั้งสองตัว แล้วมันจะหายไปถาวร
กฎอีกสองสามข้อ: master ทั้งสองมี roll-up summary จาก junction ได้ และสูตรกับกฎการตรวจสอบความถูกต้องของ junction เอื้อมไปถึงฟิลด์บน master ทั้งสองได้ แต่ junction เป็น master ของสิ่งอื่นไม่ได้ มันจึงอยู่ตรงกลางของการซ้อนไม่ได้ และ master ทั้งสองเป็นออบเจกต์เดียวกันไม่ได้ ความสัมพันธ์หลายต่อหลายจากออบเจกต์หนึ่งไปหาตัวมันเองต้องใช้การออกแบบแบบอื่น และถ้าแม่ตัวหนึ่งมีเรกคอร์ด junction มากกว่า 200 รายการ และ junction ทำ roll-up ไปยังแม่อีกตัว Salesforce จะไม่ให้คุณลบแม่ตัวนั้นจนกว่าคุณจะลบเรกคอร์ดเหล่านั้นออกมากพอ
แล้วแม่ตัวไหนควรเป็นตัวหลัก? สร้างตัวที่เป็นเจ้าของความหมายก่อน สำหรับการมอบหมายทีม ทีมจัดส่งคือผู้ทำงาน ผมจึงสร้างทีมจัดส่งก่อน แล้วเขียนบันทึกไว้ เพราะไม่มีอะไรบนหน้าจอจะบอกคนถัดไป
พูดมาทั้งหมดนี้ ผมกลับไม่ค่อยได้ใช้ Junction Object ของ Salesforce มากนัก โดยทั่วไปออบเจกต์หนึ่งมีแม่แบบ master-detail ตัวเดียว และเป็นข้อมูลประเภทเดียวกัน: ข้อมูลลูกค้าใต้ข้อมูลลูกค้า ข้อมูลธุรกรรมใต้ข้อมูลธุรกรรม (จำประเภทข้อมูลในบทที่ 2 ได้ไหม: ข้อมูลลูกค้า ข้อมูลธุรกรรม ข้อมูลอ้างอิง) เมื่อแม่อีกตัวเป็นข้อมูลต่างประเภท ซึ่งมักเป็นออบเจกต์อ้างอิง ความสัมพันธ์นั้นจะเป็น lookup รายการจัดส่งเป็นของการจัดส่งของมัน: master-detail ทั้งคู่เป็นข้อมูลธุรกรรม มันชี้ไปที่ผลิตภัณฑ์ที่มันบรรทุกด้วย lookup เพราะผลิตภัณฑ์เป็นข้อมูลอ้างอิงที่มีชีวิตของตัวเอง และไม่มีใครอยากให้การลบผลิตภัณฑ์พาประวัติการจัดส่งหลายปีหายไปด้วย รายการจัดส่งยังคงเป็นออบเจกต์เชื่อมเชิงตรรกะระหว่างการจัดส่งกับผลิตภัณฑ์ที่อยู่บนมัน แค่ไม่ใช่ Junction Object ของ Salesforce
ความสัมพันธ์กับตัวเอง: เมื่อเส้นวนกลับ
หัวข้อที่มีชื่อว่า “ความสัมพันธ์กับตัวเอง: เมื่อเส้นวนกลับ ”ออบเจกต์หนึ่งสัมพันธ์กับตัวเองได้: บัญชีแม่ ผู้จัดการ ศูนย์กระจายสินค้าที่รายงานต่อศูนย์ภูมิภาค Salesforce สร้างไว้ให้สองแบบที่คุณจะเจอแทบทุก org: บัญชีกับบัญชี คือฟิลด์ Parent Account ที่สร้างลำดับชั้นบัญชี และเคสกับเคส คือ Parent Case จากโมดูลที่ 2 ที่จัดกลุ่มเคสที่เกี่ยวข้องกัน ความสัมพันธ์กับตัวเองต้องเป็น lookup และเรกคอร์ดชี้หาตัวเองไม่ได้ แม้สองเรกคอร์ดจะชี้หากันได้ (Considerations for Object Relationships (opens in a new tab) ภาษาอังกฤษ) บนออบเจกต์ User มันเป็นประเภทพิเศษของตัวเอง คือความสัมพันธ์แบบ hierarchical (ตามลำดับชั้น) ใช้กับเรื่องอย่างผู้จัดการของผู้ใช้ กลไกนั้นง่าย การตั้งชื่อต่างหากที่สำคัญ lookup จากศูนย์กระจายสินค้าไปศูนย์กระจายสินค้าที่ชื่อ Distribution_Center__c ไม่ช่วยใครเลย แม่? สำรอง? รับส่วนเกิน? ตั้งชื่อความสัมพันธ์ตามบทบาท ไม่ใช่ตามออบเจกต์ที่มันชี้ไป
Hierarchical: ความสัมพันธ์เฉพาะของออบเจกต์ User
หัวข้อที่มีชื่อว่า “Hierarchical: ความสัมพันธ์เฉพาะของออบเจกต์ User ”เรื่องนี้เล็ก และเป็นข้อเท็จจริงแบบที่ไม่ค่อยมีคนรู้และมีแค่หนึ่งเดียว ซึ่งผมคาดว่าข้อสอบจะหยิบมาใช้ Hierarchical เป็น lookup แบบพิเศษที่มีเฉพาะบนออบเจกต์ User มันเชื่อมผู้ใช้คนหนึ่งกับผู้ใช้อีกคน และ Salesforce ไม่ยอมให้สายโซ่วนกลับ: ผู้ใช้ชี้หาตัวเองไม่ได้ ทั้งโดยตรงและโดยอ้อม (Object Relationships Overview (opens in a new tab) ภาษาอังกฤษ) ถ้าผู้จัดการของ Maria คือ Dev ผู้จัดการของ Dev จะเป็น Maria ไม่ได้ หรือเป็นใครก็ตามที่รายงานขึ้นไปถึง Maria ก็ไม่ได้
นั่นคือความต่างจากความสัมพันธ์กับตัวเองข้างบน บนบัญชีหรือออบเจกต์ที่กำหนดเอง สองเรกคอร์ดชี้หากันได้ บน User ลำดับชั้นต้องคงเป็นลำดับชั้น และมันเป็นวิธีเดียวที่จะเชื่อม User กับ User: lookup ธรรมดาจาก User ไปหาตัวเองไม่มีให้เลือก
คุณมีอยู่แล้วหนึ่งตัว ฟิลด์มาตรฐาน Manager บน User เป็นความสัมพันธ์แบบ hierarchical และกระบวนการอนุมัติใช้มันได้: ส่งคำขอนี้ไปที่ผู้จัดการของผู้ยื่น คุณสร้างของตัวเองได้ด้วย เช่น Escalation Contact หรือ Backup Approver และการอนุมัติก็ส่งต่อตามมันได้แบบเดียวกัน (ApprovalProcess, Metadata API (opens in a new tab) ภาษาอังกฤษ) อย่าสับสนกับลำดับชั้นบทบาท ซึ่งเป็นตัวกำหนดสิทธิ์เข้าถึงเรกคอร์ด ฟิลด์ hierarchical เป็นแค่ความสัมพันธ์ระหว่างผู้ใช้ มันไม่ได้แชร์เรกคอร์ดใดเลย
ความรู้ที่ออกสอบ ความสัมพันธ์แบบ hierarchical มีเฉพาะบนออบเจกต์ User เช่นฟิลด์มาตรฐาน Manager และผู้ใช้ชี้หาตัวเองไม่ได้ ทั้งโดยตรงและโดยอ้อม มันไม่ใช่ลำดับชั้นบทบาท
ความสัมพันธ์ก็มีข้อจำกัด
หัวข้อที่มีชื่อว่า “ความสัมพันธ์ก็มีข้อจำกัด ”แต่ละออบเจกต์มีความสัมพันธ์ master-detail ได้สูงสุดสองตัว ฟิลด์ lookup และ master-detail รวมกันนับเป็นฟิลด์ความสัมพันธ์: ค่าเริ่มต้น 40 ต่อออบเจกต์ สูงสุด 50 เมื่อร้องขอ ฟิลด์สรุปยอด: ค่าเริ่มต้น 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 ใช้ได้: อยู่ให้ต่ำกว่าข้อจำกัดมากๆ โดยวัดที่ปีที่สาม)
คำถามเรื่องลูก 10,000 รายการ
หัวข้อที่มีชื่อว่า “คำถามเรื่องลูก 10,000 รายการ ”แล้วก็มีแม่ที่มีลูกมากเกินไป แนวทางของ 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 จะลงลึก
อย่าออกแบบเส้นตามฟีเจอร์
หัวข้อที่มีชื่อว่า “อย่าออกแบบเส้นตามฟีเจอร์ ”นี่คือนิสัยที่ผมอยากได้จากโมดูลนี้ อย่าเริ่มจาก “ฉันต้องการ roll-up” “ฉันต้องการให้มันบังคับ” “ฉันอยากได้การแชร์ที่สืบทอด” นั่นเป็นเบาะแสของการ implement เริ่มจากธุรกิจ: ลูกมีชีวิตของตัวเองไหม ใครเป็นเจ้าของ มันอยู่เดี่ยวได้ไหม ย้ายได้ไหม จะเกิดอะไรขึ้นเมื่อแม่หายไป ความสัมพันธ์แบกข้อมูลไหม และแต่ละฝั่งใหญ่ได้แค่ไหน? แล้วเลือกความสัมพันธ์ที่ implement คำตอบเหล่านั้น
นอกเหนือจากการสอบ: AI เปลี่ยนอะไร AI เสนอความสัมพันธ์ได้ในไม่กี่วินาที แต่บอกคุณไม่ได้ว่าธุรกิจจะลบแม่ไหม การวาดไดอะแกรมที่เร็วขึ้นไม่ได้ทำให้ความสัมพันธ์ที่ผิดย้อนกลับได้ถูกลง เมื่อเรกคอร์ดหลายล้านและระบบอัตโนมัติหลายสิบตัวพึ่งพามันแล้ว
สิ่งที่สถาปนิกต้องตัดสินใจในเรื่องนี้
หัวข้อที่มีชื่อว่า “สิ่งที่สถาปนิกต้องตัดสินใจในเรื่องนี้ ”- ลูกมีวงจรชีวิตของตัวเอง หรือเป็นของแม่จริงๆ และความเป็นเจ้าของกับการเข้าถึงควรเป็นของตัวเองหรือสืบทอดมา
- ลูกมีอยู่ได้โดยไม่มีแม่ ย้ายระหว่างแม่ หรืออยู่รอดหลังแม่ถูกลบได้หรือไม่
- lookup แต่ละตัวจะทำอะไรเมื่อแม่ถูกลบ: ล้างค่า ห้ามลบ หรือลบแบบต่อเนื่อง
- ความสัมพันธ์แบบหลายต่อหลายเป็นแค่ท่อเชื่อม หรือเป็นแนวคิดทางธุรกิจ ออบเจกต์เชื่อมเชิงตรรกะจะกลายเป็น Junction Object ของ Salesforce หรือไม่ แม่ตัวไหนเป็นตัวหลัก และแม่ทั้งสองมีความหมายอย่างไรต่อสิทธิ์เข้าถึง
- โมเดลเข้ากับรูปร่างของแพลตฟอร์มหรือไม่: ลึกสามชั้น detail ที่กำหนดเอง กว้างสองแม่แบบ master-detail ข้อจำกัดของความสัมพันธ์และ roll-up
- จำนวนและการกระจายของลูกที่คาดไว้สร้างความเสี่ยงเรื่อง skew ที่ควรเปลี่ยนการออกแบบหรือไม่
ความสัมพันธ์คือชุดคำมั่นว่าข้อมูลสองชิ้นจะทำงานร่วมกันอย่างไร ให้คำมั่นอย่างตั้งใจ
ศึกษาเพิ่มเติม
หัวข้อที่มีชื่อว่า “ศึกษาเพิ่มเติม ”- Salesforce Help, Considerations for Object Relationships (opens in a new tab) (ภาษาอังกฤษ ตรวจสอบเมื่อ 2026-10-13)
- Salesforce Help, Object Relationships Overview (opens in a new tab) และ Create a Many-to-Many Object Relationship (opens in a new tab) (ภาษาอังกฤษ ตรวจสอบเมื่อ 2026-10-13)
- Salesforce Help, Roll-Up Summary Field (opens in a new tab) (ภาษาอังกฤษ ตรวจสอบเมื่อ 2026-10-13)
- Salesforce Developers, Metadata API, ApprovalProcess (opens in a new tab) (ภาษาอังกฤษ ตรวจสอบเมื่อ 2026-10-13)
- Salesforce Help, Lookup Filters (opens in a new tab) (ภาษาอังกฤษ ตรวจสอบเมื่อ 2026-10-13)
- Salesforce Help, 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) (ภาษาอังกฤษ ตรวจสอบเมื่อ 2026-10-02)
- Salesforce Developers, Designing Record Access for Enterprise Scale, Parent-Child Data Skew (opens in a new tab) (ภาษาอังกฤษ ตรวจสอบเมื่อ 2026-10-02)
