Thursday, January 20, 2011

String Keys for Apex Maps Are Case-sensitive

I discovered today that String keys for Apex Maps are case-sensitive. Apparently the Strings "johndoe" and "JohnDoe" are not equal when being compared to see if the Map contains a key.

Tuesday, January 18, 2011

Comparing Salesforce Record ID's in Visualforce

Strangely enough, the Visualforce comparison operator does not work when comparing a 15-digit record ID with an 18-digit one. The workaround I concocted is to use a very specific Boolean property in my controller extension to perform the comparison instead, since I really wanted to avoid using any kind of custom ID conversion code that may become invalid in future releases.

public Boolean isCitizenshipCountryUnitedStates {
get {
return stdCtrler.getRecord().get('Citizenship_Country__c') == unitedStatesCountryId;
}
}

The situation I have is that I want to compare the Country of Citizenship specified on an application record (for custom object Application) to see whether the applicant is a U.S. citizen. Country of Citizenship is a Lookup(Country) field, with Country also being a custom object.

Without hardcoding the Id for the United States country, I defined a unitedStatesCountryId property as follows:

 public Id unitedStatesCountryId {
get {
if (unitedStatesCountryId == null) {
List matchingCountries =
[SELECT Id FROM Country__c
WHERE Name = 'United States'];

if (matchingCountries.size() > 0) {
unitedStatesCountryId = matchingCountries.get(0).Id;
}
}

return unitedStatesCountryId;
}

set;
}

When I evaluate the expression {!Application__c.Citizenship_Country__c = unitedStatesCountryId} in my Visualforce page, the expression always returns false. When digging a little deeper, I found that Application__c.Citizenship_Country__c was returning 'a0DT0000006NIDM' while unitedStatesCountryId was returning 'a0DT0000006NIDMMA4'! Visualforce appeared to be comparing the two values as Strings and not as Ids.

Finding no Visualforce-native solution, I had to go the route of creating the isCitizenshipCountryUnitedStates property in my controller extension. Needless to say, this quirk in Salesforce does not make me happy.

Tuesday, January 4, 2011

Deleting Characters (a.k.a. Backspacing) through SSH in PuTTY

I've been annoyed consistently by a quirk with SSH, PuTTY, Unix and sudo where pressing the backspace character prints a ^? on the terminal instead of deleting the previous character. Then, to my amazement today, I stumbled upon a way to delete characters through SSH in PuTTY without messing with any terminal configurations!

To delete characters, all one has to do is press either...
  • Shift+Backspace; or
  • Right Arrow
I assume this works with Terminal in Mac OS X or Linux as well, but I have not yet tried. Gone are the days now when I have to retype a 80+ character command just because of a single, silly typo...

Monday, December 13, 2010

Enforcing Record Name Convention in Salesforce without Apex

One can enforce a record naming convention with a few steps in Salesforce, sans Apex!
  1. Create a formula field called Expected Name with a formula that evaluates to the name you want to see.
  2. Create a validation rule called "Name Expected" with error formula: Name != Expected_Name__c

Enforcing Record Name Uniqueness in Salesforce without Apex

I discovered today that it is possible to enforce record name uniqueness in Salesforce without using any Apex code!

All that is needed is a simple validation rule with the error formula set to the following:
Name = VLOOKUP( $ObjectType.Object.Fields.Name , $ObjectType.Object.Fields.Name , Name ) && Id <> VLOOKUP( $ObjectType.Object.Fields.Id , $ObjectType.Object.Fields.Name , Name )

However, there doesn't seem to be an easy to to perform a case-sensitive comparison in the formula builder. Another thought would be to do the following to enforce name uniqueness:
  1. Create a text field called Unique Name on the object, and add the case-sensitive uniqueness constraint.
  2. Create a workflow field update called Unique Name that just sets Unique_Name__c to Name.
  3. Create a workflow rule called Set Unique Name that's triggered every time a record is created or updated.
  4. Activate the workflow rule.

Last edited on 8/10/2011.

Friday, December 10, 2010

Field Update in Before Trigger Propagates to After Trigger

I confirmed a simple fact in version 20.0 Apex triggers today, that will guide me when writing future trigger code.

If a lookup field is not specified in the DML operation and will not be populated via any other non-trigger means, then a System.debug(Trigger.new); will show that the trigger does not have access to the lookup field value.

However, if the lookup field is populated or updated in the before trigger, then the after trigger will be able to access the new value!

For example, I have a Campaign Feed object that has a Lookup(Campaign) field with an API name of Campaign__c. In my before insert trigger on Campaign_Feed__c, I set Campaign__c to the Id of a newly created Campaign. As a result I am able to then use Campaign__c in my after insert trigger, even though I didn't initially specify a Campaign__c value when inserting the Campaign Feed record.

Wednesday, November 10, 2010

NO-SOFTWARE Tutorial for Salesforce Web Services

First... the gripes against Salesforce. Please feel free to open the actual tutorial if you're not interested in reading about how a billion-dollar company published an API with a lack of documentation that would induce balding in even a teenage developer.

16 man-hours of angst and frustration with Salesforce finally yielded a fruit that I can eat and then sleep on. Who would've thought that Salesforce, in its infinite wisdom, with its "NO SOFTWARE" slogan, would overlook the need for a tutorial that shows how to use the Salesforce WSDL in conjunction with the Web Services API. I certainly didn't expect this lack of documentation and support (which is Premier Support in my case).

As a newbie who has never touched a web service before with an immediate and urgent need to call one from my Salesforce org, I had no idea where to begin. Furthermore, my hopes were dashed when I discovered that the Quick Start chapter in the Web Services API Developer's Guide used Apache Axis or Microsoft Visual Studio as an integral part of the tutorial. What happened to "NO SOFTWARE"? Doesn't the Salesforce platform support both inbound messages and outbound messages for web services?

My chagrin was further exacerbated when I discovered to my extreme disappointment that neither the Salesforce-generated Enterprise WSDL nor the Partner WSDL could be directly imported back into Salesforce using the Generate from WSDL feature for Apex classes. Now, where have I encountered a very similar irony... Oh, yeah! I wrote about it in a previous post, "Salesforce CSV Format for Report Exports Is Not IETF RFC 4180-compliant".

Needless to say, when I thought that my first foray into web services would be made less painful by using Salesforce as the learning platform, I thought very, very wrongly. Well, I shouldn't say that, since the experience could've been worse if I had to write two web services from scratch in Java or something.

Anyway, thanks to an abundance of hope and the following inspirations found on the Internet, I believe I now have a workable tutorial that newbies like myself can use to familiarize themselves with using web services in Salesforce.
JavaRanch

Force.com Discussion Boards
If this tutorial helps even one person, I will consider the 16 hours well spent.