Programmatic Sharing using Apex
An essential guide for Salesforce developers on how to share records using Apex.
Summary
- Introduction
- Use Case — the business requirement
- Implementation overview — observations and code snippets
- Solution details
- A ready-to-use Package
- Resources
Introduction
Various features allow users to get access to records in Salesforce:
- Org-Wide Defaults
- Role Hierarchy
- Sharing Rules
- Manual Sharing
- Team Access
- Territory Hierarchy
Although those features cover the most common scenarios, there are a few cases where a more granular control is required. By a real use case, this article illustrates how to share records through Apex.
The solution uses Domain Layer Apex enterprise pattern for educational purposes. To know more about it, please visit the Trailhead module Apex Enterprise Patterns: Domain & Selector Layers .
Use case: training new employees
UniMatrix provides machinery and equipment maintenance services. A trainer is assigned to new technicians during their first week. All training sessions are logged into a Salesforce object called
Training Report
but, for compliance reasons, only Trainer and Employee should automatically get access to the training records they are part of.
Implementation Overview
Observations
The most common Salesforce features do not meet the requirements:
- Org-Wide Defaults — records can be accessible by the owner only, by everyone in read-only mode, by everyone in read and write mode
- Team Access, Role Hierarchy, Territory Hierarchy — Trainer and Employee might not be part of the same team, nor of the same role/territory hierarchy
- Sharing Rules — records cannot be dynamically shared with single users
- Manual Sharing — it requires a manual action by the record owner
Apex programmatic sharing is the optimal way to meet the requirements.
Prerequisites: configuring the object and setting the default access.
Training Report
custom object and fields- Org-Wide Defaults for
Training Report
as Private - Grant Access Using Hierarchies for
Training Report
as false
Apex Sharing Reason
Note: when the owner of a record changes, Salesforce removes all sharing records with
Manual
as RowCause. As we want to keep sharing records with the related employees even though the owner changes, a new sharing reason is needed.
(only available in Classic)
Setup → Objects → Training Report
→ Apex Sharing Reasons → New
Reason Label: Employee
Reason Name: Employee
Apex code snippets
Salesforce keeps track of the record sharing onto tables named
<StandardObjectName>Share
or<CustomObjectName>__Share
for any object with OWD as Private or Public Read Only.
The code below usesTrainingReport__Share
table in order to share Training Report records with the related employee.
When a new Training Report record is created, the Apex code creates a new record into TrainingReport__Share
table with:
- ParentId: current
Training Report
record Id - UserOrGroupId: Employee Id
- RowCause:
Schema.Training_Report__Share.rowCause.Employee__c
(the Apex Sharing Reason created in the previous step) - AccessLevel: Read
When a record is updated and Employee has changed, the Apex code must delete the previous sharing records first:
Solution details
The implementation of the sharing logic uses the enterprise pattern Domain Layer by fflib-apex-common external libraries. This ensures code encapsulation and reuse within the application. In fact, the same logic is going to be implemented in both trigger, to automatically share records, and Apex Sharing Recalculation Batch, to retrofit the existing data.
TrainingReports
Apex class extends fflib_SObjectDomain
class to implement the Domain Apex pattern. The sharing logic is implemented in it.
The following Apex Batch uses TrainingReports
to recalculate the sharing of all existing records.
It is added into Apex Sharing Recalculation related list of the Training Report
object:
The trigger is logic-less and it references to the Domain Layer TrainingReports
A ready-to-use Package
The full solution is already available through a free package. It contains all components: object, fields, permission set, Apex classes, trigger.
Please follow the instructions below to install the package:
- Create a new Playground in your Trailhead orgs
- Install the package:
https://login.salesforce.com/packaging/installPackage.apexp?p0=04t7R000000j9On
Note: you might need to replacelogin.salesforce.com
with your Playground domain name - Create two users (Trainer and Employee) and assign them
Training Report
Permission Set - Login as the Trainer and create a new Training Report record with the other user as Employee
- Verify that the employee has read-only permission to see the record by logging in as the employee user or by extracting data from
Training_Report__Share
table:
If you want to see a simplified approach to share records in Salesforce, please visit Programmatic sharing using Flow .