Skip to content

設計 Salesforce 物理模型

另有 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 section model cut straight through a small building, showing every floor, room, stair and pipe in one slice.
圖片由 AI 生成

第 10 個模組,共 10 個,屬於 Data Architect 課程第 3 章Salesforce 資料架構。每個模組都可以單獨閱讀。 上一篇:保持資料一致 · 下一篇:本章學習指南,然後是下一章理解企業資料

**本模組回答的問題:**我們如何把邏輯模型變成一個 Salesforce 架構?

這一章從頭到尾都在論證一件事:平台有它的形狀:標準物件和自訂物件,資料可以存放的地方,欄位類型,關係,所有權,許可,一致性規則,儲存和規模。每一樣都可能改變第 2 章的邏輯模型被構建的方式。現在,我們在 Steve Trucking 的一個切面上把它們串起來。

一個切面,而不是整個公司。我看到架構師犯的一個錯誤,是試圖在一張圖裡解決整個企業。我要的是一個我們能推理清楚的東西:一個零售合作夥伴發來一份裝貨清單,Steve Trucking 把清單上的東西送到,我們保留每次配送所需的資訊。然後我們一次做一個物理層面的決定。完整的設計留給第 1 部分的檢查點。

第 2 章完成了概念層面的工作:零售合作夥伴、收貨人、裝貨清單、配送、配送項目、停靠點類型、配送小組、卡車、配送中心、照片。我們給關係起了名字,並問了它們意味著什麼。我不再重複。現在的問題是**這些概念如何在 Salesforce 上存在。**簡介裡有一個事實馬上就很重要:Steve Trucking 已經在用 Field Service 來管理預約、配送小組和移動應用。

零售合作夥伴:不要發明一個客戶物件

Section titled “零售合作夥伴:不要發明一個客戶物件 ”

零售合作夥伴是 Steve Trucking 為之工作的公司。Salesforce 已經有一個為公司設計的物件:**客戶(Account)。**乾淨契合。所以不要因為業務方說了「合作夥伴」就建 Retail_Partner__c。它就是一個客戶,用一個零售合作夥伴記錄類型把它和其他組織區分開,隨之而來的還有合同、案例、作為連絡人的配送中心經理,以及這些連絡人的入口網站存取。很簡單的決定。但不是每個決定都這麼簡單。

合作夥伴的訂單號不是我們的身分標識

Section titled “合作夥伴的訂單號不是我們的身分標識 ”

每個零售合作夥伴都會發來它自己的編號。一個合作夥伴的訂單長這樣:8843119,另一個長這樣:A-984732。這些編號很重要,但它們是誰的?是合作夥伴的。Salesforce 有自己的記錄 ID,合作夥伴則有它在和我們溝通時使用的編號。兩者可以並存;這就是第 2 章的「一樣東西,好幾個識別符號」。

所以合作夥伴的編號成為一個外部 ID,整合用它來比對更新。而且因為兩個合作夥伴可能使用同一個編號,身分標識是合作夥伴加編號,而不是單獨的編號。不要因為某個合作夥伴的編號先到,就把它當作配送的通用身分標識,也不要讓整合每次需要找一條記錄時都去搜索一個文字欄位。

在這裡,人們很容易就去建立 Delivery__c。業務方說了「配送」,所以我們需要一個配送物件。這正是我不希望你首先去做的事。看向母艦,就像我們在模組 2 裡做的那樣。對於在某個地點執行、有生命週期、有項目、需要排期、有一個外勤小組的工作,Salesforce 已經有什麼?Field Service 的工作訂單(Work Order):Salesforce 把它描述為要為客戶執行的現場服務工作(WorkOrder (opens in a new tab),英文)。排定的上門服務及其時間視窗是服務約會(Service Appointment),而這正是排程排期的物件,也是配送小組的應用裡顯示的東西。

所以配送 → 工作訂單。不是因為詞對得上;它們對不上。而是因為它的行為與我們已經付費並打算使用的平台能力相吻合。一個標準物件不必和業務用同樣的詞彙。它必須正確地表示這個概念。

