Bỏ qua để đến nội dung

Quan hệ có hệ quả

Cũng có bằng 28 ngôn ngữ khác

English · Español · 日本語 · Português (Brasil) · Français · Deutsch · Italiano · 한국어 · 简体中文 · Português (Portugal) · 繁體中文 · Bahasa Indonesia · Türkçe · Polski · ไทย · 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.
Hình ảnh được tạo bằng AI

Mô-đun 7 trong 10 của chương Kiến trúc dữ liệu Salesforce, chương 3 của khóa học Data Architect. Mỗi mô-đun có thể đọc độc lập. Trước: Trường cũng là kiến trúc · Tiếp theo: Quyền sở hữu và vòng đời

Câu hỏi mô-đun này trả lời: Tôi thực sự đang chọn điều gì khi nối hai đối tượng Salesforce?

Vẽ một quan hệ thì dễ. Ở chương 2 chúng ta đã vẽ các đường và đặt tên cho chúng: một Đối tác bán lẻ gửi nhiều bảng kê hàng, một lần giao hàng chở nhiều mặt hàng, tổ giao hàng và xe tải gặp nhau trong một Phân công tổ. Chúng ta đã nói về lực lượng, tính tùy chọn và lịch sử. Giờ chúng ta hiện thực những đường đó trên Salesforce, và một đường trên sơ đồ bắt đầu mang sức nặng lớn hơn nhiều.

Khi chọn một loại quan hệ trên Salesforce, tôi không chỉ nói hai bản ghi này được nối với nhau. Tôi còn có thể đang quyết định ai sở hữu bản ghi con, nó có tồn tại được mà không có bản ghi cha không, ai thấy được nó, chuyện gì xảy ra khi bản ghi cha bị xóa, nó có chuyển sang bản ghi cha khác được không, tôi có tổng hợp được nó lên bản ghi cha không, và chuyện gì xảy ra khi có hàng trăm nghìn bản ghi con. Một quan hệ không chỉ là một đường kẻ. Nó mang theo hành vi.

Trước khi nói đến quan hệ tra cứu hay chính-chi tiết, hãy quay lại nghiệp vụ. Lấy một Giao hàng và các Mặt hàng giao của nó: chiếc tủ lạnh, việc lắp đặt, việc chở đồ cũ đi. Một mặt hàng có tồn tại được mà không có lần giao hàng của nó không? Không. Nếu lần giao hàng bị xóa, các mặt hàng có nên bị xóa theo không? Có. Các mặt hàng có cần chủ sở hữu riêng hay bảo mật riêng không? Không hẳn. Có ai nên chuyển một mặt hàng từ lần giao này sang lần giao khác không? Hy vọng là không phải do vô tình.

Giờ lấy một Giao hàng và Tuyến mà nó nằm trên. Lần giao hàng tồn tại trước khi được xếp tuyến, có thể được chuyển sang tuyến khác khi kế hoạch thay đổi, và xóa một tuyến không bao giờ được xóa các lần giao hàng trên đó. Hai đường một-nhiều trông giống hệt nhau trên sơ đồ, với hành vi hoàn toàn khác nhau. Để ý rằng chúng ta vẫn chưa nói “quan hệ tra cứu” hay “chính-chi tiết”. Hãy mô tả hành vi trước. Cấu hình sẽ hiện thực nó.

Mở màn hình New Field và Salesforce đưa ra cho bạn một vài kiểu quan hệ (Object Relationships Overview (opens in a new tab), tiếng Anh):

  • Tra cứu (Lookup): liên kết hai đối tượng. Món cơm hằng ngày của các quan hệ Salesforce.
  • Chính-chi tiết (Master-detail): một ràng buộc cha-con trong đó bản ghi cha kiểm soát bản ghi con.
  • Nhiều-nhiều: không phải một kiểu trường riêng, mà là một khuôn mẫu: một đối tượng nối của Salesforce (Salesforce Junction Object), tức một đối tượng tùy chỉnh có hai quan hệ chính-chi tiết.
  • Quan hệ tự thân: một quan hệ tra cứu từ một đối tượng đến chính nó.
  • Phân cấp (Hierarchical): một quan hệ tra cứu đặc biệt chỉ tồn tại trên đối tượng User, chẳng hạn người quản lý của một người dùng.
  • Tra cứu bên ngoài (external lookup) và tra cứu gián tiếp (indirect lookup): các quan hệ đến và đi từ đối tượng bên ngoài, các đối tượng __x từ mô-đun 4. Tra cứu bên ngoài trỏ đến một đối tượng bên ngoài làm cha; tra cứu gián tiếp trỏ từ một đối tượng bên ngoài đến một đối tượng chuẩn hoặc tùy chỉnh, khớp theo một ID bên ngoài duy nhất.

Phần lớn thời gian thiết kế của bạn dành cho ba kiểu đầu tiên. Hãy xem từng kiểu một.

Quan hệ tra cứu: các bản ghi này được nối với nhau

Phần tiêu đề “Quan hệ tra cứu: các bản ghi này được nối với nhau ”

Một quan hệ tra cứu nói: bản ghi này liên kết với bản ghi kia. Bản ghi con giữ danh tính riêng, chủ sở hữu riêng và cuộc đời riêng. Một Giao hàng trỏ đến Tuyến của nó. Nếu tuyến bị hủy, các lần giao hàng không biến mất; chúng quay lại để được xếp tuyến lần nữa.

Điều thú vị là: trường tra cứu nằm trên bản ghi con, nhưng bản ghi cha cũng nhận được một thứ, một danh sách liên quan (related list) các bản ghi con của nó. Vì vậy khi tạo một quan hệ tra cứu, hãy đặt tên cho cả hai đầu. Related List Label (nhãn danh sách liên quan) là thứ người dùng thấy trên bản ghi cha, và Child Relationship Name (tên quan hệ con) là thứ lập trình viên và tích hợp dùng để đi từ bản ghi cha xuống các bản ghi con. Đừng chấp nhận giá trị mặc định.

