Sunday 19 May 2024

Use Cursors for Expanded SOQL Query Result Support (Beta) - Summer ’24 Release

With Apex cursors, you can break up the processing of a SOQL query result into pieces that can be processed within the bounds of a single transaction. Cursors provide you with the ability to work with large query result sets, while not actually returning the entire result set. You can traverse a query result in parts, with the flexibility to navigate forward and back in the result set. Package developers and advanced developers can use cursors effectively to work with high-volume and high-resource processing jobs. Cursors are an alternative to batch Apex and address some of batch Apex’s limitations. Cursors are also more powerful because they can be used in a chain of queueable Apex jobs.

 

How: Apex cursors are stateless and generate results from the offset that is specified in the Cursor.fetch(integer position, integer count) method. You must track the offsets or positions of the results within your particular processing scenario.

A cursor is created when a SOQL query is executed on a Database.getCursor() or Database.getCursorWithBinds() call. When a Cursor.fetch(integer position, integer count) method is invoked with an offset position and the count of records to fetch, the corresponding rows are returned from the cursor. The maximum number of rows per cursor is 50 million, regardless of the operation being synchronous or asynchronous. To get the number of cursor rows returned from the SOQL query, use Cursor.getNumRecords().

Apex cursors throw these new System exceptions: System.FatalCursorException and System.TransientCursorException. Transactions that fail with System.TransientCursorException can be retried.


  
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public class QueryChunkingQueuable implements Queueable {
    private Database.Cursor locator;
    private integer position;
 
    public QueryChunkingQueuable() {
        locator = Database.getCursor
                  ('SELECT Id FROM Contact WHERE LastActivityDate = LAST_N_DAYS:400');
        position = 0;
    }
 
    public void execute(QueueableContext ctx) {
        List<Contact> scope = locator.fetch(position, 200);
        position += scope.size();
        // do something, like archive or delete the scope list records
        if(position < locator.getNumRecords() ) {
            // process the next chunk
            System.enqueueJob(this);
        }
    }
}
 

  

Apex cursors have the same expiration limits as API Query cursors.

To get Apex cursor limits, use these new methods in the Limits class.

  • Limits.getApexCursorRows() and its upper bound Limits.getLimitApexCursorRows() method

  • Limits.getFetchCallsOnApexCursor() and its upper bound Limits.getLimitFetchCallsOnApexCursor() method

These Apex governor limits have been updated with this feature.

  • Maximum number of rows per cursor: 50 million (both synchronous and asynchronous)

  • Maximum number of fetch calls per transaction: 10 (both synchronous and asynchronous) 

  • Maximum number of cursors per day: 10,000 (both synchronous and asynchronous)

  • Maximum number of rows per day (aggregate limit): 100 million

Dynamically Pass Bind Variables to a SOQL Query

With the new Database.queryWithBinds, Database.getQueryLocatorWithBinds, and Database.countQueryWithBinds methods, the bind variables in the query are resolved from a Map parameter directly with a key rather than from Apex code variables.

Where: This change applies to Lightning Experience and Salesforce Classic in Enterprise, Performance, Unlimited, and Developer editions.

How: In this example, the SOQL query uses a bind variable for an Account name. Its value (Acme Inc.) is passed in to the method using the nameBind Map. The accountName variable isn't (and doesn’t have to be) in scope when the query is executed within the method.


  
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public static List<Account> simpleBindingSoqlQuery(Map<String, Object> bindParams) {
    String queryString =
        'SELECT Id, Name ' +
        'FROM Account ' +
        'WHERE name = :name';
    return Database.queryWithBinds(
        queryString,
        bindParams,
        AccessLevel.USER_MODE
    );
}
 
String accountName = 'Acme Inc.';
Map<String, Object> nameBind = new Map<String, Object>{'name' => accountName};
List<Account> accounts = simpleBindingSoqlQuery(nameBind);
System.debug(accounts);
 

  

Monday 11 January 2021

Input Data

REST API With Javascript

Monday 17 July 2017