Steve Trucking 物理模型 Steve Trucking 的物理模型,每張卡片是一個業務概念,下方標出它對應的 Salesforce 物件。核心之上:零售合作夥伴是帶有記錄類型的客戶(Account),它發出裝貨清單,也就是自訂物件 Manifest__c,而每次配送都對應一個合作夥伴。每份裝貨清單列出若干次配送;配送是一張工作訂單(Work Order),以外部 ID 比對。一次配送排期為服務約會(Service Appointment),並包含配送項目,也就是工作訂單明細項目(Work Order Line Item),每個項目由一個停靠點類型,也就是工作類型(Work Type),來描述。三年後,配送移至配送歷史,這是一個大物件,歸檔在核心之上。核心之外:每次配送履行一個合作夥伴訂單,這是一個位於零售商系統中的外部物件;配送還連結到照片儲存中的配送照片。每條線都是查閱關係:Salesforce 以查閱關係打造 Field Service,而我們連同它的決定一併採用。 核心之上 核心之外 對應 排期為 零售合作夥伴 Account · 記錄類型 配送 WorkOrder · 外部 ID 預約 ServiceAppointment 每條線都是查閱關係:Salesforce 以查閱關係打造 Field Service,而我們連同它的決定一併採用。 恰好一個 零個或一個 一個或多個 零個或多個 查閱 © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

第 1 步,共 4 步:母艦。每張卡片是業務概念,下面是它對應的 Salesforce 物件。

另一面是:工作訂單不是免費的。它帶來了 Field Service 的許可、它自己的關係、安全行為、必填欄位、自動化和生命週期,而平台的其他部分期望它以某種方式表現。我們選擇它,是因為契合是乾淨的,而且我們在使用圍繞它構建的東西。如果 Steve Trucking 完全不想要 Field Service,而模型又處處和流程作對,我就會重新考慮。架構在於契合,而不在於標籤。

一旦配送成為工作訂單,在發明任何東西之前,先看看那個模型的其餘部分。工作訂單明細項目(Work Order Line Item)是工作訂單上的一個子任務(WorkOrderLineItem (opens in a new tab),英文):冰箱、安裝、拉走舊貨。所以**配送項目 → 工作訂單明細項目。**注意,第一個決定塑造了第二個決定。我們不是在為每個實體單獨選擇物件。採用一個模型,並在圍繞它構建自訂結構之前,先理解它的其餘部分。

在 Steve Trucking,一個停靠點是僅配送、配送加安裝,或者配送加拉走舊貨,而每一種都有自己的時長、配送小組技能和安裝檢查清單。在第 2 章裡,我們認定這是一個實體,而不是一個標籤。Field Service 已經有一個:工作類型(Work Type),一種可以應用到工作訂單和明細項目上的工作類別模板(WorkType (opens in a new tab),英文)。所以**停靠點類型 → 工作類型。**同樣,不是因為存在一個叫工作類型的東西,而是因為概念和行為對得上。

Steve Trucking 物理模型 Steve Trucking 的物理模型,每張卡片是一個業務概念,下方標出它對應的 Salesforce 物件。核心之上:零售合作夥伴是帶有記錄類型的客戶(Account),它發出裝貨清單,也就是自訂物件 Manifest__c,而每次配送都對應一個合作夥伴。每份裝貨清單列出若干次配送;配送是一張工作訂單(Work Order),以外部 ID 比對。一次配送排期為服務約會(Service Appointment),並包含配送項目,也就是工作訂單明細項目(Work Order Line Item),每個項目由一個停靠點類型,也就是工作類型(Work Type),來描述。三年後,配送移至配送歷史,這是一個大物件,歸檔在核心之上。核心之外:每次配送履行一個合作夥伴訂單,這是一個位於零售商系統中的外部物件;配送還連結到照片儲存中的配送照片。每條線都是查閱關係:Salesforce 以查閱關係打造 Field Service,而我們連同它的決定一併採用。 核心之上 核心之外 對應 排期為 包含 描述 零售合作夥伴 Account · 記錄類型 配送 WorkOrder · 外部 ID 配送項目 WorkOrderLineItem 預約 ServiceAppointment 停靠點類型 WorkType 每條線都是查閱關係:Salesforce 以查閱關係打造 Field Service,而我們連同它的決定一併採用。 恰好一個 零個或一個 一個或多個 零個或多個 查閱 © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

第 2 步,共 4 步:順著模型走。明細項目和工作類型隨工作訂單一起到來。

裝貨清單:現在我想要一個自訂物件

Section titled “裝貨清單:現在我想要一個自訂物件 ”

