Stat Tracker

Tuesday, February 7, 2012

Fun Times with the Force.com Metadata API

So this past weekend I spent a few hours playing around with the Force.com Metadata API. Currently Force.com is running a developer contest to drive folks to do some cool stuff with it. In my everyday Force.com adventures, this is not a feature I get to play with alot. Typically I use the Force.com IDE to do small deploys, or the Force.com Migration Toolkit to run more complex deployments (both of which use this API under the hood).

However, there are some cool things you can do with the API. You can retrieve and update all your objects, apex code, triggers, visualforce, static resources, etc via the API. Meaning you can build tools that make deployments easy. You could even build an application to take snapshots of all your Metadata on a Nightly Basis for backing up and creating versions of objects. There are all sorts of cool stuff you can do!

For example, my simple java application reads a local MySQL database schema information and uploads it to Force.com. Here's a screenshot of the beta or work in progress if you will:

You can also take a look at this demo on YouTube here: http://www.youtube.com/watch?v=OTQcayubCEA&context=C3378280ADOEgsToPDskKXJUZxact1OiFZosSoQ_52

Hopefully I'll get this sucker finished up soon. Once I do I'll post the code to GitHub along with a follow up article about it about the technical details. But if you're reading this, your probably interested in the API and what you can do. And really the sky's the limit!

I'd like to also give a shout out to Cloud Converter from Model Metrics while I'm talking about this. This application has been around a while and is available on the App Exchange, and its great for building data dictionaries for clients. Its Open Source too, so you can take a peak of the code on Google Code. http://developer.force.com/projectpage?id=a0630000003LD3HAAW

Thursday, January 12, 2012

Executing SOSL in Unit Tests

SOSL is a very powerful query method available in the Force.com platform. It allows you to query across all objects for matching text and return results in a List<List<Sobject>> result set. Very cool and very powerful.

As with any Apex code you'll need to write some unit tests to ensure code coverage and that the queries behave as designed before deploying to production. The funny thing is if you just dive right into writing some SOSL queries in Apex and try to test it, you may notice that you get 0 results back for your data. What gives? You know the code is correct. You know the code is working in your sandbox via testing it in a Visualforce page. What the heck?

You're not having a heart attack There is no issue, you just need to know how to setup your unit test properly! Because Salesforce is a multi-tenant architecture, and queries are shared across the system, they don't allow you to run the full SOSL query in your unit test since SOSL can go across all objects in the org. Fear not though, you can still test your code and the query!

You need to use the Test.setFixedSearchResults() method inside your unit test to set a subset of available data to the SOSL query. This method will open up these records so that they can be searched on by the SOSL in your unit test.

For example, lets say I have an Apex class which has a method called "search()" which executes the SOSL like so:


List<List<SObject>> searchList = [FIND :param IN ALL FIELDS RETURNING Account(Id,Name), Contact(Id,Name), Opportunity(Id,Name)];

If I setup my Unit Test as follows, it will query on the data properly and return 3 results back (1 result for each object type):

        Account a = UnitTestFactory.buildTestAccount();
        insert a;
       
        Contact c = UnitTestFactory.buildTestContact();
        insert c;
       
        Opportunity o = UnitTestFactory.buildTestOpportunity();
        insert o;
       
        Id [] fixedSearchResults= new Id[3];
        fixedSearchResults[0] = a.Id;
        fixedSearchResults[1] = c.Id;
        fixedSearchResults[2] = o.Id;
        //Required so SOSL will fire in Unit Tests Properly
        Test.setFixedSearchResults(fixedSearchResults);
       
        CustomSearchController rs = new CustomSearchController();
        rs.searchParam = 'Unit';
       
        test.startTest();
        rs.search();
        test.stopTest();
       
        system.assertEquals(3,rs.results.size());



This Unit Test code will execute and give me the 3 results I am expecting. That's it. You can now test your SOSL queries properly and ensure that they work! Easy enough!

For more information you can checkout the documenation on Force.com: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_testing_SOSL.htm

Sunday, December 11, 2011

Executing Joins in SOQL - Introduction to Relationship Queries in SOQL.

A common requirement people need to execute on the Force.com platform is to perform a JOIN in SOQL. This creates a unique challenge to many new developers as JOIN is not supported the same way it is in SOQL. In fact, JOIN is not even a valid keyword for SOQL syntax! Frustrating for new folks, but fear not. You can get some JOIN functionality in SOQL queries using what is called SOQL Relationship Queries.

First, a little explanation why you can't perform JOIN function in SOQL. Force.com platform is cloud based and uses a Multi-Tenant architecture. A multi-tenant architecture means that multiple clients are all using the same computing resources. You are sharing the computing resources with other clients, and to prevent developers from impacting the performance of other clients there are some important rules or governor limits put in place. These are the Governor Limits so many people hear about when they get introduced to the platform.

Since JOIN queries can get resource intensive, SOQL puts some limits around them. Instead of being able to do a JOIN you can use a Relationship query to pull in related records. If you have a lookup field on a object, you can perform a Relationship Query on that field to execute one SOQL query and retreive the related records.

For example, Accounts and Contacts have a relationship. Contacts have a one to many relationship to accounts. To perform a Relationship Query to retrieve all Contacts for an Account, you can perform the following SOQL method:

List<Account> accounts = [Select Id, Name, (Select Id, FirstName, LastName from Account.Contacts) from Account limit 10];

Notice the Bold section I have highlighted in the query. That is the relationship query. Notice that is uses the Account.Contacts relationship to perform the query. You can use the Force.com IDE to browse the relationships on your parent objects to retrieve the names to use in the queries.

After executing this, you can iterate over the retrieved children records by accessing a List<SObject> on the parent records. For example, this full Apex code will execute the query, print each accounts name in the system log, and print each contact under each account:

List<Account> accounts = [Select Id, Name, (Select Id, FirstName, LastName from Account.Contacts) from Account limit 10];
For(Account account : accounts)
{
      System.debug('Account Name: ' + account.Name);
      For(Contact contact : account.Contacts)
      {
           System.debug('Contact Name is ' + contact.FirstName + ' ' + contact.LastName);
      }
}


And now the output:

14:01:16.041 (41930000)|USER_DEBUG|[4]|DEBUG|Account Name: Acme
14:01:16.042 (42154000)|USER_DEBUG|[7]|DEBUG|Contact Name is Edward Stamos
14:01:16.042 (42272000)|USER_DEBUG|[7]|DEBUG|Contact Name is Howard Jones
14:01:16.042 (42433000)|USER_DEBUG|[7]|DEBUG|Contact Name is Leanne Tomlin
14:01:16.042 (42674000)|USER_DEBUG|[4]|DEBUG|Account Name: salesforce.com
14:01:16.042 (42845000)|USER_DEBUG|[7]|DEBUG|Contact Name is Marc Benioff
14:01:16.043 (43007000)|USER_DEBUG|[4]|DEBUG|Account Name: Global Media
14:01:16.043 (43121000)|USER_DEBUG|[7]|DEBUG|Contact Name is Geoff Minor


Pretty simple, right? You can execute several relationship queries in one query.

If you want more information, checkout the full documentation on the Force.com support website: http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_soql_relationships.htm