Một quan hệ tra cứu có thể bắt buộc hoặc tùy chọn. Khi nó tùy chọn, bạn quyết định chuyện gì xảy ra nếu bản ghi nó trỏ đến bị xóa, và có ba lựa chọn (Considerations for Object Relationships (opens in a new tab), tiếng Anh):

  • Clear the value of this field (xóa trống giá trị của trường này), mặc định. Bản ghi con ở lại, với một quan hệ tra cứu trống.
  • Don’t allow deletion (không cho phép xóa) bản ghi được tra cứu. Thử xóa tuyến, và Salesforce từ chối: nó là một phần của một quan hệ.
  • Delete this record also (xóa luôn bản ghi này), một thao tác xóa dây chuyền (cascade delete), giống như chính-chi tiết. Nó chỉ được đưa ra cho một quan hệ tra cứu tùy chỉnh trên một đối tượng tùy chỉnh, nó bị tắt theo mặc định, và Salesforce phải bật nó cho org của bạn, vì xóa dây chuyền bỏ qua bảo mật và chia sẻ: người dùng có thể xóa những bản ghi mà họ thậm chí không nhìn thấy được.

Đó là một quyết định về vòng đời ẩn trong một màn hình thiết lập.

Bộ lọc tra cứu (lookup filter) thu hẹp những gì người dùng có thể chọn. Giả sử Giao hàng có một quan hệ tra cứu Thợ lắp đặt đến Liên hệ, và thợ lắp đặt là một loại bản ghi liên hệ trong số nhiều loại. Một bộ lọc tra cứu chỉ hiển thị thợ lắp đặt, và nó có thể lọc theo bản ghi hiện tại, theo bản ghi đang được tra cứu, và theo người dùng: hồ sơ, vai trò hoặc quyền của họ (Lookup Filters (opens in a new tab), tiếng Anh). Đó là một cách rẻ để giữ cho quan hệ tra cứu trung thực.

Chính-chi tiết: bản ghi con này thuộc về bản ghi cha kia

Phần tiêu đề “Chính-chi tiết: bản ghi con này thuộc về bản ghi cha kia ”

Quan hệ chính-chi tiết đưa ra một tuyên bố mạnh hơn nhiều. Trong lớp tôi gọi nó là một sự ràng buộc rất chặt. Bạn không thể có bản ghi chi tiết mà không có bản ghi chính; trường chính là bắt buộc. Bản ghi chi tiết mất trường Owner của riêng nó và thừa hưởng chủ sở hữu của bản ghi cha. Không có bảng chia sẻ riêng cho bản ghi chi tiết, nên bạn không thể chia sẻ riêng một bản ghi con; nó thừa hưởng việc chia sẻ của bản ghi cha. Đó là lý do một đối tượng chi tiết không thể có quy tắc chia sẻ, chia sẻ thủ công hay hàng đợi: tất cả đều cần một trường Owner (Object Relationships Overview (opens in a new tab), tiếng Anh). Trong Thiết lập, thiết lập chia sẻ của nó ghi Controlled by Parent (do bản ghi cha kiểm soát). Và trên chính trường chính-chi tiết, bạn chọn một Sharing Setting (thiết lập chia sẻ): người dùng cần quyền Read Only hay Read/Write trên bản ghi chính để tạo, sửa hoặc xóa các bản ghi chi tiết của nó. Xóa bản ghi chính sẽ xóa các bản ghi chi tiết. Và bản ghi chính có được trường tổng hợp cuộn lên (roll-up summary).

Vậy nếu Mặt hàng giao là chi tiết của Giao hàng, tôi đang nói: mặt hàng này thuộc về lần giao hàng này suốt đời. Đó là câu hỏi tôi muốn được trả lời trước khi bất kỳ ai chọn Master-Detail Relationship trong Thiết lập.

Đây là cách tôi thích nhất để biết chúng ta đã suy nghĩ thấu đáo chưa: chuyện gì nên xảy ra với các bản ghi con nếu ai đó xóa bản ghi cha? Ai cũng thấy khó chịu. Tốt. Giờ chúng ta đang làm kiến trúc.

Một Đối tác bán lẻ có hàng trăm nghìn lần giao hàng trong lịch sử. Ai đó xóa đối tác. Các lần giao hàng có nên biến mất không? Gần như chắc chắn là không: khiếu nại, thanh toán và lịch sử đều phụ thuộc vào chúng. Có lẽ không nên cho phép xóa đối tác chút nào, mà đối tác nên được ngừng kích hoạt thay vào đó. Với quan hệ chính-chi tiết, xóa bản ghi chính sẽ lan xuống các bản ghi chi tiết và chi tiết của chúng; khôi phục bản ghi chính sẽ mang chúng trở lại (Considerations for Object Relationships (opens in a new tab), tiếng Anh). Vì vậy khi ai đó nói “chính-chi tiết cho chúng ta trường tổng hợp”, câu trả lời của tôi là: tuyệt. Bạn vừa đồng ý thêm những gì nữa?

Với quan hệ tra cứu, bản ghi con có thể có chủ sở hữu riêng. Với chính-chi tiết thì không; quyền truy cập đi theo bản ghi chính. Điều đó hoàn toàn đúng nếu bản ghi chi tiết thực sự là một phần của bản ghi cha. Nhưng nếu bản ghi con cần chủ sở hữu riêng, chia sẻ riêng hay vòng đời riêng, mô hình đang nói với bạn rằng chính-chi tiết là lựa chọn sai. Mô-đun tiếp theo đi sâu hơn vào quyền sở hữu, và khóa Sharing and Visibility còn đi xa hơn nữa. Hiện tại thì: thiết kế quan hệ và thiết kế bảo mật không phải là hai cuộc trò chuyện tách biệt. Mô hình dữ liệu định hình mô hình bảo mật trước khi có ai viết một quy tắc chia sẻ.