有沒有一個標準物件來表示「合作夥伴在鳳凰城配送中心週二的那份清單」?其實沒有,而我也不會為了說我們堅持用了標準物件,就把它硬塞進一個不相干的物件裡。**裝貨清單 → Manifest__c。**它是接收的單位:它從哪裡來(一個檔案、一批 API 資料),什麼時候來的,它的狀態和總數,以及當合作夥伴當天重發時,要比較些什麼。清單上的每一行都成為一個工作訂單,並連結回這份清單。

**用自訂物件不是失敗。**當一個概念沒有乾淨的標準歸宿時,這正是平台給我們的東西。錯誤不在於建立自訂物件,而在於沒有先檢查平台是否已經有這個概念就去建立它。

Steve Trucking 物理模型 Steve Trucking 的物理模型,每張卡片是一個業務概念,下方標出它對應的 Salesforce 物件。核心之上:零售合作夥伴是帶有記錄類型的客戶(Account),它發出裝貨清單,也就是自訂物件 Manifest__c,而每次配送都對應一個合作夥伴。每份裝貨清單列出若干次配送;配送是一張工作訂單(Work Order),以外部 ID 比對。一次配送排期為服務約會(Service Appointment),並包含配送項目,也就是工作訂單明細項目(Work Order Line Item),每個項目由一個停靠點類型,也就是工作類型(Work Type),來描述。三年後,配送移至配送歷史,這是一個大物件,歸檔在核心之上。核心之外:每次配送履行一個合作夥伴訂單,這是一個位於零售商系統中的外部物件;配送還連結到照片儲存中的配送照片。每條線都是查閱關係:Salesforce 以查閱關係打造 Field Service,而我們連同它的決定一併採用。 核心之上 核心之外 發出 對應 列出 排期為 包含 描述 零售合作夥伴 Account · 記錄類型 裝貨清單 Manifest__c · 自訂 配送 WorkOrder · 外部 ID 配送項目 WorkOrderLineItem 預約 ServiceAppointment 停靠點類型 WorkType 每條線都是查閱關係:Salesforce 以查閱關係打造 Field Service,而我們連同它的決定一併採用。 恰好一個 零個或一個 一個或多個 零個或多個 查閱 © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

第 3 步,共 4 步:唯一的一個自訂物件,用在沒有標準物件契合的地方。

照片:Salesforce 能存,不代表它應該存

Section titled “照片:Salesforce 能存,不代表它應該存 ”

「我們需要把配送照片放在 Salesforce 裡。」「放在 Salesforce 裡」是什麼意思?使用者需要從 Salesforce 中看到它們,沒錯。這是否意味著圖片檔案必須存放在核心儲存裡?不一定。數一數零的個數:每次配送大約四張照片,有安裝的更多,一年一百萬次配送,就是每年四五百萬張照片,而配送量每年增長 30%。

所以我的出發點是:**不要因為使用者需要存取照片,就把核心 org 變成一個巨大的照片倉庫。**檔案應該放在為這種資料量而構建的儲存中,在核心平台之外,由 Salesforce 保留它找到並顯示這些照片所需的東西:一個引用、一個數量,或者每張照片一條小小的索引記錄,外加一個表示所需安裝照片已齊全的標誌。存取資料,和資料在物理上存放在哪裡,是兩個不同的問題。這是模組 4 的內容又回來了。

工作訂單需要欄位:合作夥伴的編號、配送時間視窗、實際送達時間、狀態,還有「門禁密碼」或「院子裡有狗」之類的備註。我不會把這裡變成一份欄位目錄;模組 6 已經做過了。對每個欄位都過一遍那些問題:它意味著什麼,誰擁有它,它會不會變,它是不是一個識別符號、一套受控詞彙,是儲存的還是推導的,是否敏感。合作夥伴的編號是外部 ID,所以它的唯一性是整合契約的一部分,而不只是一個核取方塊。實際送達時間是一個時刻,所以用日期/時間。狀態驅動行為,所以用受控清單,絕不用自由文字。而關於某個人家裡的配送備註是個人資料,所以要對它們分類。每個欄位都能追溯到含義。

客戶到工作訂單,工作訂單到它的明細項目,裝貨清單到工作訂單,工作類型描述停靠點。然後對每一條線都問模組 7 的問題:子記錄能單獨存在嗎?誰擁有它?存取權限是否繼承?它能移動嗎?刪除時會怎樣?子記錄會堆積到多少?每個工作訂單都掛在少數幾個零售合作夥伴客戶下面,意味著每個父記錄下有幾十萬條子記錄:這是一個我們會在第 2 部分回答的傾斜問題。而對於 Field Service 的標準關係,要檢視 Salesforce 已經是怎麼構建它們的,而不是假設它們和我們會設計的一樣。當你採用一個標準模型時,你也採用了 Salesforce 在其中做出的決定。在其上構建之前,先理解它們。

