Tuesday, June 21, 2011

Salesforce Empty Key Id - 000000000000000AAA

Working through some data export CSV files I came across the ID "000000000000000AAA". Turns out this is the Empty Key and it can be used for reference relationships where there is no target record (Query for null parent ID).

Foreign keys that are empty typically point to the "Empty Key".
Benji Jasik, Senior Director Product Management

Oddly when that same data is exported via the data loader it appears as the empty string.

Force.com Explorer shows blank values for the following query. Note the use of the EmptyKey in the Where clause.

SELECT AccountId, Subject, WhoId FROM Task where AccountId = '000000000000000AAA'

So the Empty Key ID appears to be used internally to represent an empty reference.

The cross-reference ID field value is either:
* a valid record in your organization, or
* an empty value, which indicates an empty reference
(Reference Field Type)

See Also:

Tuesday, June 14, 2011

Beware the conditional breakpoint that alters execution

A conditional breakpoint caused a good head scratcher today.

The before picture looks reasonable. The conditional breakpoint will stop execution when the parameterName variable equals some value.

The after picture however shows the simple but disastrous mistake.

The conditional breakpoint is capable of assignment (which evaluates to false). So it will happily and transparently (unless you are looking closely) change the parameterName during execution.

Monday, June 13, 2011

Creating a S4S DataSource query for a child-to-parent relationship

Salesforce uses the following relationship between Account and Contact as the example of a SOQL query from the child (Contact) to the parent (Account):

SELECT Contact.FirstName, Contact.Account.Name from Contact

S4S versions greater than 1.5.2011.0906 can replicate this type of query as follows:

SalesforceSession salesforceSession = new SalesforceSession(  
        new LoginDetails("username@example.com", "salesforcePassword"));
ContactDataSource contactDataSource = new ContactDataSource(salesforceSession);

List<Contact> contacts = contactDataSource.QueryEntities<Contact>(
  Contact.Fields.Account(Account.AccountFields.Id, Account.AccountFields.Name)

foreach (Contact contact in contacts)
 Account account = contact.Account;
 string accountName = account.Name;

Friday, June 10, 2011

Frankenstein's monster build configurations

What follows will probably prove in hindsight to have been a bad idea. It was however a working solution to a problem I faced with a code base.

The problem - Two class library projects with a 90%+ common code base

I've been working on a Visual Studio 2010 solution that can produce two separate class libraries. Lets call them A and B. The key differences between the two projects are:

  • The namespaces for A and B have different prefixes.
    A has CompanyX.ProductA.FooBar while B has CompanyX.ProductB.FooBar.
  • A small number of code changes that significantly change the functionality of each output library.
  • The output Assembly Name (DLL name)
    A has CompanyX.ProductA.dll while B has CompanyX.ProductB.dll

The Frankenstien's monster solution

By using Conditional Compilation directives and multiple build configurations that define different Conditional compilation symbols for A and B the first two differences above can be handled.

At the start of each class the namespace and using statements can be toggled based on the defined symbols. This can also be used to make the code changes between the two output libraries.

using System;

#if A
namespace CompanyX.ProjectA
#elif B
namespace CompanyX.ProjectB
namespace CompanyX.ProjectX
 public class ExampleClass
  public ExampleClass()
#if A
#elif B

  private void EnableProjectAFeatureSet()
   throw new NotImplementedException();

  private void EnalbeProjectBFeatureSet()
   throw new NotImplementedException();


The final requirement for differing assembly names can be handled by copying the <AssemblyName>ClassLibrary1<:/AssemblyName> element in the csproj file into the configuration conditional PropertyGroups. See Change assembly name based on configuration (Visual Studio 2005/2008)

Friday, June 3, 2011

Update a Salesforce Custom Setting from Apex

I needed to update a Salesforce Custom Setting in a test method to check various use cases from code. Looking at the Custom Settings Methods documentation doesn't show methods for updating a custom setting instance.

I checked the partner API and the custom setting shows up as a custom object that can be updated using standard Data Manipulation Language (DML) statements.

So if the Custom Setting Definition had the Name as "Config" then it could be updated as follows:

     Config__c configEntry = [Select Id, TextValue__c From Config__c Where Name = 'A Config Name'];
     configEntry.TextValue__c = 'China, Australia, France';
     update configEntry;

Oddly, this works fine when the tests are run via Eclipse but when run from within Salesforce I get an error like:

System.DmlException: Insert failed. First exception on row 0; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Account, original object: Config__c

To resolve this wrap the previous code in a System.runAs(user) call as follows:

     User thisUser = [ select Id from User where Id = :UserInfo.getUserId() ];
     System.runAs ( thisUser ) {
          Config__c configEntry = [Select Id, TextValue__c From Config__c Where Name = 'A Config Name'];
          configEntry.TextValue__c = 'China, Australia, France';
          update configEntry;

See also:

Thursday, June 2, 2011

Sitecore CMS 6.1 with IIS 7.5 - 500.0 - Internal Server Error Calling LoadLibraryEx on ISAPI filter

I recently restored a Sitecore 6.1 website from source control after a hard drive failure and got the following error when trying to start it up from IIS 7.5:

HTTP Error 500.0 - Internal Server Error
Calling LoadLibraryEx on ISAPI filter "C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_filter.dll" failed

The application pool was set to .NET Framework v2.0.50727 but the ISAPI filter mentioned above was configured. Removing the 4.0 aspnet_filter resolved the issue.