I have one checkbox on my vf page.when i select this i want that the class to which this VF page is referring should work in with sharing mode and when i deselect it class should work in without sharing mode.Any suggestions how can i implement this functionality?
3 Answers
This is little tricky. So what can you do is keep the logic that needs to be executed in a Util Class. Say
public class Util{
public static void process(){
}
}
Now define two more classes
public with sharing class withSharing(){
public static void runCode(){
Util.process();
}
}
public without sharing class withoutSharing(){
public static void runCode(){
Util.process();
}
}
Now define your controller and from controller depending on the checkbox checked call the corresponding class
public class controller{
public void process(){
if(isChecked == true){
withSharing.runCode();
}
else{
withoutSharing.runCode();
}
}
}
PS: The code is written in Notepad my not actually compile. Please feel free to make changes
UPDATE : Just realized you dont even need the second class(without sharing) just call the util class directly from the controller.
The following solution does not work:
Put the functionality in a separate virtual class (with sharing), and create a subclass which is annotated "without sharing". You would choose which one to instantiate in your controller.
It appears that in a class hierarchy, the platform respects the sharing annotation of the class in which the method is defined, and not necessarily the class that is instantiated. For example:
public virtual with sharing class AccountSelector
{
public virtual List<Account> selectAccounts(String criteria)
{
return [select Name from Account where Name like :criteria+'%'];
}
}
public without sharing class AccountSelectorWithoutSharing extends AccountSelector {}
If I construct an instance of AccountSelectorWithoutSharing, and call selectAccounts(String), the method is executed "with sharing" because of the annotation in the class where the method is defined (AccountSelector).
The fact that the class I have instantiated, AccountSelectorWithoutSharing, is "without sharing" has no influence.
-
Yep, but doesn't need to be extended - just delegation (i.e. calling) to a non-sharing-specified class will continue to enforce the current sharing policy. Commented Feb 27, 2013 at 16:33
-
@jkraybill but extending / implementing a common interface will make the code harder to break ;) And there probably will be huge amounts of code that can be reused, a method in base class sounds like a good choice. Commented Feb 27, 2013 at 16:36
-
Actually, yes, you would not need to extend it twice, only once: the base implementation might be "without sharing", and add a single "with sharing" extension. Main thing I was aiming for was to have only 1 implementation of the logic. Commented Feb 27, 2013 at 16:42
-
@jkraybill take your point - delegation would work, and the logic would be implemented in one place, but if there are multiple methods being called from the controller then I think extension would be neater Commented Feb 27, 2013 at 17:01
-
A fun note that might make this less work for utility methods: if you leave off the with/without sharing declaration then any methods in that class inherit the sharing settings of their caller. Commented Feb 27, 2013 at 18:09
I've found the simplest way to do this is to have the parent class run in with sharing mode and then use a util class to perform certain tasks in system mode.
Example Parent Class
public with sharing class ParentController() {
private List<Contact> queryContacts() {
String query = 'select id from Contact';
if(respectSharing) {
return Database.query(query);
} else {
return SudoHelper.sudoQuery(query);
}
}
}
My Sudo Helper class looks like this
public without sharing class SudoHelper {
/* Query */
public static List<sObject> doQuery(String query) {
return Database.query(query);
}
/* Inserts */
public static Database.SaveResult doInsert(sObject recordToInsert) {
return doInsert(new sObject[] { recordToInsert })[0];
}
public static Database.SaveResult doInsert(sObject recordToInsert, Boolean opt_allOrNone) {
return doInsert(new sObject[] { recordToInsert }, opt_allOrNone)[0];
}
public static List<Database.SaveResult> doInsert(List<sObject> recordsToInsert) {
return doInsert(recordsToInsert, true);
}
public static List<Database.SaveResult> doInsert(List<sObject> recordsToInsert, Boolean opt_allOrNone) {
return Database.insert(recordsToInsert, opt_allOrNone);
}
/* Updates */
public static Database.SaveResult doUpdate(sObject recordToUpdate) {
return doUpdate(new sObject[] { recordToUpdate })[0];
}
public static Database.SaveResult doUpdate(sObject recordToUpdate, Boolean opt_allOrNone) {
return doUpdate(new sObject[] { recordToUpdate }, opt_allOrNone)[0];
}
public static List<Database.SaveResult> doUpdate(List<sObject> recordsToUpdate) {
return doUpdate(recordsToUpdate, true);
}
public static List<Database.SaveResult> doUpdate(List<sObject> recordsToUpdate, Boolean opt_allOrNone) {
return Database.update(recordsToUpdate, opt_allOrNone);
}
}