Query Tasks, Notes, Attachments by Object Type using SOQL

If you've worked with Salesforce for a while, you've probably come across the gotchas of some of the "standard" sObjects like Task, Event, Note, Attachment and some others. What these all have in common is that rather than having a standard lookup to a single object type, their parent can be any object type. For example, the CampaignMember object can be related to either a Lead or a Contact and has two distinct fields for those links; LeadId and ContactId. If you created a lookup or Master Detail on a custom object, you're asked to select a single object type for the link. In contrast, a Task can also be related to either a Lead or a Contact but has only one field to handle both relationships; WhoId.  

Recently, I needed to run a query in apex where I wanted a list of all the notes related to opportunities. Initially, I tried the following;

//the below does NOT work, LIKE cannot be used with Id fields
SELECT Id, ParentId FROM Note WHERE ParentId like '%006' 

This took me a while to figure out until I delved deeper into the API documentation and found the section Understanding Polymorphic Keys and Relationships . (Up until that point I had incorrectly been calling them dynamic id fields. And I'll probably continue doing so because Polymorphic does not exactly roll off the tongue.) In any case, the below is an example of how I was able to correctly restructure my query.

//returns a list of note records where the parent is a specific type, in this case Opportunity
SELECT Id, Parent.Id, Parent.Type FROM Note WHERE Parent.Type='Opportunity'

The Note object uses ParentId as does Attachment. For other types of objects, like Task and Event, you have the fields WhatId and WhoId. WhoId can relate to Leads and Contacts, while the WhatId is any object that supports activities. Those queries would be structured like;

//returns a list of tasks related to Leads
SELECT Id, Who.Id, Who.Type FROM Task WHERE Who.Type='Lead'

//returns a list of events related to Contacts AND Opportunities
SELECT Id, Who.Id, Who.Type FROM Event WHERE Who.Type='Contact' and What.Type='Opportunity'

One important thing to note (and something I think is unclear in the documentation), is that for the parent you are limited to the fields listed on the Name object. You can't try referencing other standard and custom fields that may be on the parent object. For example;

//This will FAIL even though CreatedDate is a standard field on the opportunity object
SELECT Id, Parent.Id, Parent.Type FROM Note WHERE Parent.Type='Opportunity' AND Parent.CreatedDate = Today

//This will work even though Title isn't even a valid field on the opportunity object
SELECT Id, Parent.Id, Parent.Type FROM Note WHERE Parent.Type='Opportunity' AND Parent.Title != 'Test' 

So, if you did need to filter by values specific to the parent object, you'll need to retructure your query to do a sub-query.  

//restructure your query
SELECT Id, Parent.Id, Parent.Type FROM Note WHERE Parent.Type='Opportunity' AND ParentID in (SELECT Id FROM Opportunity where CreatedDate = Today)

Hopefully, this saves you the 2 hours I spent Googling before breaking down and RTFM. Enjoy.

Cloud based Data Loader

Workbench_logo
On my Mac, I've historically used Simon Fell's LexiLoader as an alternative to the officially supported yet windows-only Salesforce Data Loader. Though, today, I was running a deletion of a rather large set of records and it was running oh sooooo sloooooow. Now that's probably more the fault of Time Warner Cable than anyone else. (Maybe streaming Pandora at the same time didn't help.) If only there was some cloud-based alternative.

Workbench 1Then I remembered about Workbench. Admittedly, I have not used Workbench since its very early release and at that point I think the hosted version was not yet GA. I had even forgotten that I still had it bookmarked. Well, I logged in today and  *Facepalm* . Why have I not been using this all along?

Now I don't do data migrations very often, but I am constantly looking for details on schema and testing queries. Usually I use Eclipse, but navigating Workbench is so much faster. With the pull down menu I can hit a key and get down to my object faster. Workbench loads fields faster than Eclipse as well. I can also use command +f . I can copy and paste an id from a test query or click on the record to open it in Salesforce. These little oft-used hotkey features are noticibly lacking in the Eclipse version of the schema explorer.

Ever need to get your session id? Its right there under the Info menu. 

Want a web based version of Ant? Check the Migration menu.

It even has utilites for anonymous execute and reseting user password. Probably my only complaint is that the debugging interface for anonymous execute isn't as nice as the new console, but really that's just me being nitpicky.

Go check it out for yourself.

Loginhttps://workbench.developerforce.com 
Doc http://wiki.developerforce.com/page/Workbench

Apex RoundingMode