Bản ghi con có tồn tại được trước khi chúng ta biết bản ghi cha của nó không? Điều này quan trọng hơn vẻ ngoài. Nếu các lần giao hàng đến cùng bảng kê hàng vào đêm hôm trước và tuyến được lập sau đó, một Tuyến bắt buộc trên Giao hàng có nghĩa là phải xếp tuyến trước thì mới tạo được bản ghi. Quan hệ vật lý phải hỗ trợ vòng đời thực tế. Vì vậy tôi không thiết kế quan hệ chỉ từ một sơ đồ tĩnh. Tôi muốn biết: chúng sinh ra thế nào, có tồn tại một mình được không, có di chuyển được không, và chúng chết đi thế nào?

Bản ghi con có đổi bản ghi cha được không?

Phần tiêu đề “Bản ghi con có đổi bản ghi cha được không? ”

Mặc định, một bản ghi con chính-chi tiết không thể chuyển sang bản ghi cha khác. Bạn có thể cho phép điều đó bằng cách chọn Allow reparenting (cho phép đổi bản ghi cha) trên quan hệ (Considerations for Object Relationships (opens in a new tab), tiếng Anh). Bản năng của tôi là thận trọng: nếu nghiệp vụ nói bản ghi con thuộc về một bản ghi cha suốt đời, tôi không làm cho việc chuyển nó trở nên dễ dàng. Một mặt hàng chuyển từ lần giao này sang lần giao khác nên là một sự kiện nghiệp vụ có chủ ý, không phải một lần sửa trường. Một lần nữa, thiết lập không phải là kiến trúc. Quy tắc vòng đời mới là kiến trúc, và thiết lập hiện thực nó.

Thêm hai điều khiến các đội vấp phải sau này. Bạn không thể tạo quan hệ chính-chi tiết trên một đối tượng đã có dữ liệu; bạn tạo một quan hệ tra cứu, điền nó trên mọi bản ghi, rồi chuyển đổi. Và bạn chỉ có thể chuyển ngược lại thành quan hệ tra cứu nếu bản ghi chính không có trường tổng hợp cuộn lên nào. Cũng hãy để ý việc chuyển đổi làm gì với bảo mật: biến một quan hệ tra cứu thành chính-chi tiết sẽ đặt chia sẻ của bản ghi con thành Controlled by Parent, và biến một quan hệ chính-chi tiết trở lại thành tra cứu sẽ đặt mặc định toàn tổ chức của bản ghi con thành Public Read/Write (Considerations for Object Relationships (opens in a new tab), tiếng Anh). Những bản ghi hôm qua còn riêng tư thì hôm nay bị mở, cho đến khi có người để ý. Hãy chọn sớm.

Trường tổng hợp hữu ích, nhưng không miễn phí

Phần tiêu đề “Trường tổng hợp hữu ích, nhưng không miễn phí ”

Tôi thích trường tổng hợp. Đếm số mặt hàng trên một lần giao, cộng tổng số tiền các dòng trên một hóa đơn, tìm ngày gần nhất: có sẵn, không cần code. Trường chính-chi tiết nằm trên bản ghi con, nhưng trường tổng hợp nằm trên bản ghi cha. Có điều, chúng đi kèm điều khoản in nhỏ (Roll-Up Summary Field (opens in a new tab), tiếng Anh):

  • Việc tính lại giá trị tổng hợp sau một số thay đổi (một trường tổng hợp mới, một công thức nó phụ thuộc bị đổi, một lần buộc tính lại) có thể mất đến 30 phút, tùy số bản ghi bị ảnh hưởng. Tôi đã từng thấy người ta thắc mắc sao con số trên bản ghi cha vẫn chưa đổi.
  • Chúng không tổng hợp được mọi thứ. Một số tự động không thể là trường được tổng hợp. Và một trường tổng hợp chỉ có thể tổng hợp một trường công thức nếu công thức đó không với sang một đối tượng khác và không dùng một hàm tự thay đổi, chẳng hạn NOW() hay TODAY(). Một công thức “số ngày quá hạn” dựa trên TODAY() thay đổi mỗi đêm mà không ai lưu bản ghi nào, nên trường tổng hợp chẳng có gì để tính lại. Loại con số đó cần một flow theo lịch, hoặc một báo cáo.
  • Bộ lọc cũng có giới hạn: không dùng được vùng văn bản dài, danh sách chọn nhiều giá trị, Description, các trường hệ thống như Last Activity, công thức liên đối tượng hay trường tra cứu.
  • Trường tổng hợp không có trên trang chỉnh sửa, nên một quy tắc xác thực có thể dùng nó nhưng không thể hiển thị lỗi của mình ở đó.

Và đừng đảo ngược quyết định. Đừng nói: “Chúng ta cần trường tổng hợp, nên đây phải là chính-chi tiết.” Hãy nói: “Bản ghi con này thực sự thuộc về bản ghi cha này, quyền sở hữu và vòng đời đều phù hợp, và một trong những lợi ích là trường tổng hợp có sẵn.” Nếu ngữ nghĩa không phù hợp, hãy giải bài toán tính toán theo cách khác. Đừng bóp méo mô hình dữ liệu để có một tính năng.

Vậy cách khác là gì? Bạn tự xây trường tổng hợp: một trường trên bản ghi cha giữ giá trị đã tính, và tự động hóa giữ cho nó luôn cập nhật. Giả sử Đối tác bán lẻ được nối từ Giao hàng bằng một quan hệ tra cứu, đúng như nên thế, và doanh nghiệp muốn có Số lần giao đang mở trên đối tác. Thêm một trường số, Số lần giao đang mở, vào đối tác. Rồi một flow kích hoạt theo bản ghi (record-triggered flow), hoặc một Apex trigger khi khối lượng hay logic đòi hỏi code, tính lại nó mỗi khi một lần giao hàng thay đổi. Cách này hoạt động qua một quan hệ tra cứu, có thể lọc theo bất cứ thứ gì, và có thể dùng ngày và công thức mà trường tổng hợp có sẵn không dùng được.