Salesforce Rest API Username and Password authentication with community user


  
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
@RestResource(urlMapping='/CommuntyLogin/*')
global class CommuntyLogin {
  
 /**
 * To use this rest service first the user must issue a call to the /login GET method. if the credentials are valid
 * for this org, that call will return a session ID
 **/
  
   @HttpGet
   global static void doGet(){
       //setup return data
       RestContext.response.addHeader('Content-Type', 'application/json');
       RestResponseWrapper thisResponse = new RestResponseWrapper(RestContext.request);
       try{      
           RestRequest req = RestContext.request;
           RestResponse res = RestContext.response;             
           String username = RestContext.request.params.get('username');
           String password = RestContext.request.params.get('password');
           String orgId = RestContext.request.params.get('orgId');
           String loginDomain = RestContext.request.params.get('domain');
 
           loginResult thisResult = validLogin(username,password,orgId,loginDomain);
 
           if(!thisResult.success) {
               throw new applicationException('Invalid Login');
           }
           else {
               thisResponse.responseData = thisResult;
           }                              
       }
       catch(exception e){
           thisResponse.success = false;
           thisResponse.message= e.getMessage();
       }
       //return the data to the client.
       RestContext.response.responseBody = formatResponse(thisResponse); 
   }
  
  
 /**
 * Checks the validity of a provided username and password for a given org ID at the given domain.
 * @param username the username of the person the check. Looks like name@domain.tld
 * @param password the password of the user name to check
 * @param orgId the ID of the organization to validate the credentials against.
 * @param loginDomain the login domain the use, such as 'login' (for a prod/dev instance) or 'test' (for a sandbox instance)
 * @return loginResult a simple object with a boolean success flag and a sessionId if the login is successful.
 **/
 public static loginResult validLogin(string username, string password, Id orgID, string loginDomain){
   loginResult thisResult = new loginResult();
   thisResult.success = false;     
 
   //-------------------------------------------------------
 
   string xmlData = '<?xml version="1.0" encoding="utf-8"?>';    
   xmlData += '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">'
   xmlData += '<soapenv:Header>'
   xmlData += '<urn:LoginScopeHeader>'
   xmlData += '<urn:organizationId>'+orgID+'</urn:organizationId>'
   xmlData += '</urn:LoginScopeHeader>'
   xmlData += '</soapenv:Header>'
   xmlData += '<soapenv:Body>';
   xmlData += '<urn:login>';
   xmlData += '<urn:username>'+username+'</urn:username>';
   xmlData += '<urn:password>'+password+'</urn:password>';
   xmlData += '</urn:login>';
   xmlData += '</soapenv:Body>'
   xmlData += '</soapenv:Envelope>';
 
   //------------------------------------------------------
 
   //create the HTTP request to send to the SOAP API
   HttpRequest request = new HttpRequest();
   request.setEndpoint('https://'+loginDomain+'.salesforce.com/services/Soap/c/39.0');
   request.setMethod('POST');
   request.setHeader('Content-Type', 'text/xml;charset=UTF-8');
   request.setHeader('SOAPAction', '""');
   request.setBody(xmlData);      
   HttpResponse response = new Http().send(request);
   
  final Boolean verified = response.getBodyDocument().getRootElement()
    .getChildElement('Body','http://schemas.xmlsoap.org/soap/envelope/')
    .getChildElement('loginResponse','urn:enterprise.soap.sforce.com') != null;
   
   
       //if the login is valid, now check to see if the orgId this account is for matches the given orgId
       if(verified){
           final string userOrgId = readXmlElement(string.valueOf(response.getBody()), 'organizationId');
           if(userOrgId == orgId){
               thisResult.sessionId = readXmlElement(string.valueOf(response.getBody()), 'sessionId');
               thisResult.success = true;
           }
       }
       return thisResult;
   }
  
   /**
   * Reads a single XML attribute element from an XML document
   * useful for just getting a single element from some XML without having to go through the complexity of
   * full on parsing.
   * @param xmlBody the XML document body to find elementName in
   * @elementName the XML element to read the value from and return.
   * @return the value of the element if it exists, or null if it does not.
   **/
   public static string readXmlElement(string xmlBody, string elementName){       
       Xmlstreamreader reader = new Xmlstreamreader(xmlBody);
       while(reader.hasNext()) {
           if (reader.getEventType() == XmlTag.START_ELEMENT &&  reader.getLocalName() == elementName){
               reader.next();
           return getDecodedString(reader);
           }
           reader.next();
       }    
       return null;
   }
  
 /**
 * Decodes a URL encoded string into a non encoded string
 **/
   public static String getDecodedString(Xmlstreamreader reader){
       return EncodingUtil.urlDecode(reader.getText(), 'UTF-8').trim();
   }
  
   /**   
   * take one of those wrapper objects and format it by wrapping it in a callback if needed, and serializing
   * the result into json. Callbacks allow for cross domain javascript requests. Uses callback param in the url
   * @param responseData an object of whatever data you want to return to the client. Can be anything that can be serialized as JSON
   * @return a blob to be sent to the client. JSON encoded, wrapped in callback if one is provided in the URL.
   **/  
   public static blob formatResponse(object responseData){
       string response = JSON.serialize(responseData);
       return blob.valueOf(response);
   }
  
   /**
   * Result of login call. More data could be populated here, but this is all we need for now
   **/
   public class loginResult{
       public boolean success{get;set;}
       public string sessionId{get;set;}
   }   
  
 /** Custom Exception Class **/
 public class applicationException extends Exception {}
 
   /**
   * simple wrapper response class. Makes it so all replies via this API have the same basic structure
   * including a boolean success flag, a message, any sObjects affected and some debugging params.
   **/
   public class restResponseWrapper{
       public string message;
       public boolean success;   
       public object responseData;
       public object inputData;
       private string requestURI;
 
       public restResponseWrapper(RestRequest reqContext){          
           message = 'run successful';
           success = true;
           requestURI = reqContext.requestURI;
       }
   }
 
   public class ValidateCredentials{
       public String username;
       public String password;
       public String orgId;   
       public String domain;  
   }
  
}
 

  