所有權和收貨人:不要讓預設值替你決定

Section titled “所有權和收貨人:不要讓預設值替你決定 ”

有兩個決定,預設值會很樂意替我們做出。

**一次配送歸誰所有?我們在模組 8 裡回答過這個問題,而答案可以直接沿用到工作訂單上:在這裡,所有權並不決定任何人的存取權限,所以整合使用者擁有它所建立的工作訂單。**排程員看到自己配送中心的工作訂單,配送小組看到自己路線上的,每個零售合作夥伴通過入口網站看到自己的,這一切都通過共用實現,而不是通過所有權。整合使用者沒有角色,也不進入我們的共用規則所用的公用組,因為按每天 3,300 條計算,它三天就會超過 10,000 條記錄。我們還要寫下:如果這個使用者有一天被替換,會發生什麼。

**收貨人是什麼?一個連絡人?一個個人帳戶?還是隻儲存在配送上的某樣東西?這取決於 Steve Trucking 是否和這些人有任何關係(他們是零售合作夥伴的客戶),一個合作夥伴是否可能看到另一個合作夥伴的收貨人,他們的個人資料可以保留多久,還有規模:每年大約一百萬個新收貨人。這些我們還沒有全部掌握,這沒關係。有時候正確的答案是我們知道的還不夠。**把問題寫下來,然後去獲取資訊;不要把不確定性埋進一個自訂物件裡。我們會在第 1 部分的檢查點回答它,那時第 4 到第 6 章已經給了我們企業資料和主資料的全貌。

模組 9 的階梯在這裡適用:合作夥伴的編號是外部 ID,唯一,所以重發的裝貨清單會做 upsert,而不是產生重複;狀態是一個受限清單;實際送達時間只在狀態變為已送達後才是必填的;安裝停靠點在檢查清單和照片齊全之前不能關閉。不是一個巨大的 Flow。每條規則都在它自己的那一級上。

再把這個切面過一遍,帶著模組 4 的問題:**每一塊資料存放在哪裡?**在我的課堂幻燈片裡,這是一張幻燈片,邏輯對照物理:第 2 章的邏輯實體,以及每一個在物理上落在哪裡:核心之上,作為一個 sObject(如果是自訂的,就是 __c)或一個大物件(__b);或者核心之外,作為一個外部物件(__x),或者是根本不進入 Salesforce 的資料。

  • **核心之上,每天都在用:**客戶、工作訂單及其明細項目、服務約會、工作類型、Manifest__c。
  • **核心之上,已歸檔:**超過三年的配送移到配送歷史(Delivery History),一個大物件,仍然留著以備索賠,放在後院的棚子裡。
  • **引用的:**零售合作夥伴自己的訂單詳情留在合作夥伴的系統裡;我們把合作夥伴的編號儲存為外部 ID,有人需要其餘資訊時,再通過一個外部物件或整合去獲取。
  • **核心之外:**照片,放在為數以百萬計的圖片而構建的儲存中,工作訂單上保留一個連結。

這就是物理模型:不僅是哪個物件,還有哪個歸宿。

  • 零售合作夥伴 → 客戶,帶有零售合作夥伴記錄類型;配送中心經理作為連絡人。
  • 配送 → Field Service 工作訂單,通過服務約會排期。
  • 配送項目 → 工作訂單明細項目。
  • 停靠點類型 → 工作類型。
  • 裝貨清單 → 自訂物件 Manifest__c。
  • 合作夥伴編號 → 工作訂單上的外部 ID,在每個合作夥伴內唯一。
  • 照片 → 存放在核心平台之外;Salesforce 保留引用和齊全標誌。
  • 配送歷史 → 三年後歸檔到一個大物件。
  • 所有權 → 整合使用者,存取通過共用實現(模組 8)。
  • 收貨人 → 未決,留給第 1 部分的檢查點。