Nhưng giờ việc làm cho đúng là của bạn, và đây là chỗ những thứ này hay hỏng. Tự động hóa phải chạy với mọi thay đổi có ý nghĩa: một bản ghi con mới, một bản ghi con được sửa, một bản ghi con bị xóa, một bản ghi con được khôi phục, và một bản ghi con chuyển sang bản ghi cha khác, nghĩa là phải tính lại cả bản ghi cha cũ lẫn bản ghi cha mới. Nó phải xử lý được một lần nạp dữ liệu 200 bản ghi mỗi đợt mà không chạm giới hạn. Hãy đếm lại từ đầu thay vì cộng và trừ, để một sự kiện bị bỏ sót không làm con số sai mãi mãi. Hãy lên kế hoạch cho một cách tính lại tất cả, cho lần nạp đầu tiên và cho ngày con số bị lệch. Và nhớ rằng giờ mỗi lần lưu bản ghi con đều cập nhật bản ghi cha, nên một bản ghi cha có hàng nghìn bản ghi con sẽ mang trở lại chuyện khóa bản ghi mà chúng ta sẽ thấy ngay sau đây. Một trường tổng hợp có sẵn làm tất cả những việc đó cho bạn; một trường tự xây là một mẩu phần mềm nhỏ mà bạn sở hữu.

Sâu ba tầng: xếp chồng các quan hệ chính-chi tiết

Phần tiêu đề “Sâu ba tầng: xếp chồng các quan hệ chính-chi tiết ”

Nền tảng có một hình dáng, và quan hệ chính-chi tiết có hai chiều của hình dáng đó. Chiều thứ nhất là độ sâu.

Bạn có thể xếp chồng các quan hệ chính-chi tiết sâu ba tầng chi tiết tùy chỉnh, và đó là đáy (Considerations for Object Relationships (opens in a new tab), tiếng Anh). Trong lớp, tôi vẽ nó thành một tài khoản với một đơn hàng (một), đơn hàng với các mặt hàng của nó (hai), và các mặt hàng với các chi tiết của chúng (ba), rồi tôi thử thêm tầng thứ tư và Salesforce không cho. Ở Steve Trucking nó có thể trông thế này: một Giao hàng (Delivery) là bản ghi chính; các Mặt hàng giao (Delivery Item) của nó là tầng thứ nhất; các Nhiệm vụ lắp đặt (Install Task) của một mặt hàng là tầng thứ hai; và các Bước nhiệm vụ (Task Step) của mỗi nhiệm vụ là tầng thứ ba. Tầng thứ tư, chẳng hạn một Ghi chú bước (Step Note), phải là một quan hệ tra cứu.

Ba tầng chính-chi tiết Ba quan hệ chính-chi tiết xếp chồng ở Steve Trucking, vẽ bằng đường đậm. Giao hàng là bản ghi chính. Mặt hàng giao là tầng chi tiết 1, Nhiệm vụ lắp đặt là tầng 2, và Bước nhiệm vụ là tầng 3. Ghi chú bước treo dưới Bước nhiệm vụ trên một đường tra cứu mảnh, vì tầng thứ tư phải là một quan hệ tra cứu. Bên dưới: quyền sở hữu, chia sẻ và thao tác xóa chảy xuống từ Giao hàng tới mọi tầng. tầng 1 tầng 2 tầng 3 tầng thứ tư là quan hệ tra cứu Giao hàng Delivery__c · bản ghi chính Mặt hàng giao Delivery_Item__c Nhiệm vụ lắp đặt Install_Task__c Bước nhiệm vụ Task_Step__c Ghi chú bước Step_Note__c Quyền sở hữu, chia sẻ và thao tác xóa chảy xuống từ Giao hàng tới mọi tầng. đúng một không hoặc một một hoặc nhiều không hoặc nhiều chính-chi tiết tra cứu © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

Đi kèm việc xếp chồng là vài quy tắc:

  • Đối tượng chuẩn không thể nằm ở phía chi tiết của một đối tượng tùy chỉnh. Một đối tượng tùy chỉnh có thể là chi tiết của Tài khoản; Tài khoản không thể là chi tiết của đối tượng của bạn.
  • Một đối tượng chỉ được xuất hiện một lần trong một chồng nhiều tầng. Salesforce không muốn bạn vòng ngược lại chính mình: một bản ghi chi tiết cấp dưới không thể đồng thời là bản ghi chính của bản ghi chính của nó.
  • Bản ghi chính không thể tổng hợp trực tiếp tầng dưới cùng. Nếu Giao hàng muốn biết số Bước nhiệm vụ, Nhiệm vụ lắp đặt tổng hợp các bước của nó, Mặt hàng giao tổng hợp các giá trị tổng hợp đó, và Giao hàng tổng hợp các mặt hàng: từng tầng một.
  • Quyền sở hữu và chia sẻ đến từ trên đỉnh. Mọi tầng đều thừa hưởng chủ sở hữu và quyền truy cập của bản ghi chính.
  • Xóa bản ghi chính sẽ xóa mọi thứ bên dưới nó, và khôi phục nó sẽ mang mọi thứ trở lại.

Ba tầng thường là quá đủ. Nếu thiết kế của bạn cứ muốn có tầng thứ tư, hãy hỏi xem mọi tầng có thực sự thuộc về tầng trên nó suốt đời không. Và nhớ rằng bạn được chọn mắt xích nào sẽ cắt chuỗi. Tầng thứ tư không nhất thiết phải là quan hệ tra cứu: có thể một Nhiệm vụ lắp đặt không thực sự thuộc về Mặt hàng giao của nó, nó được lên lịch và phân công riêng, nên mắt xích đó trở thành quan hệ tra cứu, và giờ Nhiệm vụ lắp đặt bắt đầu một chuỗi mới với Bước nhiệm vụ và Ghi chú bước bên dưới. Hãy chọn mắt xích nơi bản ghi con thực sự có cuộc đời riêng, và biến mắt xích đó thành quan hệ tra cứu.

