Apex class to be used for both with and without sharing
I had the same requirement once. So what we did is we had a class that executed the query to be abstract and we created instances of its successors, that determined the sharing model. This way you still only one query to maintain and a single entry point, but you're free to switch the sharing context on flight.
For your case this will look something like this:
public class CampaignSelector {
private static CampaignDataService dataService {
get {
if (null == dataService) {
// use with sharing by default
dataService = new WithSharing();
}
return dataService;
}
set;
}
public static Map<Id, Campaign> getCampaigns() {
return dataService.getCampaigns();
}
public static void switchSharing(Boolean useSharing) {
// this method is used to switch sharing model
if (useSharing) {
dataService = new WithSharing();
} else {
dataService = new WithoutSharing();
}
}
private abstract class CampaignDataService {
public Map<Id, Campaign> getCampaigns() {
Map<Id, Campaign> campaignsByIds = new Map<Id, Campaign>([
SELECT Id,
Name
FROM Campaign
WHERE Start_Date__c <= TODAY
AND End_Date__c >= TODAY
]);
return campaignsByIds;
}
}
private with sharing class WithSharing extends CampaignDataService {}
private without sharing class WithoutSharing extends CampaignDataService {}
}
The query is still can be executed by calling CampaignSelector. getCampaigns()
. By default it will be executed with sharing
. To switch the sharing context you need to call CampaignSelector.switchSharing(false)
- this will init dataService as an instance of WihtoutSharing
and execute the query in without sharing
context. You can switch back to with sharing
in the same transaction by calling CampaignSelector.switchSharing(true)
.
The problem with static methods is that they block you from using inheritance and other cool OOP stuff
One way would be to use inherited sharing instead of specifying the class using with or without sharing.
public inherited sharing class CampaignSelector {
public static Map<Id, Campaign> getCampaigns() {
Map<Id, Campaign> campaignsByIds = new Map<Id, Campaign>([
SELECT Id,
Name
FROM Campaign
WHERE Start_Date__c <= TODAY
AND End_Date__c >= TODAY
]);
return campaignsByIds;
}
}
Now if you call the class from without sharing class it will run in system mode.
And if you call the class from the with sharing it will execute in with sharing mode.
If you have a same class that needs to run in with sharing and without sharing , create an inner class using without sharing. Call your logic from the inner class to run in system context.