Steve Trucking 物理模型 Steve Trucking 的物理模型,每張卡片是一個業務概念,下方標出它對應的 Salesforce 物件。核心之上:零售合作夥伴是帶有記錄類型的客戶(Account),它發出裝貨清單,也就是自訂物件 Manifest__c,而每次配送都對應一個合作夥伴。每份裝貨清單列出若干次配送;配送是一張工作訂單(Work Order),以外部 ID 比對。一次配送排期為服務約會(Service Appointment),並包含配送項目,也就是工作訂單明細項目(Work Order Line Item),每個項目由一個停靠點類型,也就是工作類型(Work Type),來描述。三年後,配送移至配送歷史,這是一個大物件,歸檔在核心之上。核心之外:每次配送履行一個合作夥伴訂單,這是一個位於零售商系統中的外部物件;配送還連結到照片儲存中的配送照片。每條線都是查閱關係:Salesforce 以查閱關係打造 Field Service,而我們連同它的決定一併採用。 核心之上 核心之外 發出 對應 列出 排期為 包含 描述 由…履行 連結到 移至 零售合作夥伴 Account · 記錄類型 裝貨清單 Manifest__c · 自訂 配送 WorkOrder · 外部 ID 配送項目 WorkOrderLineItem 配送歷史 Delivery_History__b 預約 ServiceAppointment 停靠點類型 WorkType 合作夥伴訂單 Partner_Order__x 配送照片 照片儲存,以連結指向 每條線都是查閱關係:Salesforce 以查閱關係打造 Field Service,而我們連同它的決定一併採用。 恰好一個 零個或一個 一個或多個 零個或多個 查閱 © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

第 4 步,共 4 步:整個切面,包括核心之上、已歸檔和核心之外的部分。每條連線都是一個查閱關係:Salesforce 用查閱關係構建了 Field Service,而我們連同它的決定一起採用。

我可以把那張圖交給你,但這還不夠。**架構是它背後的推理過程。**為什麼用客戶?一家乾淨契合的公司。為什麼用工作訂單而不是 Delivery__c?配送的行為像現場工作,而 Field Service 已經到位。為什麼用自訂的裝貨清單?沒有乾淨的標準歸宿。為什麼照片不直接用檔案?資料量和儲存的經濟賬。為什麼用外部 ID?另一個系統需要一個跨越邊界的穩定身分標識。為什麼由整合使用者擁有工作訂單?在這裡,所有權並不決定存取權限,而這樣能讓稽核軌跡保持真實。為什麼收貨人仍然未決?我們回答的問題還不夠多。連線是產出;是那些決定產生了它們。

所以這是我希望你帶著離開第 3 章的習慣。指著物理模型裡的任何東西問**為什麼?**為什麼是這個物件、這個類型、這個關係、這個所有人、這個地方、這條規則?你應該能把答案追溯回去:從配置,到物理模型,到邏輯模型,再到業務需求。如果你做不到,那就是有人從設定介面開始做了設計。

你也會注意到那些我們還沒完全算清的數字:每個合作夥伴的配送量、明細項目、照片、保留、歸檔。很好。在鎖定設計之前,先問零的個數:一個在五萬條記錄下執行得很漂亮的模型,在五億條記錄下可能表現得截然不同。那是第 2 部分的內容。

**考試之外:AI 改變了什麼。**把 Steve Trucking 的簡介交給 AI,它會在幾秒內生成一套結構:客戶、工作訂單、自訂物件、欄位,甚至部署後設資料。這是一個出色的加速器,但它不是評審。架構師的工作轉向檢查這些對映及其後果:契合度、許可、所有權、生命週期、規模、身分、安全,以及什麼留在平台之外。AI 是火箭助推器;它不會告訴你方向是否對準了。

  • 每個業務概念如何對映到 Salesforce:一個標準物件、一個自訂物件,還是核心平台之外的某樣東西。
  • 哪些識別符號、欄位和關係實現了業務含義,而沒有悄悄改變它。
  • 你所採用的標準模型附帶了哪些平台行為和許可。
  • 在設計完成之前,必須做出哪些關於所有權、生命週期、一致性、儲存和規模的決定。
  • 哪些問題要明確地保持開放,而不是藏在一個隨意的實現選擇背後。

在本章開頭,我們問的是模型應該如何在 Salesforce 上存在。這就是 Salesforce 資料架構:不是建立物件,不是背熟設定介面,也不是畫更漂亮的方框,而是有意識地讓業務模型契合平台的形狀。**每個結構都是一份承諾。**做那些你能解釋清楚的承諾。