Cắt chuỗi bằng một quan hệ tra cứu Cùng năm đối tượng của Steve Trucking như chồng ba tầng, với một quan hệ tra cứu ở giữa. Giao hàng là một bản ghi chính, với Mặt hàng giao là bản ghi chi tiết trên một đường chính-chi tiết đậm. Mặt hàng giao nối với Nhiệm vụ lắp đặt trên một đường tra cứu mảnh, cắt đứt chuỗi. Nhiệm vụ lắp đặt là một bản ghi chính mới: Bước nhiệm vụ là bản ghi chi tiết của nó, và Ghi chú bước là bản ghi chi tiết của Bước nhiệm vụ, đều trên đường chính-chi tiết đậm. Bên dưới: giờ Nhiệm vụ lắp đặt có chủ sở hữu và chia sẻ riêng, và xóa một lần giao hàng không còn xóa các nhiệm vụ lắp đặt của nó. tầng 1 quan hệ tra cứu cắt chuỗi tầng 1 tầng 2 Giao hàng Delivery__c · bản ghi chính Mặt hàng giao Delivery_Item__c Nhiệm vụ lắp đặt Install_Task__c · một bản ghi chính mới Bước nhiệm vụ Task_Step__c Ghi chú bước Step_Note__c Giờ Nhiệm vụ lắp đặt có chủ sở hữu và chia sẻ riêng, và xóa một lần giao hàng không còn xóa các nhiệm vụ lắp đặt của nó. đúng một không hoặc một một hoặc nhiều không hoặc nhiều chính-chi tiết tra cứu © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

Giờ Nhiệm vụ lắp đặt có chủ sở hữu riêng và chia sẻ riêng, một lần giao hàng có thể bị xóa mà không kéo theo các nhiệm vụ lắp đặt, và Nhiệm vụ lắp đặt có thể có thêm hai tầng bên dưới. Đó là sự đánh đổi: chuỗi ngắn hơn, và cuộc đời của nhiệm vụ lắp đặt là của riêng nó.

Rộng hai bản ghi cha: đối tượng nối của Salesforce

Phần tiêu đề “Rộng hai bản ghi cha: đối tượng nối của Salesforce ”

Trước hết, đôi lời về từ ngữ, vì “đối tượng nối” có hai nghĩa, và tôi dạy cả hai.

Ở chương 2, chúng ta đã tìm ra đối tượng nối logic: chỗ giao nhau của hai ý tưởng chính trở thành một thứ riêng, với các thuộc tính riêng. Một con chó biết nhiều trò, một trò được nhiều con chó biết, và Trò của chó nằm giữa chúng, giữ mức độ kỹ năng và ngày tháng. Đó là một đối tượng nối logic, trong mô hình logic, từ rất lâu trước khi ai đó quyết định tra cứu hay chính-chi tiết.

Salesforce dùng thuật ngữ này hẹp hơn. Khi Salesforce nói đối tượng nối, ý nó là một đối tượng tùy chỉnh có hai quan hệ chính-chi tiết (Create a Many-to-Many Object Relationship (opens in a new tab), tiếng Anh). Tôi sẽ gọi nó là đối tượng nối của Salesforce (Salesforce Junction Object). Mọi đối tượng nối của Salesforce đều là một đối tượng nối logic, nhưng không phải đối tượng nối logic nào cũng trở thành đối tượng nối của Salesforce: hãy xây một cái với một quan hệ chính-chi tiết và một quan hệ tra cứu, hoặc hai quan hệ tra cứu, và nó vẫn là một đối tượng nối logic, chỉ không phải loại của Salesforce. (Bản thân Salesforce cũng không hoàn toàn nhất quán: tài liệu tham chiếu đối tượng của chính họ gọi một số đối tượng chuẩn xây trên quan hệ tra cứu là “junction object”. Trong kỳ thi, hãy hiểu theo định nghĩa hẹp.)

Kiến thức hay ra thi. Một đối tượng nối của Salesforce là một đối tượng tùy chỉnh có hai quan hệ chính-chi tiết, và đó là điều Salesforce muốn nói khi nói “đối tượng nối”. Đối tượng nối logic là ý tưởng mô hình hóa rộng hơn: bất kỳ đối tượng nào nối hai đối tượng khác trong một quan hệ nhiều-nhiều và mang thuộc tính riêng, dù được xây theo cách nào.

Chiều thứ hai là độ rộng. Một bản ghi con có thể có hai bản ghi cha chính-chi tiết không? Có. Ba thì sao? Không. Mỗi đối tượng tùy chỉnh có thể có tối đa hai quan hệ chính-chi tiết (Considerations for Object Relationships (opens in a new tab), tiếng Anh). Hai bản ghi cha chính-chi tiết là cách bạn xây một đối tượng nối của Salesforce cho một quan hệ nhiều-nhiều. Tổ giao hàng và Xe tải gặp nhau trong một Phân công tổ (Crew Assignment), và như chúng ta đã tìm ra ở chương 2, nó không phải đường ống kỹ thuật: nó có ngày, có tuyến, có thể có trạng thái. Đối tượng nối là nơi quan hệ trở thành một khái niệm nghiệp vụ. Các mẹo của Salesforce khi xây một đối tượng nối: đặt cho nó một cái tên nói lên nó là gì, đặt tên bản ghi của nó là số tự động, và đổi tên danh sách liên quan trên mỗi bản ghi chính theo bản ghi chính còn lại, để trang Tổ giao hàng hiển thị “Xe tải” và trang Xe tải hiển thị “Tổ giao hàng” (Create a Many-to-Many Object Relationship (opens in a new tab), tiếng Anh).

Đây là chỗ tinh tế. Một trong hai bản ghi cha là master chính (primary master), và đó là bản ghi cha có trường chính-chi tiết được bạn tạo trước. Không có dấu hiệu trực quan nào cho biết đó là cái nào, nên đây là một câu hỏi thi kinh điển, và một bất ngờ kinh điển.

