Apex based record sharing in Salesforce

Last update : May 4 2020

There are situations where the business requirement is too complex and standard sharing rules provided by the Salesforce will not work.

Example: On Opportunity, you want to give access to record to some users which are in related list.
One way is to manually share the record which will need the interference of opportunity owner. But everyone will love automated solution.

Apex managed sharing provides developers with the ability to support an application’s particular sharing requirements programmatically via Apex code.

Before you proceed, few points to note about Apex based sharing

  • Share table available only when Organization Wide Default [OWD] sharing is not Public Read Write
  • Apex sharing reasons can be created only for custom objects
  • As Apex Sharing Reason not available for Standard objects only way to create Apex based sharing for Standard objects are using row cause Manual
  • As row cause is Manual for Standard objects, Apex based sharing would be lost once owner is changed [Because its behavior of Manual Sharing]
  • In case of custom object & custom Apex Sharing Reason, sharing would not be lost when owner changed
  • Read more in detail from official documentation

Pre requisite:

The object’s organization-wide default access level must not be set to the most permissive access level. For custom objects, this is Public Read/Write. For more information, see Access Levels. This object is used for creating Apex based sharing.

The user to which the record going to be shared must have the object level permission. If you are trying to share the record with edit permission but user does not have the edit permission on that object, then it will not work.

To access sharing programmatically, you must use the share object associated with the standard or custom object for which you want to share. For example, AccountShare is the sharing object for the Account object, ContactShare is the sharing object for the Contact object, and so on. In addition, all custom object sharing objects are named as follows, where MyCustomObject is the name of the custom object: “MyCustomObject__Share”.

Objects on the detail side of a master-detail relationship do not have an associated sharing object. The detail record’s access is determined by the master’s sharing object and the relationship’s sharing setting.

In this article I want to share the custom object “Test__c” with students. Let’s consider that every “Test” has lookup to the “Student”.

Sharing Table

All objects that have a default sharing setting of the either “Private” or “Public Read Only” also have a related “Share” object that is similar to an access control list (ACL) found in other platforms. All share objects for custom objects are named as MyCustomObject__Share, where MyCustomObject__c is the name of the related custom object. A share object includes records supporting all three types of sharing: Force.com managed sharing, user managed sharing, and Apex managed sharing.

A custom object’s share object allows four pieces of information to be defined:

  • The record being shared.
  • The User or Group with whom the object is being shared.
  • The permission level being granted to the User or Group.
  • The reason why the User or Group has been granted sharing access.
Salesforce Share Table
Salesforce Share Table

This information corresponds with the following fields in a share object:

ParentId
The Id of the record being shared. This field cannot be updated.
UserOrGroupIdThe Id of the User to whom you are granting access. May also be a Public Group Id, Role Id, or Territory Id. This field cannot be updated.
AccessLevelThe level of access that the specified User or Group has been granted.

Valid values for Apex managed sharing are: Edit, Read.

This field must be set to an access level that is higher than the organization’s default access level for the parent object. For more information, see Access Levels.
RowCause (aka Sharing Reasons)The reason why the user or group is being granted access. The reason determines the type of sharing, which in turn controls who can alter the sharing record. This field cannot be updated.

Apex sharing reason

Salesforce Apex Sharing Reason
Salesforce Apex Sharing Reason

Before we can start writing any Apex managed sharing code, we must create an Apex sharing reason. To do that:

  • Click “Setup | Create | Objects”.
  • Select the custom object. (In this case, the “Test” Custom object.)
  • Click New in the Apex Sharing Reasons related list. (If you don’t see this related list, Apex managed sharing has not been configured for your Org – please contact your support representative.)
  • Enter a label for the Apex sharing reason.
  • Enter a name for the Apex sharing reason.
  • Click Save.

Now let’s start with Apex code:

Posted

in

, ,

by


Related Posts

Comments