Wednesday 5 October 2016

Salesforce Chatter Profile Pic Upload

Uploads a user’s photo to their Chatter profile page


To upload chatter profile pic from visual force page no need to write single piece of apex code or lot of visual force components

By using only one visual force component we can achieve this

By using below component we can Uploads a user’s photo to their Chatter profile page.

Visual Force page:

<apex:page >
    <chatter:userPhotoUpload showOriginalPhoto="true"/>
</apex:page>




Note :  

1. To use this component, you must enable Chatter in the org.

2. Users must belong to either Standard User, Portal User, High Volume Portal User, or          Chatter External User profiles. 
3. In apex page component "showHeader" attribute should "true"

Monday 21 December 2015

DUPLICATE RECORD FINDING Using Duplicate and Matching rule

Without trigger , workflow , validation.......

By using Duplicate Management we can restrict end user not to allow duplicate records 

When a user attempts to save a new record, the record is first compared with existing Salesforce records to identify possible duplicates (1). 

The criteria used to compare records and identify the possible duplicates are defined by a matching rule. 

Next, a list of possible duplicates is returned (2).

 What happens when the record being saved is identified as a possible duplicate depends on what’s defined in the duplicate rule (3). 

For example, the duplicate rule could block users from saving the possible duplicate record or allow them to save it anyway. 

Both the Block and Allow options include an alert, which tells users why they can’t save the record and what they need to do. 

The Allow option includes the ability to report on the duplicate records.

When a user attempts to save an edited record, the record is first checked to see if the user has changed the value of a matching rule field.

 If so, the duplicate management process works as described for new records.

 If not, no further action is taken and duplicates are not detected.



Follow below steps to create matching and duplicate rule in salesforce 


STEP 1 :

Go to setup>Administration Setup>Data.com Administration>Duplicate Management>Matching Rules


STEP 2 :

New Rule>SelectObject>

1. Rule Name : TestMatchingRule
2. Matching Rule Criteria : Select fileds which you want to match duplicate records

EX: Name : Exact






STEP 3 :

Go to setup>Administration Setup>Data.com Administration>Duplicate Management>Duplicate Rules

New Rule>Select Object>





In duplicate management give any name in name section


In Action section select action when duplicate rule has to fire


In Matching rule section select the matching rule before created


Condition section is optional


Click on save


Note : After saving duplicate or matching rule Activate the Matching as well as Duplicate rule



STEP 4 : 

Go to object and try to create same record two times





Note : No need of Data.com Licence , it is free for all licence


                                                  That's all folk

Wednesday 15 April 2015

EMAIL TO APEX USING EMAIL SERVICES IN SALESFORCE



By using Email Services in sales force we can invoke an apex class 
 
By sending an email from any email service(gamil,yahoo..etc) to sales force generated email address it will invoke the apex class 

First we have to create an email service in sales force it will generated an email address 
 
Follow the below steps to create an email service and apex class in sales force

Step 1 : Create an apex class to executive when email receive 


 Ex: Below is the sample code to insert a record in contact (Data got from email body and subject)

global class CreateContactFrmEmail implements Messaging.InboundEmailHandler {
 global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail      email,Messaging.InboundEnvelope envelope) {
Messaging.InboundEmailResult resultData = new Messaging.InboundEmailresult();

if((email.subject ! = null && email.plainTextBody != null){

      Contact con = new Contact();
         con.LastName = email.fromName;
         con.Email = email.fromAddress;
         con.Description = email.plainTextBody;
         con.Title = email.subject;
      insert con;

if(email.textAttachments != null){
      for (Messaging.Inboundemail.TextAttachment tAttachment : email.textAttachments) {
             Attachment attachment = new Attachment();
                 attachment.Name = tAttachment.fileName;
                 attachment.Body = Blob.valueOf(tAttachment.body);
                 attachment.ParentId = con.Id;
            insert attachment;
      }
}

  if(email.binaryAttachments != null){
        for (Messaging.Inboundemail.BinaryAttachment bAttachment : email.binaryAttachments) {
              Attachment attachment = new Attachment();
                 attachment.Name = bAttachment.fileName;
                 attachment.Body = bAttachment.body;
                 attachment.ParentId = con.Id;
             insert attachment;
      }
  }
}
      resultData.success = true;
      return resultData;
   }
}

Step 2 : After creation of sales force apex class follow below steps to create email service 


Go to SETUP > BUILD > DEVELOPE > EMAIL SERVICES > NEW EMAIL SERVICES



Fill the form

1. Email Service Name : give any name

2. Apex Class : Select a class which you want to executive when email send

3. Accept Attachments : If you want add attachments then select which type of attachment your adding

4. Accept Email From : List the email addresses and domains from which you want this email service                                       to receive emails.                       
Separate multiple entries by commas. For example: george@mycompany.com, yahoo.com, gmail.com.

Leave this field blank if you want the email service to receive email from any email address or domain.
 
5. Active : Check if you want to use this service

6. Route Error Emails to This Email Address : If error occurs while sending, if you want know error ,     give your email address to receive error

7. Save

Step 3 : After saving the record create new email address under Email Addresses


1. Email address : Don't change any thing

2. Accept Email From : Enter email addresses or domain names that are authorized to send emails to      the service.

Separate multiple entries by commas. Examples: george@mycompany.com, yahoo.com, gmail.com.

NOTE: the addresses entered in this field must be the same as or fully qualify addresses or domains allowed by the service as shown above. For example, if the service's list above only include mycompany.com then the list entered below must be of the form user1@mycompany.com, user2@mycompany.com, etc.

3. Save

After saving it will generate an new email address

Step 4 : Copy the email address generated in step 3 and send an email from your email(gmail,yahoo,....etc)  


Then go to the contact object and check it record is create or not

NOTE : wait for few minutes it will take some time to insert a record in sales force