Master chính quyết định điều gì? Ba điều (Create a Many-to-Many Object Relationship (opens in a new tab), tiếng Anh):

  • Giao diện. Các trang của đối tượng nối dùng màu và biểu tượng của master chính.
  • Chủ sở hữu. Các bản ghi nối thừa hưởng chủ sở hữu của bản ghi master chính. Bạn không bao giờ thấy nó, vì bản ghi chi tiết không có trường Owner; nó chỉ quan trọng nếu sau này bạn gỡ bỏ cả hai quan hệ chính-chi tiết.
  • Division (bộ phận), nếu org của bạn dùng division, cũng theo cách đó.

Và cái còn lại là master phụ (secondary master). Nó có ý nghĩa gì?

  • Nó đứng sẵn để trở thành master chính. Xóa trường chính-chi tiết của master chính hoặc chuyển nó thành quan hệ tra cứu, và master phụ trở thành master chính.
  • Nó đặt phạm vi cho báo cáo. Salesforce cho bạn hai loại báo cáo: “Primary master with junction object and secondary master” và “Secondary master with junction object and primary master”. Bản ghi chính được liệt kê trước quyết định báo cáo có thể hiển thị những bản ghi nào.
  • Nó cũng quan trọng ngang bằng về quyền truy cập. Tôi nói thế này: quyền sở hữu từ master chính, quyền truy cập từ cả hai, và cái hạn chế nhất sẽ thắng. Một đối tượng nối, như mọi bản ghi chi tiết, không có bảng chia sẻ riêng. Salesforce kiểm tra quyền truy cập của người dùng vào cả hai bản ghi chính, thông qua Sharing Setting trên mỗi trường chính-chi tiết. Nếu cả hai được đặt là Read/Write, người dùng cần quyền Read/Write trên tổ giao hàng và trên xe tải để sửa Phân công tổ (Considerations for Object Relationships (opens in a new tab), tiếng Anh).
  • Nó cũng xóa ngang bằng. Xóa một trong hai bản ghi chính, tổ giao hàng hoặc xe tải, và các bản ghi nối của nó vào Thùng rác. Xóa cả hai thì chúng mất hẳn.
Master chính và master phụ của một đối tượng nối Một đối tượng nối nằm dưới hai bản ghi cha chính-chi tiết của nó, vẽ bằng đường đậm. Tổ giao hàng, ở trên bên trái, là master chính, vì trường chính-chi tiết của nó được tạo trước; nó cho Phân công tổ chủ sở hữu và giao diện. Xe tải, ở trên bên phải, là master phụ; nó quyết định phạm vi của loại báo cáo thứ hai và trở thành master chính nếu quan hệ thứ nhất bị gỡ bỏ. Phân công tổ nằm giữa và bên dưới chúng. Bên dưới: quyền truy cập cần cả hai bản ghi cha, và cái hạn chế nhất sẽ thắng; xóa bản ghi cha nào thì phân công cũng mất theo. chủ sở hữu và giao diện phạm vi báo cáo Tổ giao hàng Crew__c · master chính: tạo trước Xe tải Truck__c · master phụ Phân công tổ Crew_Assignment__c Quyền truy cập cần cả hai bản ghi cha: cái hạn chế nhất sẽ thắng. Xóa bản ghi cha nào thì phân công cũng mất theo. đúng một không hoặc một một hoặc nhiều không hoặc nhiều chính-chi tiết © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

Thêm vài quy tắc nữa: cả hai bản ghi chính đều có thể có trường tổng hợp cuộn lên từ đối tượng nối, và công thức cùng quy tắc xác thực của đối tượng nối có thể với tới các trường trên cả hai. Nhưng một đối tượng nối không thể là bản ghi chính của bất cứ thứ gì khác, nên nó không thể nằm ở giữa một chồng, và hai bản ghi chính không thể là cùng một đối tượng; một quan hệ nhiều-nhiều từ một đối tượng đến chính nó cần một thiết kế khác. Và nếu một bản ghi cha có hơn 200 bản ghi nối và đối tượng nối tổng hợp lên bản ghi cha còn lại, Salesforce sẽ không cho bạn xóa bản ghi cha đó cho đến khi bạn đã gỡ bỏ đủ số bản ghi nối.

Vậy: bản ghi cha nào nên là master chính? Hãy tạo trước bản ghi cha sở hữu ý nghĩa. Với một Phân công tổ, tổ giao hàng là bên làm việc, nên tôi sẽ tạo Tổ giao hàng trước. Rồi hãy ghi lại điều đó, vì không có gì trên màn hình sẽ cho người tiếp theo biết.

Nói vậy thôi, thực tế tôi không có nhiều đối tượng nối của Salesforce. Thông thường một đối tượng có một bản ghi cha chính-chi tiết, và nó cùng loại dữ liệu: dữ liệu khách hàng dưới dữ liệu khách hàng, dữ liệu giao dịch dưới dữ liệu giao dịch (nhớ lại các loại dữ liệu ở chương 2: khách hàng, giao dịch, tham chiếu). Khi bản ghi cha còn lại của nó là một loại khác, thường là một đối tượng tham chiếu, quan hệ đó là một quan hệ tra cứu. Một Mặt hàng giao thuộc về Giao hàng của nó: chính-chi tiết, cả hai đều là dữ liệu giao dịch. Nó trỏ đến Sản phẩm mà nó chở bằng một quan hệ tra cứu, vì sản phẩm là dữ liệu tham chiếu có cuộc đời riêng, và không ai muốn việc xóa một sản phẩm kéo theo cả nhiều năm lịch sử giao hàng. Mặt hàng giao vẫn là một đối tượng nối logic giữa một lần giao hàng và các sản phẩm trên đó; nó chỉ không phải là một đối tượng nối của Salesforce.

Quan hệ tự thân: khi đường kẻ quay về

Phần tiêu đề “Quan hệ tự thân: khi đường kẻ quay về ”