25 responses to “Apex based record sharing in Salesforce”

  1. Harsha Avatar
    Harsha

    Save error: Entity is not org-accessible

    Hi Jitendra,
    I’m getting the above mentioned error.Can you please help me out with this

    Thaks in advance

    1. JitendraZaa Avatar
      JitendraZaa

      Hi,

      The share records only exist when the object sharing model is set to private

      1. Harsha Avatar
        Harsha

        Yes, Came to know

        Thanks for the reply

      2. Harsha Avatar
        Harsha

        trigger Book on Book__c(after insert, after update)

        {

        // We only execute the trigger after a Book record has been inserted

        // because we need the Id of the Book record to already exist.

        if(trigger.isInsert || trigger.isUpdate){

        // Book_Share is the “Share” table that was created when the

        // Organization Wide Default sharing setting was set to “Private”.

        // Allocate storage for a list of Book__Share records.

        List lstBookShares = new List();

        List lstNewBooks = new List();

        // For each of the Book records being inserted, do the following:

        for(Book__c book : trigger.new){

        lstNewBooks.add(book);

        // Create a new Book__Share record to be inserted in to the Book_Share table.

        Book__Share hiringManagerShare = new Book__Share();

        // Populate the Book__Share record with the ID of the record to be shared.

        hiringManagerShare.ParentId = book.Id;

        // Specify that the Hiring Manager should have edit access for

        // this particular Book record.

        hiringManagerShare.UserOrGroupId = book.CreatedById;

        hiringManagerShare.AccessLevel = ‘Read’;

        // Specify that the reason the Hiring Manager can edit the record is

        // because he’s the Hiring Manager.

        // (Hiring_Manager_Access__c is the Apex Sharing Reason that we defined earlier.)

        hiringManagerShare.RowCause = Schema.Book__Share.RowCause.Test_Sharing;

        // Add the new Share record to the list of new Share records.

        lstBookShares.add(hiringManagerShare);

        }

        // Insert all of the newly created Share records and capture save result

        Database.SaveResult[] jobShareInsertResult = Database.insert(lstBookShares,false);

        //delete lstNewBooks;

        // Error handling code omitted for readability.

        }

        }

        I just copied the code as it is and made the required changes as you guided above

        But still i’m getting this error, that

        Save error: Invalid share row cause:test_sharing

        hiringManagerShare.RowCause = Schema.Book__Share.RowCause.Test_Sharing;

        at this line

        Test_Sharing : is my Sharing Reason name

        Can you guide me through this..!

        1. Ami Raja Avatar
          Ami Raja

          Same issue..Please guide!!!!

        2. Nikhil Avatar
          Nikhil

          __c is missing in rowCause, use Schema.Book__Share.rowCause.Test_Sharing__c

  2. Dinesh Singla Avatar
    Dinesh Singla

    hi,

    In account there is related list of opportunity and i have two record type in opportunity
    These records type assign with a different page layout and in the page layout we have different fields set.

    based on pick list(Interest PickList ) value on account when we create a new opportunity in related list can we redirect to particular record type or we can say particular page layout so that user will see different layout based on different picklist value in account.

    eg in account if he select “A” as interest then while creating opportunity it should go to Page layout A of opportunity

    if he select “B” as interest while creating opportunity it should go to Page layout B of opportunity

    DInesh SIngla

    1. JitendraZaa Avatar
      JitendraZaa

      HI Dinesh,
      You can Override Opportunity Create Button and try to do some checks on click event of that button by getting merge fields of Account.

      I have not tried like this, but you can give a shot on this

  3. jamie smirnoff Avatar
    jamie smirnoff

    Thank you so much for sharing
    this information….

    Whenever the salesforce code
    written by the developers is over-written or deleted…This tool will help you to
    take the backup of your code and attach as an attachment. Follow the below link
    and say byee to all the code-backup problems with the help of this app.

    I would also recommend for salesforce
    users to make use of it..

    https://appexchange.salesforce.com/listingDetail?listingId=a0N3000000B3XxLEAV

  4. Cooler Avatar
    Cooler

    Thanks alot for this article! Its very useful for me. I was trying to find an information about Share objects for custom objects and i got even more here! Thanks again.

  5. Shweta Avatar
    Shweta

    Hi Jitendra,

    I inserted the share records for the an custom object and I want to share the records to the opportunity owner and users above in the role hierarchy so I created one group having opportunity owner as member and check box of grand access using hierarchy is checked and inserted the share record on custom object but it is not working .Upper in role hierarchy user are not able to access the records .Can you please help me out with this.

    1. Jitendra Zaa Avatar

      Hi Sweta, Grant access using hierarchy, for which object you have selected ?

      1. Shweta Avatar
        Shweta

        Hi Jitendra,
        Grant access using hierarchy is checked for the public group used in the share record. on my custom object it is unchecked. Is it necessary to Grant access using hierarchy to be checked on object level then it will work for an public group ?

        1. Shweta Avatar
          Shweta

          Hi Jitendra,

          Please respond when you get a chance.

  6. Guest Avatar
    Guest

    Hi ,
    I was reading out Apex developer’s guide. It says ” Apex managed sharing is maintained across record owner changes.”.I think it is just a contradictory to your note”Important Note: If the owner of record is changed, all the Apex based sharing will be lost. “.Have to try it out.Still thinking…

  7. Anil Salesforce Avatar
    Anil Salesforce

    Hi Jitendra,
    Can you please tell me how the “Student_Access__c” has been retrived from Apex sharing reason, which is used in the step below
    studentRecord.RowCause = Schema.Test_Share.RowCause.Student_Access__c;

    1. konareddy Avatar
      konareddy

      this should be Access_to_Child_Record__C
      Schema.Test_Share.RowCause. Access_to_Child_Record__C

  8. Ipsita Avatar
    Ipsita

    Hi what about detail records in master detail relationship. Can I share the records by any means without sharing parent records? Can manually sharing or Apex sharing solve the purpose?

  9. Pooja Avatar
    Pooja

    Hi, Can you please let me know How to write test class for the code which you have written?

    1. hari vijay Avatar

      Hi

      When I changed the record leadowner sharing also removed, for partner user how to avoid this issue?

      Please let me know which type of RowCause I need to use??

      Thanks

  10. hari vijay Avatar

    Hi
    when I changed the leadowner, lead sharing also removed for partner users. please help me to resolve this issue.
    Please let me know which type of RowCause I need to use??

    Thanks
    Hari

  11. Vamshi Krishna Avatar
    Vamshi Krishna

    Hi Jitendra,

    How can we use the same feature Standard Account? how can we add “Apex Sharing Reasons” for account object, where can I find this option.

    Thanks”

  12. mohan Avatar
    mohan

    Hi Jitendra

    Do you have test class for above sharing trigger?

  13. pranav Avatar
    pranav

    Field RowCause is not editable getting this error from trigger

  14. Craig Avatar
    Craig

    I have an Opportunity Share record with a reason “Record Collection”. Could you please let me know how is this created and how can it be deleted to unshare the record. This share record is between an Opportunity and a Portal User

    Thanks

Leave a Reply to PoojaCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Jitendra Zaa

Subscribe now to keep reading and get access to the full archive.

Continue Reading