One of the things that always sends me searching through my old code is rounding. I can never remember the syntax and the Apex documentation on Decimal methods on the Salesforce Developer site doesn't provide any examples inthe description (Its somewhat hidden up in the Divide method description if you look for it) . So, I thought I'd put a few examples here as a reminder to myself and to share with everyone else Googling it. 

Decimal numberToRound = 12.345;
Decimal roundedUp = numberToRound.round(roundingMode.UP); //result: 13
Decimal roundedDown = numberToRound.round(roundingMode.DOWN); //result: 12
Decimal scaled = numberToRound.setscale(0); //result: 12 – no rounding specified, just removes decimal places
Decimal scaledUp = numberToRound.setscale(0, roundingMode.UP); //result: 13 – no rounding, just removes decimal places

Look at the documentation on the RoundingModes for more detail on Ceiling, Half_Down, Half_Up, etc. 

 

 

Salesforce Technical Architect Certification; Part 1 Multiple Choice Exam

Yesterday, I passed part two of the three-part Technical Architect Certification for Salesforce.com. (Step one being the self-evaluation; which really doesn't count given that its free and you can take it repeatedly until you pass.) The third and final step will be a four hour session presenting two cases in front of a live review board of technical architects. I've got a few months to prepare for that. So, in the meanwhile, I thought I'd do a bit to help anyone who might be prepping for the exam while its still fresh in my mind.

1. Find out what you don't know

When I went through the self evaluation, I wrote down the terms that I was less familiar with and made a point of researching them afterwards. This was helpful because a lot of the study resources listed below will assume a certain level of knowledge and make reference to terms without necessarily defining them for you. Though I've been an architect and working with Salesforce for several years, I didn't come from an EAI background, so I wasn't as familiar with industry jargon like Enterprise Service Bus (ESB) or Execute, Transform, & Load (ETL) as they referred to integration and middleware. Honestly, I only first heard the acronym EAI last week and I had to go look it up. 

So, if you're stronger on the functional side get familiar with Apex and Visualforce to the level where you can define an Apex abstract class and explain how it might differ from an interface. If you are a developer, make sure you know what can be better done with configuration (Declarative) vs code (Programmatic). In the majority of cases, the former will be preferable to the latter. In that same vein, understand when it is better to use synchronous (web service) vs asynchronous (outbound messaging) callouts. If you don't have a background as a network admin, understand proxies and firewalls and how they might need to be configured to successfully allow salesforce to connect to internal systems in the DMZ (also know what that term means).

Personally, I had little direct experience working with SSO, Large Data Volumes (LDV), REST API, and Heroku. So I put a little more focus on those areas.

Learn the differences between three types of SSO available to Salesforce - delegated authentication, SAML, and Oauth – and when using an appexchange partner like Ping Identity might be appropriate. The comparison matrix here was very helpful to that end.

The most important thing about LDV was knowing the line of demarcation; 2 million records or greater. Next understand what it take to import that volume of data. Also, familiarize yourself with skinny tables and know that in some cases you'll need to de-normalize data or create external id fields (which are indexed) for reporting and performance. Lastly, know when to question if importing the data is even the best approach – does it need to be used for reports or processes in Salesforce (ie workflows, escalations, etc) or can be be accessed on demand via web service callouts or mashups. 

Know the difference between Soap, Rest, and Bulk API's and which situations call for each. Also understand the methods for securing inbound API calls and how an external system might verify that an outbound message or callout came from Salesforce – certificates, 2 way SSL, ip restrictions, trusted ips, remote site settings.

2. Dive in

I was fortunate enough to have access to some proprietary webinars and study materials that I can't make publicly available. However, if you are a Salesforce partner look into getting access to the study group in the Partner Academy. Otherwise, if your Salesforce org has paid for Premier Training there are some self-paced technical architect courses available in the online catalog- https://help.salesforce.com/apex/HTTrainingCatalog.

The following is a list of publically-available material that I reviewed prior to the exam. 

http://certification.salesforce.com/Architects

http://wiki.developerforce.com/page/10_Common_Mistakes_Architects_Make

http://wiki.developerforce.com/page/CRC:PlatformArchitecture

http://wiki.developerforce.com/page/CRC:PlatformGovernance

http://wiki.developerforce.com/page/CRC:OrgArchitecture#Force.com_Org_Architectures

http://wiki.developerforce.com/page/CRC:IntegrationArchitecture

http://wiki.developerforce.com/page/Integrating_with_the_Force.com_Platform

http://wiki.developerforce.com/page/CRC:DataArchitecture

http://wiki.developerforce.com/page/CRC:SSO

http://wiki.developerforce.com/page/Single_Sign-On_for_Desktop_and_Mobile_Applications_using_SAML_and_OAuth

http://wiki.developerforce.com/page/Single_Sign-On_with_Force.com_and_Microsoft_Active_Directory_Federation_Services

http://www.salesforce.com/us/developer/docs/ldv/salesforce_large_data_volumes_bp.pdf

http://wiki.developerforce.com/page/DeveloperCoreResources

http://wiki.developerforce.com/page/Architect_Core_Resources

http://bobbuzzard.blogspot.com/2012/02/certified-salesforce-technical.html

3. Exam Tips

The exam itself is 60 questions and 120 minutes long. So, you can't dwell too long on any one question. If I didn't know some of the people who wrote the questions, I would swear some of them were written by lawyers. (I kid because I love.) In all seriousness, there are some questions where you may need to just pass and move on. If you read a question more than two times and find yourself going for a third, just flag it for review, select a random answer, and move to the next. Don't sacrifice five questions you do know for one question that you might. My strategy was to do a first quick pass through the exam and tackle only the easy low hanging fruit. Then I did a second pass on those I had flagged for review (a little less than half) with a better sense of how much time I could afford each. 

The questions follow your typical standardized testing format, in that, of the answers given, one is egregiously incorrect, another is incorrect because of some slight twist in phrasing and of the choices remaining one is better than the other. There were only a handful of questions where the correct answer jumped out at me. In the cases where it didn't, I identified the incorrect answers first and then evaluated those that remained. From what I recall, about the majority of questions were evenly split between selecting a single answer and two. Only a handful required selecting three. You don't get credit for partially correct answers so do give those a bit more time.

 

Good luck.

 

Added May 16, 2012 – Continued in Salesforce Technical Architect Certification; Part 2 – Review Board

Determining Salesforce Server Pod and if Sandbox via Apex

Recently, I’ve developed some apex classes that were doing callouts to external endpoints like CastIron and Worldpay. I was developing those in a sandbox and from that sandbox called to test endpoints. However, when that code was migrated to production, we obviously wanted those to point to the production endpoints. At first, I used Custom Settings to hold the endpoint value, but I had to change that each time I refreshed. I wanted to store both the test and production endpoints in the custom settings and have the code determine which to use based on if it was being called in a Sandbox or not. Unfortunately, there isn’t a IsSandbox() method in Apex. So, I figured out my own.

I started off using the X-Salesforce-Forwarded-To request header listed in the pagereference documentation because it gave me a consistent value for users accessing Salesforce via the standard interface, Partner Portal, and Sites. However, because you’re using ApexPages.currentPage(), this only works if the code is called from a page controller or extension. In my tests, I tried using URL.getSalesforceBaseUrl(), which can be called from regular classes, but it was inconsistent what was received. For example, I tried calling GetHost() and GetAuthority() from the system log and got cs12.salesforce.com. But with with internal and portal users, a visualforce page returned c.cs12.visual.force.com. Conversely, when using sites I received SiteName.SandboxName.cs12.force.com. So, my approach was determine which method to use based on where the call was coming from in order to get consistent results. 

Parsing out the domains gave me the exact pod that I was on (ex NA1 or CS12) and from that I could determine if that pod was a sandbox or not from whether it started with a “c”. (You can see the full list of available Salesforce pods at http://trust.salesforce.com/trust/status/)

Note: I haven’t tested this with a Site with a Custom Web Address or URLRewriter classes. If you do, please add a comment with your results.

Here’s my code;

 


public String currentPod {
String server;
if (ApexPages.currentPage() != null){ //called from VF page
server = ApexPages.currentPage().getHeaders().get('X-Salesforce-Forwarded-To');
} else { //called via standard class
server = URL.getSalesforceBaseUrl().getHost();
}
if ( server != null && server.length() > 0){
server = server.substring(0 ,server.indexOf('.'));
}
return server ;
}
public Boolean isSandbox {
String pod = currentPod();
if (pod != null && pod.length() > 0 && pod.toUpperCase().startsWith('C')){
return true;
}
return false;
}

Jiujitsu in Buenos Aires, Argentina – Parte Dos

I’ve taken my sweet time in writing the follow up to my first post on researching BJJ in Argentina. In my defense, in the four months since I’ve been back I’ve been travelling like a madman — San Francisco, Boston (twice), Minnesota, and the UK (five times) — and finished deploying a huge Salesforce project. Compounding that, I had a nagging injury before I went to BA that got exasperated afterwards training in Minnesota, so I’ve been off Jiujitsu for the past few months and not happy about it. That made it a bit hard to write anything on the subject. Anyway, I’m feeling better now and getting back on that horse even if the horse is looking at me like ‘Wow! You really let yourself go.’

My original intention wasn’t to visit all the places I researched in my original post. I planned to find one that was close, with a convenient schedule and just go there like I’ve done in Panama and Boston. Since I was working during the days and had some social events in the evenings, I had all the schedules at the ready and ended up going wherever had a class scheduled whenever I found myself with a free moment. Turned out that those all ended up being at different places. I have mixed feelings about this approach; I liked spending more time at a single place. You get a change to know the people there better and they get to do the same. Though, with my limited schedule I glad to visit as many different places as I did. It’s always fresh, new and exciting. So, there’s a trade off.

I was staying in Palemo Soho near Darregueyra and Guatemala, so all the travel times are based on that. Your results may vary.

On a side note, Buenos Aires seems to attract a lot of BJJ players from abroad. I saw a guy with a Roger Gracie shirt in Puerto Madera and another with a Royce Gracie/TeamRoc shirt in a cafe near my apartment in Palermo Soho. In fact, at 2 of the 3 gyms I visited, I ran into fellow New Yorkers.


Sukata Brothers – http://sukata.com.ar 

On my first Saturday, only Sukata and Pitbull had classes and I ended up at Sukata.

On a quiet Saturday morning, Sukata is about a 15 minute ($20 AR) cab and 50 minute walk from Palermo Soho. I attended the 10:30am beginners GI class. The gym is a small storefront with a basic fitness/free weights area in front and a small room for BJJ in the back. No fancy zebra mats here; just a tarp stretched out over the type of thin rubber tiles you see in a weight room. Made a mental note not to get caught in any Judo throws.

The instructor was purple belt whose name I didn’t didn’t catch (Perhaps Luis?). He didn’t speak any English and neither did anyone else in the class of about 10 white and blue belts. No preocupes. Yo hablo spanglish. Plus, arm bar needs no translation. He showed two arm bar escapes that I really liked, a novel side control escape, and a kneebar sub from within half guard that has since become my secret half-guard killer. I do recall thinking whites belts and kneebars are usually a recipe for disaster. Then he busted out a spider guard sweep to a calf slicer. Now I’m thinking, someone here’s going home with a torn ACL and it ain’t gonna be me. We started rolling to a round timer that sounded like a school bell. I kept feeling that panic about being late for something every time it went off.

I was told that weekday mornings are the advanced belts. Unfortunately my schedule didn’t allow for that. Plus, if I’m fighting black belts I want my A game. At 8 am, I’m still working on my Zzz game. Freddy Sukata teaches the Tuesday evening class. $30 peso mat fee. Gym has showers and a locker room.

Sukata1   Sukata2   Sukata3

Gracie Academia Buenos Aires – http://www.graciebuenosaires.com.ar 

Most of the gyms in Buenos Aires have evening classes starting at 8pm (20:00) or even 9pm (21:00). On Monday, I had a late dinner scheduled so, I needed an earlier class. The Gracie Academia at Club Flex had a beginners class at 7pm and advanced at 8:30(ish) so I went there. It was a bit hard to find. There’s a single dark doorway with a staircase leading right up to the gym on the second floor. I must have walked past it about three times. The class is held on the ‘third floor’ which I suspect was once the roof now covered with a thin ceiling supported by scaffolding. This was winter in Buenos Aires and it was about 35 degrees Celsius outside. So, while I appreciated the homage to the open air gyms of Brazil, I secretly wished I could wear socks and not look like a fool.

The instructor, Sebastian, spoke English fluently and was great at making sure I was following everything. In the beginner class, I met a fellow New Yorker from the Upper East Side who was a university student doing a semester abroad. The beginner class had about 20 people but, for the advanced class that dropped to about 7; blues and purples only. That day there happened to be a black belt from Brazil visting BA on business. He was invited to teach the class and taught some interesting sweeps from half guard.

Gracie Academia is about a 15 minutes cab ride from Palermo Soho; $20 peso. No locker rooms or showers that I saw.

Gracie1   Gracie2   Gracie3   Gracie4   Gracie5

Dudu Duarte – http://www.dudubjj.com 

On Wednesday, I ran over to Dudu Duarte during a 1 pm lunch break. Based on the Google map I put together of all the gym locations, I thought it was much further, but it ended up being closer than the previous two. That’s because taxis can go across on Av. Cordoba much quicker than through the local streets. It only cost $10 pesos and was 10 minute cab ride. This was the largest of the gyms I visited with a more modern fitness/free weight in the front and a very sizable mat area in back. It also had really high ceilings and large windows, which made me feel like I was training in a cathedral. For a midday class, there was a rather large group of whites and blues. Included in the mix were a few foreigners; two Australians and another New Yorker, this one from the Upper West Side. Head instructor, Dudu Duarte, taught the class. He also spoke English and mentioned that he had lived in the US for a substantial length of time. He was a really nice guy and had a good approach to breaking down a move into its individual components. He showed us a transition from an abandoned arm bar to a single leg takedown involving a backward roll that at first glance looked complex but ended up being surprisingly simple and effective.

Following class, we rolled. After about 10 fights or so I was exhausted and started getting ready to leave. Of course, this is always when someone asks you to roll. You hesitate for a brief moment while the little angel on your left shoulder says, ‘You’re tired and should call it a day.’ and the devil on your right shoulder say ‘Put on your big girl pants and do it!’  It didn’t help that it was a young woman in her late teens who asked. Even though she was a purple belt, I probably outwieghed her by 70 pounds. Ok, one last easy roll. Mistake. I started off slow and she started off like a starving mongoose attacking a baby cobra. She went knee on belly and, before I could react, spun me into a baseball choke that caught my chin and almost snapped my head clear off my shoulders. Let’s call this one a learning moment … and I got the hell learned outta me.

The gym has a locker room with showers. I don’t recall being charged a mat fee.

Dudu1   Dudu2   Dudu3   Dudu4   Dudu5   Dudu6

For the second half of trip, my wife and I went to Cordoba for the weekend and then San Juan, where she was delivering a presentation at Argentina’s national HIV conference. Cordoba has some BJJ gyms, but I hadn’t been there before and wanted to leave my days for sightseeing. San Juan is a much smaller city with less to see, which left me with some time on my hands. Unfortunately, Google turned up nothing and after a fairly extensive (my wife said obsessive) search around the city, I’m pretty certain there weren’t any BJJ schools there.  If you know of any, please add them to the comments below.

Get your Salesforce project stats using Apex

I mentioned recently that I was working an a rather large project and posted some stats on how many classes, custom objects, etc were involved. Of course, I didn’t count those by hand. I wrote a little script that I run via Execute Anonymous either in Eclipse or in the System Log. Thought I’d share that out.

In the code below I filter out any managed packages because I just wanted stats on stuff that I had done. Feel free to modify the queries to your specific needs.

 


Integer triggerCount = 0;
Integer codeLines = 0;
Integer classCount = 0;
Integer componentCount = 0;
Integer pageCount = 0;
Integer customObjectCount = 0;
for (ApexTrigger t : [Select a.NamespacePrefix, a.Name, a.LengthWithoutComments From ApexTrigger a where NamespacePrefix = null]){
triggerCount++;
codeLines += t.LengthWithoutComments;
}
for (ApexClass a : [Select a.NamespacePrefix, a.Name, a.LengthWithoutComments From ApexClass a where NamespacePrefix = null]){
classCount++;
codeLines += a.LengthWithoutComments;
}
for (ApexComponent c : [Select a.NamespacePrefix, a.Id From ApexComponent a
From ApexComponent a where NamespacePrefix = null]){
componentCount++;
}
for (ApexPage p : [Select a.NamespacePrefix, a.Id From ApexPage a
From ApexPage a where NamespacePrefix = null]){
pageCount++;
}
Map gd = Schema.getGlobalDescribe();
for (Schema.SObjectType s : gd.values()){
Schema.DescribeSObjectResult r =s.getDescribe();
if (r.isCustom()){
customObjectCount++;
}
}
system.debug('---------Project Stats---------')
system.debug( 'triggerCount = ' + triggerCount);
system.debug( 'codeLines = ' + codeLines);
system.debug( 'classCount = ' + classCount);
system.debug( 'componentCount = ' + componentCount);
system.debug( 'pageCount = ' + pageCount);
system.debug( 'customObjectCount = ' + customObjectCount);