Một đối tượng có thể liên kết với chính nó: tài khoản cha, người quản lý, một trung tâm phân phối báo cáo lên một trung tâm vùng. Salesforce dựng sẵn hai quan hệ bạn sẽ gặp trong hầu hết mọi org: Tài khoản đến Tài khoản, trường Tài khoản cha (Parent Account) xây nên phân cấp tài khoản, và Trường hợp đến Trường hợp, Trường hợp cha (Parent Case) từ mô-đun 2, dùng để nhóm các trường hợp liên quan. Quan hệ tự thân phải là quan hệ tra cứu, và một bản ghi không thể trỏ đến chính nó, mặc dù hai bản ghi có thể trỏ đến nhau (Considerations for Object Relationships (opens in a new tab), tiếng Anh). Trên đối tượng User, nó là một kiểu riêng, quan hệ phân cấp (hierarchical), dùng cho những thứ như người quản lý của một người dùng. Cơ chế thì dễ; cách đặt tên mới quan trọng. Một quan hệ tra cứu từ Trung tâm phân phối đến Trung tâm phân phối tên là Distribution_Center__c chẳng giúp được ai. Cha? Dự phòng? Quá tải? Hãy đặt tên quan hệ theo vai trò, không theo đối tượng mà nó trỏ đến.

Quan hệ tự thân Ba đối tượng, mỗi đối tượng có một quan hệ tra cứu đến chính nó. Tài khoản, qua trường ParentId, trỏ đến một tài khoản cha, tạo nên phân cấp tài khoản. Trường hợp, qua trường ParentId, trỏ đến một trường hợp cha. Trung tâm phân phối, một đối tượng tùy chỉnh, trỏ đến trung tâm vùng của nó qua một trường tên là Regional_Hub__c. Bên dưới: luôn là quan hệ tra cứu, không bao giờ trỏ đến cùng một bản ghi, và được đặt tên theo vai trò nó đảm nhận. tài khoản cha trường hợp cha trung tâm vùng Tài khoản Account · ParentId Trường hợp Case · ParentId Trung tâm phân phối Distribution_Center__c · Regional_Hub__c Luôn là quan hệ tra cứu, không bao giờ trỏ đến cùng một bản ghi, và được đặt tên theo vai trò nó đảm nhận. đúng một không hoặc một một hoặc nhiều không hoặc nhiều tra cứu © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

Phân cấp: quan hệ riêng của đối tượng User

Phần tiêu đề “Phân cấp: quan hệ riêng của đối tượng User ”

Điều này nhỏ thôi, và đó chính là loại sự thật ít người biết, độc nhất vô nhị mà tôi nghĩ một kỳ thi sẽ khai thác. Phân cấp (Hierarchical) là một quan hệ tra cứu đặc biệt chỉ tồn tại trên đối tượng User. Nó liên kết một người dùng với một người dùng khác, và Salesforce không cho chuỗi vòng ngược lại: một người dùng không thể trỏ đến chính mình, trực tiếp hay gián tiếp (Object Relationships Overview (opens in a new tab), tiếng Anh). Nếu người quản lý của Maria là Dev, thì người quản lý của Dev không thể là Maria, hay bất kỳ ai báo cáo lên Maria.

Đó là điểm khác với các quan hệ tự thân ở trên. Trên Tài khoản hay một đối tượng tùy chỉnh, hai bản ghi có thể trỏ đến nhau. Trên User, phân cấp phải giữ là phân cấp. Và đó là cách duy nhất để liên kết User với User: một quan hệ tra cứu thông thường từ User đến chính nó không được cung cấp.

Bạn đã có sẵn một cái. Trường Manager chuẩn trên User là một quan hệ phân cấp, và quy trình phê duyệt có thể dùng nó: gửi yêu cầu này đến người quản lý của người gửi. Bạn cũng có thể tạo cái của riêng mình, chẳng hạn Người liên hệ khi leo thang (Escalation Contact) hay Người phê duyệt dự phòng (Backup Approver), và một quy trình phê duyệt có thể đi theo nó theo cùng cách (ApprovalProcess, Metadata API (opens in a new tab), tiếng Anh). Đừng nhầm nó với phân cấp vai trò, thứ điều khiển quyền truy cập bản ghi. Một trường phân cấp chỉ là một quan hệ giữa các người dùng; nó không chia sẻ một bản ghi nào cả.

Kiến thức hay ra thi. Quan hệ phân cấp chỉ tồn tại trên đối tượng User, như trường Manager chuẩn, và một người dùng không thể trỏ đến chính mình, trực tiếp hay gián tiếp. Nó không phải là phân cấp vai trò.

Mỗi đối tượng có tối đa hai quan hệ chính-chi tiết. Trường tra cứu và trường chính-chi tiết cùng được tính là trường quan hệ: mặc định 40 trên mỗi đối tượng, tối đa 50 khi yêu cầu. Trường tổng hợp cuộn lên: mặc định 25 trên mỗi đối tượng, tối đa 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), tiếng Anh). Salesforce nói thêm rằng nâng một trong hai giới hạn có thể ảnh hưởng đến hiệu năng.

Bạn không cần thiết kế theo những con số đó; bạn cần nhận ra khi mình đang đến gần chúng. Một đối tượng có hết quan hệ này đến quan hệ khác treo trên nó đang nói với bạn điều gì đó. Có thể nó thực sự trung tâm đến vậy. Hoặc có thể mô hình sai. (Và quy tắc khoảng dự phòng của chương 18 áp dụng: hãy ở xa dưới giới hạn, đo theo năm thứ ba.)

Rồi đến bản ghi cha có quá nhiều con. Hướng dẫn của chính Salesforce là không vượt quá khoảng 10.000 bản ghi con cho một bản ghi cha chính-chi tiết (Considerations for Object Relationships (opens in a new tab), tiếng Anh), và hướng dẫn về truy cập bản ghi ở quy mô lớn của họ cũng nói như vậy cho quan hệ cha-con nói chung (Parent-Child Data Skew (opens in a new tab), tiếng Anh). Bản ghi thứ 10.001 không làm hỏng org. Nhưng vượt qua ngưỡng đó, việc lưu một bản ghi con có thể khóa bản ghi cha, và thay đổi chia sẻ trên bản ghi cha lan qua mọi bản ghi con.

