<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6603137353225548719</id><updated>2011-11-16T03:34:34.443-08:00</updated><category term='apex'/><category term='config'/><category term='visualforce'/><category term='force.com'/><category term='governor limits'/><category term='record types'/><title type='text'>Salesforce developer</title><subtitle type='html'>Musings of a Salesforce.com and Force.com developer.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-515353605980168845</id><published>2011-08-26T00:44:00.000-07:00</published><updated>2011-09-05T15:22:32.113-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='apex'/><category scheme='http://www.blogger.com/atom/ns#' term='config'/><title type='text'>Protecting code from configuration</title><content type='html'>A few posts back, I talked about how you can use SObject in Apex to treat objects generically. For example rather than getting a field from Opportunity like this:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;String name = myOpp.Some_Custom_Field__c;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can use:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;SObject mySObject = Opportunity.getSObjectType().newSObject();&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;String name = mySObject .get('Some_Custom_Field__c');&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Whilst this opens interesting opportunities for code re-use, it can leave you exposed - what if someone changes the field's API name? In the first example, a user wouldn't be allowed to rename the API name field - salesforce.com would pick up that the field was referenced and prevent the change. In the SObject example however, this isn't the case - the field name is actually a string, so the change could be allowed and the first you'll hear of it is when your app starts breaking...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One way around this is to create a class that refers to the field directly, as in the first example. Seems a bit wasteful, to create a class just for this. We'll also need to write unit tests even though we're not really going to use the code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unless we skip the first part and just create a test class that refers to the field. Something like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;@istest&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;private class ConfigCheck {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;  static testmethod void testField {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;    Opportunity o = new Opportunity();&lt;/span&gt;    &lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;    o.Some_Custom_Field__c = 'Test value';&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;  }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This idea can be extended for all sorts of uses. My last post covered Record Types and raised the question: "What happens if someone renames a record type?". Write another test that checks for the presence of record types your code is expecting to be there. This won't prevent the record type name being changed, but if something goes wrong and you suspect config changes are to blame, you could run the tests in ConfigCheck to check your code's assumptions against the current configuration to see if anything has changed that will cause your code problems.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-515353605980168845?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/515353605980168845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2011/08/protecting-code-from-configuration.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/515353605980168845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/515353605980168845'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2011/08/protecting-code-from-configuration.html' title='Protecting code from configuration'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-2358982077792742354</id><published>2011-08-26T00:26:00.000-07:00</published><updated>2011-08-26T00:39:03.614-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='governor limits'/><category scheme='http://www.blogger.com/atom/ns#' term='apex'/><category scheme='http://www.blogger.com/atom/ns#' term='record types'/><title type='text'>Record Types</title><content type='html'>The Force.com 201 blog &lt;a href="http://force201.wordpress.com/2011/07/22/accessing-record-type-ids-in-apex-code/trackback/"&gt;posted&lt;/a&gt; a great example of how to query the record type table in salesforce in a way that's considerate toward governor limits - think memoization pattern.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's a useful technique and I've used it on every major project I've worked on over the last few years. However, there is another way to get record type information. Take the following example:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" &gt;List&lt;schema.recordtypeinfo&gt; oppRecTypes = Opportunity.SObjectType.getDescribe().getRecordTypeInfos();&lt;/schema.recordtypeinfo&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="line-height: 21px; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="line-height: 21px; "&gt;There are also the following methods:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="line-height: 21px; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;Map&lt;id, recordtypeinfo=""&gt; oppRecTypesByID = Opportunity.SObjectType.getDescribe().getRecordTypeInfosByID();&lt;/id,&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;Map&lt;string, recordtypeinfo=""&gt; oppRecTypesByName = Opportunity.SObjectType.getDescribe().getRecordTypeInfosByName();&lt;/string,&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new'; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="line-height: 21px;"&gt;These all return RecordTypeInfo objects in some way, shape or form, but without using up one of you SOQL queries! These calls are not without penalty however - instead of a SOQL query, you use up a "record type describe", which you have a hundred of in a transaction on EE. So you'll still want to apply the memoization (cache) pattern explained in the Force.com 201 blog.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="line-height: 21px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="line-height: 21px;"&gt;There is one other drawback - RecordTypeInfos do not appear to have any reference to the developer name of a record type. Really, both record type names and developer names can be changed pretty easily which could introduce breakage to your code, however developer names are less likely to change in my opinion, so querying the record type table can be a safer option.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="line-height: 21px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-2358982077792742354?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/2358982077792742354/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2011/08/record-types.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/2358982077792742354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/2358982077792742354'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2011/08/record-types.html' title='Record Types'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-2896576689508543368</id><published>2011-02-09T15:19:00.000-08:00</published><updated>2011-02-09T15:39:26.758-08:00</updated><title type='text'>Describe, and Schema, and SObject and Oh my! Part 2</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;In my previous post, I talked about using Schema, SObject and Describe objects to help make code generic and usable across different types of objects. To recap: when creating/updating/deleting an object, a corresponding object should be created/updated/deleted with a small sub-set of details copied across to the new record. The previous post looked at how to automatically determine the type of object should be created (or edited or deleted – I'm sure you get the idea by now) when a record is inserted.&lt;/p&gt;&lt;p class="MsoNormal"&gt;So we have a way of working out what type of object we need to create. How do we go about copying values between the different types of object? As different objects have different fields, we need a way of knowing which fields to copy for which objects. Once again we turn to our good friend Map:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; "&gt;&lt;span class="Apple-style-span" &gt;&lt;span class="Apple-style-span" style="line-height: 14px; "&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal; font-size: small; "&gt;&lt;span class="Apple-style-span" &gt;&lt;span style="font-size: 10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;Map&amp;lt;String, Map&amp;lt;String, String&amp;gt; &amp;gt; fieldsByObjectName = &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin-bottom: 0.0001pt; line-height: normal; font-size: small; "&gt;&lt;span class="Apple-style-span" &gt;&lt;span style="font-size: 10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:#7F0055"&gt;new&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt; Map&amp;lt;String, Map&amp;lt;String, String&amp;gt;&amp;gt; {&lt;/span&gt;&lt;span style="font-size:10.0pt; font-family:&amp;quot;Courier New&amp;quot;;color:green"&gt;'Account'&lt;/span&gt;&lt;span style="font-size: 10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt; =&gt; &lt;/span&gt;&lt;b&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:#7F0055"&gt;new&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt; Map&lt;string,&gt; {&lt;/span&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;; color:green"&gt;'Name'&lt;/span&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;; color:black"&gt; =&gt; &lt;/span&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;; color:green"&gt;'Name'&lt;/span&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;; color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.0pt; font-family:&amp;quot;Courier New&amp;quot;;color:green"&gt;'OwnerID'&lt;/span&gt;&lt;span style="font-size: 10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt; =&gt; &lt;/span&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:green"&gt;'Custom_Field1__c'&lt;/span&gt;&lt;span style="font-size: 10pt; font-family: 'Courier New'; "&gt;, &lt;/span&gt;&lt;span class="Apple-style-span" style="line-height: 14px; "&gt;&lt;span style="font-size:10.0pt; line-height:115%;font-family:&amp;quot;Courier New&amp;quot;;color:green"&gt;'ID'&lt;/span&gt;&lt;span style="font-size:10.0pt;line-height:115%;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt; =&gt; &lt;/span&gt;&lt;span style="font-size:10.0pt;line-height:115%;font-family:&amp;quot;Courier New&amp;quot;; color:green"&gt;'Account__c'&lt;/span&gt;&lt;span style="font-size:10.0pt;line-height:115%; font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;}};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;What an eyesore – but not as difficult as it may first look. We have a map (let's call it the outer map) where the values themselves are a map (inner maps). The inner maps hold the details of what fields should be copied for an object; we can get these values from the outer map by get()ing the values associated with the object name of the object being inserted.&lt;/p&gt;&lt;p class="MsoNormal"&gt;Let's look how that applies to the example above. fieldsByObjectName.get('Account') returns a map of strings, keyed by strings. These hold the fields that should be copied from the account to the custom object, and what the corresponding field is on the custom object.&lt;/p&gt;&lt;p class="MsoNormal"&gt;Usefully, the generic SObject has put() and get() methods to retrieve and set field values. Get() takes a field on an SObject for which the value should be returned; put() takes a field and a value and sets the field to the value given. As we have these values in a collection, we can simply loop over the collection and copy the fields with these methods:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"  &gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin-bottom:0cm;margin-bottom:.0001pt;line-height: normal;mso-layout-grid-align:none;text-autospace:none"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span style="font-size: 10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;Map&amp;lt;String, String&amp;gt; fieldsToCopy = fieldsByObjectName.get(objectName);&lt;span style="mso-tab-count: 4"&gt;                    &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;span class="Apple-style-span"  &gt;  &lt;p class="MsoNormal" style="margin-bottom:0cm;margin-bottom:.0001pt;line-height: normal;mso-layout-grid-align:none;text-autospace:none"&gt;&lt;b&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:#7F0055"&gt;for&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;(String field : fieldsToCopy.keySet()) {&lt;/span&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom:0cm;margin-bottom:.0001pt;text-indent: 36.0pt;line-height:normal;mso-layout-grid-align:none;text-autospace:none"&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;newObject.put(fieldsToCopy.get(field), ourNewObject.get(field));&lt;/span&gt;&lt;span style="font-size:10.0pt;font-family: &amp;quot;Courier New&amp;quot;"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size:10.0pt;line-height:115%;font-family: &amp;quot;Courier New&amp;quot;;color:black"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Some relatively straightforward DML plumbing at the end of the code handles inserts/updates of the necessary objects.&lt;/p&gt;&lt;p class="MsoNormal"&gt;So, the end result is code that will extend quite nicely if I need to do this for other objects. I just need to create a new custom object with fields to hold values; update the code to map the object to the new custom object, along with what fields should be copied; and finally add a simple trigger that calls the relevant method depending on the type of operation performed.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;So are there any downsides?&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Though the code is extendable, I don’t think it’s as easy to read as doing it the long-handed way. There’s a whole discussion to be had about the pros and cons of this, however, I think that it would take someone looking at the code longer to understand this approach than simply having triggers and code for each object.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;My solution doesn’t do anything to convert between different field types – not really an issue for what I was doing, but if you had a source field of one type and a destination field of another type, some sort of conversion may need to take place. At this time, I'm not sure how I'd approach that.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Where updates occur to objects, I had to hard code queries to retrieve the objects with the sub-set of details so that I could update them (or delete them in the deletion case). This is because I had a set of IDs to use in the query, and had I constructed a query string, there was no easy way to include them in the string. This did feel as if I was breaking the principle that led me down the route in the first place. However, it was “just” a proof of concept and, more importantly, a learning opportunity for me and all things considered, I’m pretty happy with the end result.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-2896576689508543368?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/2896576689508543368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2011/02/describe-and-schema-and-sobject-and-oh.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/2896576689508543368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/2896576689508543368'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2011/02/describe-and-schema-and-sobject-and-oh.html' title='Describe, and Schema, and SObject and Oh my! Part 2'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-7831287091543823151</id><published>2011-02-07T15:16:00.000-08:00</published><updated>2011-02-09T15:41:32.483-08:00</updated><title type='text'>Describe, and Schema, and SObject and Oh my!</title><content type='html'>&lt;p class="MsoNormal"&gt;I've seen a few of the cool things that can be done with "describe" information in Apex, and using the Schema and SObjects to handle different objects in a generic fashion, but I only recently had a good opportunity to get my hands on it. It was an interesting exercise, so I thought I'd write up my experiences.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;First: the requirement. We wanted to give limited visibility of accounts in some circumstances, and full visibility in others. If a user owns an account or is a member of the account team, he (or she) should see all details; otherwise they should only see the account name and owner.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Sharing rules, field level security, record types and page layouts were options that wouldn't deliver what we wanted: sharing rules would control whether a user could see a record or not, not what they could see on the object.&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;Field level security would limit access to fields for all accounts, not on an account-by-account basis. Record types and page layouts would not work for a reason that would take some time to explain, but seasoned admins/developers can work out for themselves.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;So we had to customise – we could have overridden view and edit actions with Visualforce, and some of the upcoming Spring '11 features would take some of the pain away when it comes to controlling what fields display on the page in a config-friendly, no-code-changes-needed way. Personally though, I don't like overriding standard functionality with something that looks, feels and operates in such a similar way.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;Instead, we decided to create another object that held only the details that anyone can see (account name and owner) that would be created, updated or deleted when something of interest happened on the account object. The oragnisation wide default for accounts could be set to private, granting access to owners and people above them in the hierarchy (and people added to the account team), whereas the new custom object would be public for all. Search for an account and you’ll either see the new custom object if an account exists, or the custom object and the account (if you are able to see the account).&lt;/p&gt;  &lt;p class="MsoNormal"&gt;So why bother with the Describe and Schema objects? We also needed to do the same thing for contacts, and possibly other objects in the future. We could have written specific code for each object but it seemed a shame when the operations were the same over the different objects:&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;If an account/contact is inserted, create a corresponding custom object record with the necessary details.&lt;/li&gt;&lt;li&gt;If an account/contact is updated, update the corresponding record.&lt;/li&gt;&lt;li&gt;If an account/contact is deleted, delete the corresponding&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;record.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;      &lt;p class="MsoNormal"&gt;So I created three methods, one for each of those scenarios. Each method took a list (or Map) of SObjects and created/edited/deleted a corresponding record using Schema, SObject and Describe. This was then mixed in with some variables to hold information about what fields need copying for each type of object, as well as what custom objects should be created for an object. The later was accomplished with a Map of Schema.SObjectType to String i.e.:&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom:0cm;margin-bottom:.0001pt;line-height: normal;mso-layout-grid-align:none;text-autospace:none"&gt;&lt;span style="font-size: 10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;&lt;string, sobjecttype=""&gt;Map&amp;lt;String, Schema.SObjectType&amp;gt; objectMap = &lt;/string,&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size:10.0pt;line-height:115%;font-family:&amp;quot;Courier New&amp;quot;;color:#7F0055"&gt;new&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size:10.0pt;line-height:115%;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt; &lt;string, sobjecttype=""&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;; mso-fareast-font-family:Calibri;mso-fareast-theme-font:minor-latin;color:black; mso-ansi-language:EN-GB;mso-fareast-language:EN-US;mso-bidi-language:AR-SA"&gt;Map&amp;lt;String, Schema.SObjectType&amp;gt;&lt;/span&gt;{&lt;/string,&gt;&lt;/span&gt;&lt;span style="font-size:10.0pt; line-height:115%;font-family:&amp;quot;Courier New&amp;quot;;color:green"&gt;'Account'&lt;/span&gt;&lt;span style="font-size:10.0pt;line-height:115%;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt; =&gt; &lt;/span&gt;&lt;b&gt;&lt;span style="font-size:10.0pt;line-height:115%;font-family: &amp;quot;Courier New&amp;quot;;color:#7F0055"&gt;new&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size:10.0pt; line-height:115%;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt; Custom_Object__c().getSObjectType()};&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;My method that creates objects when an account or contact is inserted takes a list of SObjects; how do we work out what object we need to create? Like this:&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;String objectInsertedType = insertedSObject.getSObjectType().getDescribe().&lt;/span&gt;&lt;span class="Apple-style-span"&gt;getName();&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="Apple-style-span"&gt;&lt;/span&gt;&lt;span style="font-size: 10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;Schema.SObjectType objectTypeToCreate = objectMap.get(&lt;/span&gt;&lt;span class="Apple-style-span"&gt;objectInsertedType&lt;/span&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;);&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal" style="margin-bottom:0cm;margin-bottom:.0001pt;line-height: normal;mso-layout-grid-align:none;text-autospace:none"&gt;&lt;span style="font-size: 10.0pt;font-family:&amp;quot;Courier New&amp;quot;;color:black"&gt;&lt;span style="mso-tab-count:4"&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;&lt;span style="font-size:10.0pt;line-height:115%;font-family: &amp;quot;Courier New&amp;quot;;color:black"&gt;SObject newObject = objectTypeToCreate.newSObject();&lt;/span&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;In the first line, we get the name of the object being inserted (account or contact in our scenario) as a string, then use that string to get what type of record we should be creating from the Map we created earlier. Finally, we use the newSObject() method on the SObjectType object to give us an instance of the object we need to create. So far we've only done accounts – if an account is inserted, the newObject variable will be a Custom_Object__c&lt;span style="mso-spacerun:yes"&gt;  &lt;/span&gt;object. But we can extend this for other objects by adding to the objectMap; for example if contacts should have records created of an object called Another_Custom_Object__c, we could put that into the map. Then, if a contact is inserted, newObject will be a Another_Custom_Object__c. And that way, we at least don't have duplicated logic that's essentially doing the same thing with a few small changes.&lt;/p&gt;  &lt;p class="MsoNormal"&gt;So that was how step 1 of making this functionality as generic as possible for use with different objects – implemented a way of determining what object should be created depending on what was inserted. As this has already turned into a fairly lengthy post, I’ll discuss how to copy values between the fields on the two objects in my next post. I’ll also discuss some of the pros and cons of this approach.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-7831287091543823151?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/7831287091543823151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2011/02/ive-seen-few-of-cool-things-that-can-be.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/7831287091543823151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/7831287091543823151'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2011/02/ive-seen-few-of-cool-things-that-can-be.html' title='Describe, and Schema, and SObject and Oh my!'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-4796028953635806914</id><published>2010-09-08T03:46:00.000-07:00</published><updated>2010-09-08T05:58:14.456-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='force.com'/><category scheme='http://www.blogger.com/atom/ns#' term='apex'/><title type='text'>Static boolean variables as "Locks"</title><content type='html'>Over 6 months and no new posts, tsk tsk! I'm trying to get back into the habit (though did I ever really have it?) with some - hopefully! - short, sharp posts.&lt;br /&gt;&lt;br /&gt;So - do you use static boolean variables to control trigger flow and behaviour? I do - a lot. A common use is when Object A has a trigger that does something to Object B, and Object B has a trigger that does something to Object A. To avoid recursion when you update one, you can use a static boolean to cause the second trigger to return immediately rather than execute it, which causes the first trigger to fire again yadda yadda yadda. Similarly, if you have workflow that will cause an update to a record and you don't want triggers firing a second time, a static boolean does the job.&lt;br /&gt;&lt;br /&gt;The advice in this post is simple: I think it's a good idea to keep these variables in a separate class. This is due to recent experiences, when I needed such a static variable in a class. I took the easy route and put it in the same class, and this was OK initially. Later, I needed to access that variable from somewhere else, which was possible, however, in that same class I also had a static code block in the same class that queried the database and set some variables.&lt;br /&gt;&lt;br /&gt;Now, just by looking at this variable from outside the class, I was causing queries against the database to happen. I had enough headroom for this at the time but in the long term, it's a potential headache waiting to happen.&lt;br /&gt;&lt;br /&gt;The solution is to have a separate class that holds such variables and refer to them from other points of code that need to look at them, rather than have the booleans amongst classes scattered here, there and every where. It'll be easier to manage and is better in the long run.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-4796028953635806914?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/4796028953635806914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2010/09/static-boolean-variables-as-locks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/4796028953635806914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/4796028953635806914'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2010/09/static-boolean-variables-as-locks.html' title='Static boolean variables as &quot;Locks&quot;'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-1845463522995848351</id><published>2010-02-05T09:08:00.000-08:00</published><updated>2010-02-05T09:19:16.153-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='governor limits'/><category scheme='http://www.blogger.com/atom/ns#' term='force.com'/><category scheme='http://www.blogger.com/atom/ns#' term='apex'/><category scheme='http://www.blogger.com/atom/ns#' term='visualforce'/><title type='text'>Too many script statements?</title><content type='html'>With any luck, this weekend should be the go-live for the project I mentioned in my last post. It's been an interesting project, and, at the risk of sounding schmaltzy, there have been a lot of lessons learnt (and most of them painfully).&lt;br /&gt;&lt;br /&gt;I'll be posting about some of the lessons learned in upcoming posts, but I just wanted to take a moment to an &lt;a href="https://sites.secure.force.com/ideaexchange/ideaView?c=09a30000000D9xt&amp;amp;id=087300000007DQRAA2"&gt;idea I have up on Ideas&lt;/a&gt;. The governor limit on script statements has been my main obstacle this time around; I know that it's part of multi-tenancy and working with Salesforce. I don't actually mind operating within those limits, but I do like being able to handle meeting those limits in a sensible way.&lt;br /&gt;&lt;br /&gt;The reason that "Too many script statements" is special is that, when hitting other governor limits, you can catch them as exceptions and handle them appropriately - usually displaying an error to the user. However, once you've used too many script statements, you don't have any script statements left to tidy up or present something meaningful to the user.&lt;br /&gt;&lt;br /&gt;There are ways around this - not hitting the limit in the first place (not a practical solution this time round), periodically checking how many statements have been used and throwing an exception at a threshold (fiddly, unpredictable and uses script statements!). But a neater solution would be nice.&lt;br /&gt;&lt;br /&gt;Feel my pain? Don't mope, &lt;a href="https://sites.secure.force.com/ideaexchange/ideaView?c=09a30000000D9xt&amp;amp;id=087300000007DQRAA2"&gt;promote&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-1845463522995848351?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/1845463522995848351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2010/02/too-many-script-statements.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/1845463522995848351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/1845463522995848351'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2010/02/too-many-script-statements.html' title='Too many script statements?'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-7534802822339797594</id><published>2009-11-25T07:27:00.000-08:00</published><updated>2009-11-25T07:57:20.277-08:00</updated><title type='text'>Lookup filter - a cautionary tale</title><content type='html'>Apologies for the lack of posts of late - I've been busy coding for a project, and I'm off on holiday for the end of the year, so the pressure is on!&lt;br /&gt;&lt;br /&gt;I'm at the "fun" stage of the project where I'm writing my test methods and encountered an unusual problem. We have a custom object, I created some instances of this object and saved them to the database. This object also has an (optional) lookup field to another instance of the same object, so I then tried to update some of the inserted objects with references to other inserted objects.&lt;br /&gt;&lt;br /&gt;When running the test code, I was getting an error message along the lines of:&lt;br /&gt;&lt;br /&gt;"FIELD_INTEGRITY_EXCEPTION: Value does not exist or does not match filter criteria. Click icon to select a value."&lt;br /&gt;&lt;br /&gt;Turns out the error was related to a feature in beta, "&lt;a href="http://ideas.salesforce.com/article/show/25164/Filter_on_Lookup"&gt;Filter on Lookup&lt;/a&gt;". To be fair, it wasn't the feature's fault: it was being used incorrectly which was causing the problem, and it wasn't an obvious culprit.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://ideas.salesforce.com/article/show/25164/Filter_on_Lookup"&gt;Idea&lt;/a&gt; requests a way to restrict what records are shown when a look up button is pressed. For example, let's say you use the Account object for two types of account, customer and partner. On the Opportunity object, you may want fields related to the customer you are trying to sell to, and the partner you are partnering with on the deal. You want to stop users putting partners in the customer field and vice versa. Sharing rules are no good as you want users to be able to see both type of account. With filter on lookup, users click the lookup button on the customer field, and only see customer accounts, and partner accounts when clicking the partner lookup.&lt;br /&gt;&lt;br /&gt;It also stops you manually entering names of accounts that do not meet the filter criteria. It's actually slightly cleverer than this, because whatever way you try to save a record, it will check the related object matches the filter; if it doesn't an error is reported...&lt;br /&gt;&lt;br /&gt;Which is where the problem I encountered comes into play: the field I was trying to set in my test method had such a filter set on it, and the filter had been set up incorrectly - it was looking at the wrong field, which hadn't been set by my test code. The result: error! Hope someone finds this useful...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-7534802822339797594?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/7534802822339797594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2009/11/lookup-filter-cautionary-tale.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/7534802822339797594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/7534802822339797594'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2009/11/lookup-filter-cautionary-tale.html' title='Lookup filter - a cautionary tale'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-950648910584631575</id><published>2009-08-05T01:52:00.000-07:00</published><updated>2009-08-05T02:01:06.458-07:00</updated><title type='text'>Coming in Winter '10...</title><content type='html'>The &lt;a href="http://blogs.salesforce.com/blogs/"&gt;Official Salesforce Blog &lt;/a&gt;has just posted &lt;a href="http://ideas.salesforce.com/popular/coming_in_winter_10"&gt;a link&lt;/a&gt; to the Ideas that have been chosen for inclusion in the Winter '10 release. The two features that leap out straight away are batch Apex and scheduled Apex - seriously powerful stuff. Take a look to see if there's something that will make your life easier...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-950648910584631575?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/950648910584631575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2009/08/coming-in-winter-10.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/950648910584631575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/950648910584631575'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2009/08/coming-in-winter-10.html' title='Coming in Winter &apos;10...'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-6832297724228142615</id><published>2009-07-27T01:27:00.000-07:00</published><updated>2009-07-27T01:35:36.138-07:00</updated><title type='text'>Force.com Debug Log Parser</title><content type='html'>Have you seen Kyle Peterson's &lt;a href="http://codebit.wordpress.com/2009/06/04/force-com-debug-log-parser/"&gt;Force.com debug log parser&lt;/a&gt;? If you spend time working out how your workflows and Apex code are interacting with each other, you should at least watch the video.&lt;br /&gt;&lt;br /&gt;A lot can take place in the background when you interact with Salesforce and tracking what's happening can mean trawling through megabytes of log file. Kyle's log parser gives you a near instant overview of what's happening behind the scenes of your application. Great work.&lt;br /&gt;&lt;br /&gt;How do you deal with the complexities of multiple Salesforce features interfering with one another? If you have anything interesting to share, let us know in the comments...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-6832297724228142615?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/6832297724228142615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2009/07/forcecom-debug-log-parser.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/6832297724228142615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/6832297724228142615'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2009/07/forcecom-debug-log-parser.html' title='Force.com Debug Log Parser'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-3843127459012520450</id><published>2009-07-24T03:25:00.000-07:00</published><updated>2009-07-24T04:49:57.288-07:00</updated><title type='text'>Batch Apex processing</title><content type='html'>One of the more interesting feature additions to Salesforce and Force.com had a somewhat muted announcement, slipping out on a &lt;a href="http://www.typepad.com/services/trackback/6a00d8341cded353ef01156f8fe3b2970c"&gt;blog post&lt;/a&gt; on the Force.com blog. The comments on the post show there's a fair amount of interest in such functionality.&lt;br /&gt;&lt;br /&gt;And rightly so, as batch Apex processing fills a gap that has required kludges to work around until now.&lt;br /&gt;&lt;br /&gt;For those that haven't heard of this feature, it allows Apex code to be run asynchronously over large datasets (it still needs to be clarified if it is 5 million or 50 million). You could look over millions of records and produce statistics for reporting purposes; you could look over records and perform actions on a set of them that are not possible through current functionality. It should mean that any time you want Apex logic to apply to massive (by Salesforce standards) amounts of records, governor limits needn't stand in your way.&lt;br /&gt;&lt;br /&gt;However, there are currently two limitations: firstly, though the blog post calls batch Apex one of the "new goodies in Summer '09", it was only released on a limited developer preview - if you've not signed up by now, you'll have to wait for the preview to be extended or for the general release. (Of course, if you're a large enough Salesforce customer, you could always try pestering your account exec...)&lt;br /&gt;&lt;br /&gt;The second limitation is that batch jobs can't be scheduled to run, and it's not planned to do so in the initial release. It's on the roadmap apparently, but that's all that's been said so far. If the announcement of this initial functionality is anything to go by, we may not know until it's almost upon us. The comments on the afore-linked blog post contain ideas as to how to work around this for now.&lt;br /&gt;&lt;br /&gt;Should you use this new functionality once it's released, even if the lack of scheduling is a pain? My answer would be yes if you can make do with a workaround for now, especially if you're creating new batch jobs for your org. It may be a hassle in the short to medium term but at some point down the line you'll (hopefully) be able to add a schedule relatively easily.&lt;br /&gt;&lt;br /&gt;For those currently using workarounds that they'd like to get rid of with batch Apex (e.g. using a batch job on one of your own servers to run Data Loader to extract records and upload them back in just to cause something server side to kick off), consider the workarounds available, and if they can work for you, dip your toe in the water - port some of what you currently do to batch Apex and see how it works for you.&lt;br /&gt;&lt;br /&gt;And don't forget to leave a message with how you get on - especially those of you taking part in the developer preview.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-3843127459012520450?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/3843127459012520450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2009/07/batch-apex-processing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/3843127459012520450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/3843127459012520450'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2009/07/batch-apex-processing.html' title='Batch Apex processing'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6603137353225548719.post-1298670923555007322</id><published>2009-07-13T13:21:00.000-07:00</published><updated>2009-07-13T13:32:44.162-07:00</updated><title type='text'>Welcome, what's this all about, all that jazz...</title><content type='html'>Hello!&lt;br /&gt;&lt;br /&gt;In the unlikely event you've stumbled on this page, you may be wondering what it's about. I'll explain.&lt;br /&gt;&lt;br /&gt;My day job is as a Salesforce consultant - I've been working with Salesforce and the underlying Force.com platform for little over a year now. Sometimes I stumble on things I think others may find useful, encounter problems others may (have) struggle(d) with, or just want to whinge a little.&lt;br /&gt;&lt;br /&gt;Rather than bore friends and family, I thought I'd blog my musings so that it may reach a more suitable audience who may actually find my posts useful/interesting/ridiculous, delete as appropriate really.&lt;br /&gt;&lt;br /&gt;Obviously it's early days so there's nothing here yet, but I've had a few things I've wanted to share for a little while so hopefully there'll be some content worth reading RSN.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6603137353225548719-1298670923555007322?l=sfdc-developer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfdc-developer.blogspot.com/feeds/1298670923555007322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sfdc-developer.blogspot.com/2009/07/welcome-whats-this-all-about-all-that.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/1298670923555007322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6603137353225548719/posts/default/1298670923555007322'/><link rel='alternate' type='text/html' href='http://sfdc-developer.blogspot.com/2009/07/welcome-whats-this-all-about-all-that.html' title='Welcome, what&apos;s this all about, all that jazz...'/><author><name>He Be GB</name><uri>http://www.blogger.com/profile/16153282177288126057</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
