45

I run a query from an apex class (with sharing), and I get no results I can be sure the user doesn't have permissions (if I know otherwise that the records do exist).

But can I get this information without running a query?

I was thinking of the <object_name>Share objects but I suppose they aren't created for manual and rule based sharing?

Edit: Why I want no query? Here's my real scenario. In a VF page displaying multiple records, I need to show an 'Edit' button against records for which the current user has edit permissions. My question should've been clearer; sincere apologies.

1
  • 1
    What information are you trying to get? A guarantee (or count) of how many records the user has permission to view? Commented Aug 5, 2012 at 23:59

4 Answers 4

75

To find out if a particular user has Edit access to a record, use the UserRecordAccess object. This object is available in API version 24.0 and later. You can use SOQL to query this object to find out if the user has edit access to the record in question.

SELECT RecordId, HasEditAccess 
FROM UserRecordAccess 
WHERE UserId = [single ID] AND RecordId = [single ID]

If you want to check a batch of records you can use

SELECT RecordId 
FROM UserRecordAccess 
WHERE UserId=:UserInfo.getUserId() 
    AND HasReadAccess = true 
    AND RecordId IN :allRecordIds 
LIMIT 200

But make sure that allRecordIds is a LIST of IDs. It doesn't work if allRecordIds is a SET of IDs. I guess that's a bug.

Also, only a maximum amount of 200 recordIds can be checked in one query.

1
  • 1
    "But make sure that allRecordIds is a LIST of IDs. It doesn't work if allRecordIds is a SET of IDs. I guess that's a bug." - That line just ended my hair pulling session. Commented Apr 19, 2013 at 18:19
22

Since API 30.0 you can query an object directly (see Checking for Object Accessibility):

SELECT Id, Name, UserRecordAccess.HasReadAccess, UserRecordAccess.HasTransferAccess, UserRecordAccess.MaxAccessLevel 
  FROM Account

It also works for custom object, but unfortunately it doesn't help myself since it doesn't seem to work for the Task object.

4
  • Check the answers that already have given and since there may be the accepted answer as well. Also it's good to check when the question has raised. BTW, it's good to help the community :)
    – highfive
    Commented Apr 1, 2014 at 9:52
  • 5
    It was meant as an expansion on the (perfectly acceptable) answer given. People looking for this issue might end up here (like I did) and might be interested in the API30 solution as well. Commented Apr 16, 2014 at 12:45
  • I think this is a far better approach (for those object types for which it works) than the selected best answer because you are not limited to 200 objects; we have tested this and know it works with at least 1000 objects (if not more). BTW, I believe this provides a compound answer based on both profile CRUD permissions and sharing rules, but if someone knows better I would be interested to hear.
    – Phil W
    Commented May 15, 2019 at 14:22
  • have you been able to find some way to get it working for Task?
    – zaitsman
    Commented May 28, 2019 at 23:55
14

There is Checking for Object Accessibility that shows how to check for access at the object level.

In Visualforce:

{!$ObjectType.Account.accessible}

In Apex (see Understanding Apex Describe Information):

Schema.DescribeSObjectResult accountDescribe = Account.sObjectType.getDescribe();
System.debug('accessible:' + accountDescribe.accessible);

Beyond that, I suspect if you want to check at a per record level you won't be able to avoid the query.

I'm not very familiar with how the Apex managed sharing works, but from what I've read you would just be querying the related sharing object rather than the object in question.

6
  • 7
    I would agree that there is no way to check record accessibility without a query. Rather than querying the sharing, use a newer object: SELECT RecordId, MaxAccessLevel FROM UserRecordAccess WHERE UserId = [single ID] AND RecordId = [single ID]. You can see more about this object here: salesforce.com/us/developer/docs/api/Content/… Commented Aug 6, 2012 at 14:32
  • @DanielHoechst Can you put that as an answer. Sorry if my question wasn't clear. I wanted to avoid a query only because it'd throw a No rows for assignment exception..
    – LVS
    Commented Aug 6, 2012 at 17:30
  • 1
    @LVS Select into a list (rather than an object) and you won't get the 'no rows' exception.
    – metadaddy
    Commented Aug 6, 2012 at 17:54
  • @metadaddy yes I do that..more detail in the question's edit :)
    – LVS
    Commented Aug 6, 2012 at 18:01
  • This is by far the shortest and clearest answer out there. It does not work for me only because my team wants me to create a service rather than doing it this way but if you have no limitations, this is hands down the easiest path.
    – JPG
    Commented Mar 4, 2020 at 18:24
2

There are multiple programmatic ways of determining access. But a declarative method is to just click the Sharing button on the record and view the users who have access as well as why they have access by clicking the 'Why?' link?

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .