Searching Salesforce Records

You should always consider performance when searching Salesforce. The following code searches for Salesforce Contacts that meet specific criteria. The important points are:

  • Use a AddDataSourceFilter method to modify the query that is sent to Salesforce. Only records that match this filter criterion will be pulled down.
  • Within the foreach loop don't pull the Contact down again as this will send another query to Salesforce. You should avoid calling:

Contact person = contactService.GetByEntityId(contact.Id);

  • When calling QueryEntities only pass the fields that you require are parameters. These will be pulled down and populated into the Contact for use in the foreach loop. The fewer fields that are pulled the faster the query will go. If you don't need to pull the details of the corresponding Account this will also improve query performance.
  • Consider how many Contact records will match the search criteria? If there are, say 2000 or 4000 records, the following approach will be fine as only two partner API calls will be required. If there are 10,000 or more matches we should consider an approach that supports paging.
  • Consider how frequently the data accessed and how often does it change. It may be appropriate to store the query result in an EntityCache for a duration to reduce the number of API calls.

In the following example, you can change the customBooleanFieldName to be "Find_a_person__c" and the AddDataSourceFilter to true.


			[TestMethod]
public void GetByCustomFieldAndMailingCountry()
{
    SalesforceSession salesforceSession = SessionTest.GetActiveSession();
    ContactDataSource contactDataSource = new ContactDataSource(salesforceSession);

    // this could be a customer field. Uses built in field for the test case.
    string customBooleanFieldName = "IsDeleted";
    string filterCountry = "USA";

    // these will be converted into query filters in Salesforce so that only the matching rows will be returned.
    // TODO: Change the false to true when using Find_a_person__c
    contactDataSource.AddDataSourceFilter(customBooleanFieldName, ComparisonOperator.Equals, false); 
    contactDataSource.AddDataSourceFilter(Contact.Fields.MailingCountry, ComparisonOperator.Equals, filterCountry);

	// specify the exact fields you need from the Contact here and they will be returned in the query. You may or may not need to return the field that you were filtering on.
     List<Contact> matchingContacts = contactDataSource.QueryEntities<Contact>(Contact.Fields.Id, Contact.Fields.MailingCountry, Contact.Fields.Account(Account.Fields.Id, Account.Fields.Name, Account.Fields.Website), new SObjectField() { Name = customBooleanFieldName });

	Assert.AreNotEqual(0, matchingContacts.Count);
    foreach (Contact contact in matchingContacts)
    {
    	// confirm that the customFieldName filter was applied
        Assert.IsFalse(contact.InternalFields.GetField<bool>(customBooleanFieldName));
    
		// confirm that the mailing country filter was applied
        Assert.AreEqual(filterCountry, contact.MailingCountry);

        Account accountForContact = contact.Account;
        Assert.IsNotNull(accountForContact);

        string accountName = accountForContact.Name;
        Assert.IsNotNull(accountName);
	}
}

For more information see Filtering Data with S4S