Vì vậy khi thấy một bản ghi cha, số lượng bản ghi con khổng lồ, tôi hỏi: tại sao tất cả đều nằm dưới cùng một bản ghi cha, ai sở hữu chúng, chúng được truy vấn thế nào, và tự động hóa nào chạm vào bản ghi cha? Mọi lần giao hàng dưới một tài khoản “Steve Trucking” duy nhất sẽ vượt 10.000 trong vài ngày. Một quan hệ một-nhiều vô hại trở thành vấn đề lệch dữ liệu. Mô-đun tiếp theo giới thiệu trước về lệch dữ liệu, và Phần 2 đi sâu.

Đừng thiết kế đường kẻ theo tính năng

Phần tiêu đề “Đừng thiết kế đường kẻ theo tính năng ”

Đây là thói quen tôi muốn bạn có từ mô-đun này. Đừng bắt đầu từ “tôi cần trường tổng hợp”, “tôi cần nó bắt buộc”, “tôi muốn chia sẻ được thừa hưởng”. Đó là những manh mối hiện thực. Hãy bắt đầu từ nghiệp vụ: bản ghi con có cuộc đời riêng không, ai sở hữu nó, nó có tồn tại một mình được không, có di chuyển được không, chuyện gì xảy ra khi bản ghi cha mất đi, quan hệ có mang dữ liệu không, và mỗi bên có thể lớn đến đâu? Rồi chọn quan hệ hiện thực các câu trả lời đó.

Tra cứu, chính-chi tiết hay đối tượng nối? Một ma trận gồm ba khuôn mẫu quan hệ đối chiếu với sáu câu hỏi nghiệp vụ. Quan hệ tra cứu: bản ghi con có thể tồn tại độc lập, có chủ sở hữu riêng, có thể đổi bản ghi cha, và chịu được hơn 10.000 bản ghi con mỗi bản ghi cha, dù vẫn cần để ý lệch dữ liệu; mặc định nó không đi theo bản ghi cha (trường bị xóa trống hoặc thao tác xóa bị chặn) và mỗi trường giữ một bản ghi cha. Nó có nghĩa là được nối với nhau. Chính-chi tiết: bản ghi cha là bắt buộc, bản ghi con thừa hưởng chủ sở hữu của bản ghi cha, nó bị xóa dây chuyền cùng bản ghi cha, chỉ đổi bản ghi cha nếu cho phép đổi cha (reparenting), và hơn 10.000 bản ghi con kéo theo khóa bản ghi cha và tính toán lại. Nó có nghĩa là thuộc về. Đối tượng nối của Salesforce (Salesforce Junction Object): nó cần cả hai bản ghi cha, lấy chủ sở hữu từ master chính, bị xóa cùng bất kỳ bản ghi cha nào, và là khuôn mẫu duy nhất cho quan hệ nhiều ở cả hai phía. Nó có nghĩa là một khái niệm nghiệp vụ. Bên dưới: trả lời các câu hỏi nghiệp vụ trước; kiểu quan hệ đi theo sau. TỒN TẠI ĐỘC LẬP CHỦ SỞ HỮU RIÊNG ĐI THEO BẢN GHI CHA ĐỔI BẢN GHI CHA NHIỀU Ở CẢ HAI PHÍA HƠN 10.000 MỖI BẢN GHI CHA NGHĨA LÀ Quan hệ tra cứu Giao hàng → Tuyến xóa trống hoặc chặn, mặc định một bản ghi cha mỗi trường vẫn phải để ý lệch dữ liệu ĐƯỢC NỐI VỚI NHAU Chính-chi tiết Giao hàng → Mặt hàng giao bắt buộc có bản ghi cha thừa hưởng của bản ghi cha xóa dây chuyền chỉ khi bật đổi cha một bản ghi chính mỗi trường khóa bản ghi cha, tính lại THUỘC VỀ Đối tượng nối của Salesforce Tổ giao hàng + Xe tải → Phân công tổ cần cả hai bản ghi cha từ master chính bản ghi cha nào cũng xóa được nó chỉ khi bật đổi cha đó là việc của nó cùng hướng dẫn 10.000 MỘT KHÁI NIỆM NGHIỆP VỤ Trả lời các câu hỏi nghiệp vụ trước. Kiểu quan hệ đi theo sau; đừng bắt đầu từ tính năng bạn muốn. © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

Ngoài kỳ thi: AI thay đổi điều gì. AI có thể đề xuất quan hệ trong vài giây. Nó không thể cho bạn biết nghiệp vụ có bao giờ xóa bản ghi cha hay không. Vẽ sơ đồ nhanh hơn không làm cho một quan hệ sai rẻ hơn khi đảo ngược, một khi hàng triệu bản ghi và hàng chục tự động hóa đã phụ thuộc vào nó.

  • Bản ghi con có vòng đời riêng hay thực sự thuộc về bản ghi cha, và quyền sở hữu cùng quyền truy cập nên là của riêng nó hay được thừa hưởng.
  • Bản ghi con có tồn tại được mà không có bản ghi cha, có chuyển giữa các bản ghi cha, hay có tồn tại sau khi bản ghi cha bị xóa không.
  • Mỗi quan hệ tra cứu làm gì khi bản ghi cha của nó bị xóa: xóa trống, chặn, hay xóa dây chuyền.
  • Một quan hệ nhiều-nhiều là đường ống kỹ thuật hay một khái niệm nghiệp vụ, đối tượng nối logic có trở thành đối tượng nối của Salesforce không, bản ghi cha nào là master chính, và cả hai bản ghi cha có ý nghĩa gì với quyền truy cập.
  • Mô hình có phù hợp với hình dáng của nền tảng không: sâu ba tầng chi tiết tùy chỉnh, rộng hai bản ghi cha chính-chi tiết, giới hạn quan hệ và trường tổng hợp.
  • Số lượng và sự phân bố bản ghi con dự kiến có tạo ra rủi ro lệch dữ liệu đáng để thay đổi thiết kế không.

Một quan hệ là một tập hợp lời hứa về cách hai mẩu dữ liệu hành xử cùng nhau. Hãy đưa ra chúng một cách có chủ ý.