У связей есть последствия
Также доступно на 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 мы рисовали линии и давали им имена: розничный партнер отправляет много манифестов, доставка везет много позиций, бригады и грузовики встречаются в назначении бригады (Crew Assignment). Мы говорили о кардинальности, обязательности и истории. Теперь мы реализуем эти линии в Salesforce, и линия на диаграмме начинает нести гораздо больший вес.
Когда я выбираю тип связи в Salesforce, я не просто говорю, что эти две записи связаны. Я, возможно, также решаю, кто владеет дочерней записью, может ли она существовать без родителя, кто может ее видеть, что будет, когда родителя удалят, может ли она перейти к другому родителю, могу ли я свести ее данные на родителя и что будет, когда дочерних записей сотни тысяч. Связь — это не просто линия. Она несет поведение.
Начните с бизнес-отношения
Заголовок раздела «Начните с бизнес-отношения »Прежде чем думать о lookup или master-detail, вернитесь к бизнесу. Возьмите доставку и ее позиции доставки — холодильник, установку, вывоз старой техники. Может ли позиция существовать без своей доставки? Нет. Если доставку удалят, должны ли исчезнуть ее позиции? Да. Нужны ли позициям собственный владелец или собственная безопасность? Не особенно. Должен ли кто-то переносить позицию из одной доставки в другую? Надеюсь, не случайно.
Теперь возьмите доставку и маршрут (Route), в который она входит. Доставка существует до того, как ее поставили в маршрут, ее можно перенести в другой маршрут, когда план меняется, и удаление маршрута никогда не должно удалять доставки в нем. Две связи «один ко многим», которые на диаграмме выглядят одинаково, с совершенно разным поведением. Заметьте, мы все еще не сказали «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 объекта на самого себя.
- Иерархическая: особый lookup, который существует только на объекте User, например руководитель пользователя.
- External lookup и indirect lookup: связи к внешним объектам и от них — объектам
__xиз модуля 4. External lookup указывает на родительский внешний объект; indirect lookup указывает от внешнего объекта на стандартный или пользовательский объект, с сопоставлением по уникальному External ID.
Большая часть вашего времени на проектирование уходит на первые три. Разберем их по одному.
Lookup: эти записи связаны
Заголовок раздела «Lookup: эти записи связаны »Lookup говорит: эта запись связана с той записью. Дочерняя запись остается самостоятельной: у нее свой владелец и своя жизнь. Доставка указывает на свой маршрут. Если маршрут отменили, доставки не исчезают; они возвращаются, чтобы их снова поставили в маршрут.
Забавно: поле lookup находится на дочерней записи, но родитель тоже кое-что получает — связанный список своих дочерних записей. Поэтому, создавая его, назовите оба конца. 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 (удалить и эту запись) — каскадное удаление, как у master-detail. Оно предлагается только для пользовательского lookup на пользовательском объекте, по умолчанию отключено, и включить его для вашего org должен Salesforce, потому что каскадное удаление обходит безопасность и общий доступ: пользователи могут удалять записи, которые даже не могли видеть.
Это решение о жизненном цикле, спрятанное в экране настройки.
Фильтры lookup сужают то, что может выбрать пользователь. Скажем, у доставки есть lookup Installer на Contact, а монтажники — лишь один тип записи контакта среди многих. Фильтр lookup показывает только монтажников, и он может фильтровать по текущей записи, по записи, которую ищут, и по пользователю: его профилю, роли или разрешениям (Lookup Filters (opens in a new tab)). Это дешевый способ держать lookup честным.
Master-detail: эта дочерняя запись принадлежит тому родителю
Заголовок раздела «Master-detail: эта дочерняя запись принадлежит тому родителю »Master-detail делает куда более сильное заявление. На занятиях я называю это очень тесной привязкой. Подчиненная запись не может существовать без главной; поле master обязательно. Подчиненная запись теряет собственное поле Owner и наследует владельца родителя. У подчиненного объекта нет отдельной таблицы общего доступа, поэтому дочернюю запись нельзя расшарить отдельно; она наследует общий доступ родителя. Вот почему у подчиненного объекта не может быть правил общего доступа, ручного общего доступа или очередей: всем им нужно поле Owner (Object Relationships Overview (opens in a new tab)). В Setup его настройка общего доступа выглядит как Controlled by Parent (управляется родителем). А в самом поле master-detail вы выбираете Sharing Setting: какой доступ к главной записи нужен пользователю — Read Only или Read/Write, — чтобы создавать, редактировать или удалять ее подчиненные записи. Удаление главной записи удаляет ее подчиненные. А главная запись получает поля сводки (roll-up summary).
Так что если позиция доставки — подчиненная запись доставки, я говорю: эта позиция принадлежит этой доставке всю свою жизнь. Вот на какой вопрос я хочу получить ответ, прежде чем кто-то выберет в Setup Master-Detail Relationship.
Вопрос об удалении
Заголовок раздела «Вопрос об удалении »Вот мой любимый способ выяснить, продумали ли мы все: что должно произойти с дочерними записями, если кто-то удалит родителя? Всем становится неуютно. Хорошо. Теперь мы занимаемся архитектурой.
У розничного партнера сотни тысяч исторических доставок. Кто-то удаляет партнера. Должны ли доставки исчезнуть? Почти наверняка нет: от них зависят претензии, биллинг и история. Может, удаление партнера вообще не должно быть разрешено, а партнера нужно деактивировать. С master-detail удаление главной записи каскадом удаляет подчиненные и их подчиненные; восстановление главной записи возвращает их (Considerations for Object Relationships (opens in a new tab)). Поэтому когда кто-то говорит «master-detail дает нам roll-up», мой ответ: отлично. А на что еще вы только что согласились?
Владение едет в комплекте
Заголовок раздела «Владение едет в комплекте »С lookup у дочерней записи может быть свой владелец. С master-detail — нет; доступ следует за главной записью. Это ровно то, что нужно, если подчиненная запись действительно часть родителя. Но если дочерней записи нужен свой владелец, свой общий доступ или свой жизненный цикл, модель говорит вам, что master-detail — неверный выбор. Следующий модуль глубже разбирает владение, а курс Sharing and Visibility идет еще дальше. Пока запомните: проектирование связей и проектирование безопасности — не отдельные разговоры. Модель данных формирует модель безопасности еще до того, как кто-то напишет правило общего доступа.
Родитель обязателен или нет?
Заголовок раздела «Родитель обязателен или нет? »Может ли дочерняя запись существовать раньше, чем мы знаем ее родителя? Это важнее, чем кажется. Если доставки приходят в манифесте накануне вечером, а маршруты строятся потом, обязательный маршрут на доставке означал бы, что маршрутизация должна произойти еще до того, как запись можно создать. Физическая связь должна поддерживать реальный жизненный цикл. Поэтому я не проектирую связи только по статичной диаграмме. Я хочу знать: как они рождаются, могут ли существовать одни, могут ли переезжать и как умирают?
Может ли дочерняя запись сменить родителя?
Заголовок раздела «Может ли дочерняя запись сменить родителя? »По умолчанию дочернюю запись master-detail нельзя перенести к другому родителю. Это можно разрешить, выбрав для связи Allow reparenting (Considerations for Object Relationships (opens in a new tab)). Мой инстинкт консервативен: если бизнес говорит, что дочерняя запись принадлежит одному родителю всю жизнь, я не делаю ее перенос легким. Переход позиции из одной доставки в другую должен быть осознанным бизнес-событием, а не правкой поля. Опять же, настройка — не архитектура. Архитектура — это правило жизненного цикла, а настройка его реализует.
Еще две вещи, на которых команды попадаются позже. Нельзя создать связь master-detail на объекте, в котором уже есть данные; вы создаете lookup, заполняете его на каждой записи, а потом преобразуете. И преобразовать обратно в lookup можно, только если на главном объекте нет полей roll-up summary. Следите и за тем, что преобразование делает с безопасностью: превращение 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 не от чего пересчитываться. Такому числу нужен запланированный flow или отчет. - У фильтра тоже есть ограничения: нельзя длинную текстовую область, список с множественным выбором, Description, системные поля вроде Last Activity, межобъектные формулы и поля lookup.
- Roll-up нет на страницах редактирования, поэтому правило проверки может его использовать, но не может показать там свою ошибку.
И не переворачивайте решение. Не говорите: «Нам нужен roll-up, значит, это должен быть master-detail». Говорите: «Эта дочерняя запись действительно принадлежит этому родителю, владение и жизненный цикл подходят, и одно из преимуществ — нативные roll-up». Если смысл не подходит, решите расчет по-другому. Не искажайте модель данных ради функции.
Так какой же другой способ? Вы строите roll-up сами: поле на родителе, которое хранит вычисленное значение, и автоматизацию, которая поддерживает его актуальным. Скажем, розничный партнер связан с доставкой через lookup, как и должно быть, и бизнес хочет видеть на партнере открытые доставки. Добавьте партнеру числовое поле Open Deliveries. Затем flow, запускаемый записью (record-triggered flow), или триггер Apex, когда объем или логика требуют кода, пересчитывает его при каждом изменении доставки. Это работает через lookup, может фильтровать по чему угодно и может использовать даты и формулы, недоступные нативному roll-up.
Но теперь правильность — на вас, и именно здесь такие решения ломаются. Автоматизация должна срабатывать на каждое важное изменение: новая дочерняя запись, отредактированная, удаленная, восстановленная и дочерняя запись, перенесенная к другому родителю, — а это значит пересчитать и старого родителя, и нового. Она должна выдерживать загрузку данных по 200 записей за раз, не упираясь в лимиты. Пересчитывайте заново, а не прибавляйте и вычитайте, чтобы одно пропущенное событие не оставило число неверным навсегда. Предусмотрите способ пересчитать все — для первой загрузки и на тот день, когда значения разойдутся. И помните, что теперь каждое сохранение дочерней записи обновляет родителя, поэтому родитель с тысячами дочерних записей возвращает блокировки, которые мы сейчас увидим. Нативный roll-up делает все это за вас; пользовательский — это маленький кусочек ПО, которым владеете вы.
Три уровня вглубь: цепочки master-detail
Заголовок раздела «Три уровня вглубь: цепочки master-detail »У платформы есть форма, и у master-detail в ней два измерения. Первое — глубина.
Связи master-detail можно выстраивать в цепочку на три пользовательских подчиненных уровня вглубь, и это дно (Considerations for Object Relationships (opens in a new tab)). На занятиях я рисую это как организацию с заказом (один), заказ с его позициями (два) и позиции с их деталями (три), а потом пытаюсь добавить четвертый, и Salesforce не дает. В Steve Trucking это может выглядеть так: доставка — главная запись; ее позиции доставки — первый уровень; задачи установки (Install Tasks) позиции — второй; а шаги задачи (Task Steps) каждой задачи — третий. Четвертый уровень, скажем заметка к шагу (Step Note), должен быть lookup.
К цепочке прилагается несколько правил:
- Стандартные объекты не могут быть подчиненными для пользовательского объекта. Пользовательский объект может быть подчиненным для Account; Account не может быть подчиненным для вашего.
- Объект может появиться только один раз в многоуровневой цепочке. Salesforce не хочет, чтобы вы замыкались на себя: подчиненная запись второго уровня не может одновременно быть главной для своей главной.
- Главная запись не может напрямую свести нижний уровень. Если доставке нужно количество шагов задачи, задача установки сводит свои шаги, позиция доставки сводит эти сводки, а доставка сводит позиции: по одному уровню за раз.
- Владение и общий доступ идут сверху. Каждый уровень наследует владельца и доступ главной записи.
- Удаление главной записи удаляет все под ней, а ее восстановление возвращает все обратно.
Трех уровней обычно более чем достаточно. Если ваш дизайн все время просит четвертый, спросите, действительно ли каждый уровень принадлежит вышестоящему всю жизнь. И помните, что вы сами выбираете, какое звено разорвет цепочку. Четвертый уровень не обязательно должен быть lookup: может, задача установки на самом деле не принадлежит своей позиции доставки — ее планируют и назначают отдельно, — тогда это звено становится lookup, и теперь задача установки начинает новую цепочку, под которой шаг задачи и заметка к шагу. Выберите звено, где у дочерней записи действительно своя жизнь, и сделайте lookup именно его.
Теперь у задачи установки свой владелец и свой общий доступ, доставку можно удалить, не утянув за собой задачи установки, и под задачей установки может быть еще два уровня. Вот компромисс: цепочка короче, а жизнь задачи установки — ее собственная.
Два родителя вширь: связующий объект Salesforce
Заголовок раздела «Два родителя вширь: связующий объект Salesforce »Сначала пара слов о словах, потому что «связующий объект» (junction object) означает две вещи, и я преподаю обе.
В главе 2 мы нашли логический связующий объект: соединение двух ключевых идей, которое становится самостоятельной сущностью со своими атрибутами. Собака знает много трюков, трюк знают многие собаки, а Трюк собаки стоит между ними и хранит уровень навыка и дату. Это логический связующий объект — в логической модели, задолго до того, как кто-то решит, 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 или с двумя lookup — и это все равно логический связующий объект, просто не в понимании Salesforce. (Сам Salesforce не вполне последователен: в его собственном справочнике объектов некоторые стандартные объекты, построенные на lookup, названы «junction objects». На экзамене исходите из узкого определения.)
Знать к экзамену. Связующий объект Salesforce (Salesforce Junction Object) — это пользовательский объект с двумя связями master-detail, и именно это Salesforce имеет в виду, когда говорит «junction object». Логический связующий объект — более широкая идея моделирования: любой объект, который соединяет два других в связи «многие ко многим» и несет свои собственные атрибуты, как бы он ни был построен.
Второе измерение — ширина. Может ли у дочерней записи быть два родителя master-detail? Да. Три? Нет. У каждого пользовательского объекта может быть не больше двух связей master-detail (Considerations for Object Relationships (opens in a new tab)). Два родителя master-detail — это способ построить связующий объект Salesforce для связи «многие ко многим». Бригада (Crew) и грузовик (Truck) встречаются в назначении бригады (Crew Assignment), и, как мы выяснили в главе 2, это не сантехника: у него есть дата, маршрут, может быть, статус. Связующий объект — это место, где связь становится бизнес-понятием. Советы Salesforce по его созданию: дайте ему имя, которое говорит, что это такое, сделайте имя записи Auto Number и переименуйте связанный список каждого главного объекта по другому главному объекту, чтобы на странице бригады было «Грузовики», а на странице грузовика — «Бригады» (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)):
- Внешний вид. Страницы связующего объекта используют цвет и значок основного главного объекта.
- Владелец. Записи связующего объекта наследуют владельца основной главной записи. Вы его никогда не видите, потому что у подчиненной записи нет поля 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». Главный объект, указанный первым, решает, какие записи может показать отчет.
- Для доступа он значит столько же. Я формулирую это так: владение — от основного, доступ — от обоих, и побеждает самый строгий. У связующего объекта, как у любого подчиненного, нет своей таблицы общего доступа. Salesforce проверяет доступ пользователя к обеим главным записям через Sharing Setting в каждом поле master-detail. Если в обоих стоит Read/Write, пользователю нужен Read/Write и к бригаде, и к грузовику, чтобы редактировать назначение бригады (Considerations for Object Relationships (opens in a new tab)).
- Удаляет он столько же. Удалите любую из главных записей, бригаду или грузовик, и ее записи связующего объекта отправятся в корзину. Удалите обе — и они исчезнут навсегда.
Еще несколько правил: у обоих главных объектов могут быть поля roll-up summary по связующему объекту, а формулы и правила проверки связующего объекта могут обращаться к полям обоих. Но связующий объект не может быть главным ни для чего другого, поэтому он не может стоять в середине цепочки, а два главных объекта не могут быть одним и тем же объектом; связь «многие ко многим» объекта с самим собой требует другого дизайна. И если у родителя больше 200 записей связующего объекта, а связующий объект сводится в другого родителя, Salesforce не даст удалить этого родителя, пока вы не уберете достаточно из них.
Итак, какой родитель должен быть основным? Создавайте первым того, кому принадлежит смысл. В назначении бригады работу выполняет бригада, поэтому я бы создал первой бригаду. А потом запишите это, потому что на экране следующему человеку ничего не подскажет.
При всем этом у меня в итоге не так уж много связующих объектов Salesforce. Обычно у объекта один родитель master-detail, и это данные того же вида: клиентские данные под клиентскими, транзакционные под транзакционными (вспомните виды данных из главы 2: клиентские, транзакционные, справочные). Когда другой родитель — данные другого вида, обычно справочный объект, эта связь — lookup. Позиция доставки принадлежит своей доставке: master-detail, обе транзакционные. На продукт, который она везет, она указывает через lookup, потому что продукт — справочные данные со своей жизнью, и никто не хочет, чтобы удаление продукта унесло с собой годы истории доставок. Позиция доставки все равно остается логическим связующим объектом между доставкой и продуктами в ней; просто это не связующий объект Salesforce.
Самосвязи: когда линия возвращается
Заголовок раздела «Самосвязи: когда линия возвращается »Объект может быть связан сам с собой: родительская организация, руководитель, распределительный центр, подчиненный региональному хабу. 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 на Distribution Center под именем Distribution_Center__c никому не помогает. Родительский? Резервный? Для перегрузки? Называйте связь по роли, а не по объекту, на который она указывает.
Иерархическая: собственная связь объекта User
Заголовок раздела «Иерархическая: собственная связь объекта 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: держитесь намного ниже лимита, считая на третий год.)
Вопрос 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 за несколько дней. Безобидная связь «один ко многим» становится проблемой data skew (перекоса данных). Следующий модуль кратко знакомит с перекосом, а Часть 2 разбирает его глубоко.
Не проектируйте линию под функцию
Заголовок раздела «Не проектируйте линию под функцию »Вот привычка, которую я хочу от этого модуля. Не начинайте с «мне нужен roll-up», «мне нужно, чтобы было обязательно», «я хочу унаследованный общий доступ». Это подсказки для реализации. Начинайте с бизнеса: есть ли у дочерней записи своя жизнь, кто ею владеет, может ли она существовать одна, может ли переезжать, что будет, когда уйдет родитель, несет ли связь данные и насколько большой может стать каждая сторона? Затем выберите связь, которая реализует ответы.
За пределами экзамена: что меняет ИИ. ИИ может предложить связи за секунды. Но он не скажет вам, будет ли бизнес когда-нибудь удалять родителя. Быстрое рисование диаграмм не делает разворот неверной связи дешевле, когда от нее зависят миллионы записей и десятки автоматизаций.
Что здесь решает архитектор
Заголовок раздела «Что здесь решает архитектор »- Есть ли у дочерней записи свой жизненный цикл или она действительно принадлежит родителю, и должны ли владение и доступ быть ее собственными или унаследованными.
- Может ли дочерняя запись существовать без родителя, переходить между родителями или пережить удаление родителя.
- Что делает каждый lookup, когда его родителя удаляют: очищает, блокирует или удаляет каскадом.
- Является ли связь «многие ко многим» сантехникой или бизнес-понятием, становится ли логический связующий объект связующим объектом Salesforce, какой родитель основной и что оба родителя значат для доступа.
- Подходит ли модель к форме платформы: три пользовательских подчиненных уровня вглубь, два родителя master-detail вширь, лимиты связей и roll-up.
- Создает ли ожидаемое число и распределение дочерних записей риск перекоса, который должен изменить дизайн.
Связь — это набор обещаний о том, как два элемента данных ведут себя вместе. Давайте их осознанно.
Дополнительно
Заголовок раздела «Дополнительно »- 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.
