Programmatic Sharing using Apex

Michele Milidoni
4 min readAug 21, 2022

--

An essential guide for Salesforce developers on how to share records using Apex.

Photo by Markus Winkler on Unsplash

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 Manualas 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

New Apex Sharing Reason

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 uses TrainingReport__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:

  • 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 .

--

--

Michele Milidoni

Salesforce enthusiast. Passionate about software design and development, best practices, rock music, photography.