Продолжим работать с моделью данных нашего приложения Library, заодно разберемся с понятием связей между объектами.
Salesforce предлагает три типа связей, которые различаются между собой по жесткости связи (обязательная, необязательная), зависимости (каскадное удаление), наследованием прав доступа.
Вот что говорит нам документация salesforce на эту тему:
Master-Detail (1:n) - жесткая связь в которой родитель (master) контролирует поведение подчиненных (delail) объектов:
- при удалении родителя, удаляются подчиненные объекты.
- значение поля Owner подчиненного объекта становится недоступным и берется из аналогичного поля родителя.
- подчиненный наследует sharing и security settings от своего родителя
- поле master-detail связи на странице редактирования объекта (layout) является обязательным
- по умолчанию подчиненный не может сменить родителя (жесткая связь). Однако в настойках для custom объекта можно включить настройку Allow reparenting, что позволит в последствии менять родителя.
Связи Master-Detail может быть установлена между custom объектами или custom объектом и standard объектом. Однако standard объект не может быть подчиненным другого объекта (у standard object отсутствует поле типо Master-Detail, только Lookup). Также нельзя создать связь, в которой объекты User и Lead должны быть родителями.
Связь Master-Detail устанавливается со стороны подчиненного объекта (появляется поле в котором можно выбрать родителя для создаваемого подчиненного). На странице редактирования родителя появляется секция (Related List) в которой отображаются все подчиненные объекты для данного.
Many-to-many - связь "многие-ко-многим". Объяснять что это за тип связи не буду - интернет в помощь. Организовать такую связь можно через связующий объект (junction object) который должен иметь 2 master-details связи (для каждого объекта, который он связывает).
Lookup (1:n) - не жесткая связь, в которой оба объекта никак не влияют друг на друга (sharing, securinty, каскадное удаление). Связь является необязательной, поэтому поле типа lookup у подсиненного объекта является необязательным и может содержать null.
А теперь простыми словами, то о чем нужно помнить каждый день.
Связь между объектами устанавливается с помощью создания у подчиненного объекта полей специального типа: master-details или lookup. Основное различие в их использовании, это то что master-datails связь подразумевает что ссылка на родителя будет обязательно и без нее подчиненный объект не сможет существовать, в то время как lookup связь подразумевает то, что подчиненный объект может существовать отдельно без родителя (null) или может менять родителя в любое время.
Еще что надо обязательно запомнить - master-details полей у объекта может быть только 2, а lookup - 20. Важное ограничение, которое надо учитывать при проектировании модели данных.
В прошлом уроке мы создали объекты для нашего приложения Library (Book, Author, Card и User). Сейчас свяжем их между собой согласно схеме.
Книги могут быть написаны одним или несколькими авторами, в то же время автор может иметь одну или несколько книг. Типичная связь "многие-ко-многим". Используем для этого junction объект Book_Author c двумя master-details ссылками на Book и Author. Для значения поля Name установим Auto Number BA-{00000}.
Создаем 2 master-detail custom поля (для Book и Author).
В итоге на странице редактирования объекта вы должны увидеть 2 master-details поля.
Пойдем дальше. Когда читатель берет книгу, в его читательском билете (Card) должна появиться запись об этом. Т.е. должна появиться связи для Book и Card. Это тоже связь "многие-ко-многим" потому что один читательский билет может содержать ссылки на несколько книг, так и книга может находиться в нескольких читательских билетах. Создадим junction объект Card_Item. Однако в отличии от предыдущего junction объекта Book_Author, это объект будет содержать еще дополнительные поля (CreatedDate, Status). Тем самым у нас появится связь с параметрами. Поле CreatedDate позволит хранить дату, когда читатель взял книгу, Status - статус книги для этого читателя (In progress, Returned, Expired, Missing).
Создайте объект с необходимыми полями: Card (master-details), Book (master-details), Status (Picklist). CreatedDate создавать не надо. Это стандартное поле, которое есть у любого объекта и заполняется автоматически при создании записи. Так что остается его только использовать.
Должно получиться следующее
Последний штрих - надо связать читательский балет (Card) с объектом User. Заходим в объект Card и создаем поле lookup на объект User. Почему lookup, а не master-details? Смотрим выше про ограничения использования объекта User в связи master-details. (кому лень, напоминаю,
"Также нельзя создать связь, в которой объекты User и Lead должны быть родителями.")
Все. Модель данных готова. Переходим к стадии создания функционала. Но сперва необходимо наполнить базу данных некоторыми тестовыми данными, чтобы в процессе разработки иметь возможность чем-то пользоваться.
Кстати заметил на практике - создание тестовых данных до начала разработки часто приводит к тому, что забываешь про простейшие проверки на отсутствие необходимых данных и на первом этапе после миграции кода на орг заказчика появляются всякие нехорошие сюрпризы. Так что не забывайте про этот момент.