Cooking with Code: A Satisfying Introduction to Apex sObjects

Working with sObjects in ApexWelcome back to Cooking with Code (CWC), where today you’ll enter a place that should feel pretty familiar to my fellow Awesome Admins (can I get a “hell yeah!”?).

I’m talking about working with records in Salesforce objects (e.g., Accounts, Contacts, Opportunities). When we work with these in Apex, we have a fancy new way to talk about them, as sObjects.

I can’t wait to show them off to you (and you off to them!). I think you’re really going to like each other. And after that…who knows what might develop?

What are sObjects?

Salesforce records are Apex sObjects.Like primitives and collections that I’ve covered in CWC previous posts, sObjects are another Salesforce data type.

An sObject is a variable (container) that holds a particular type of data; a Salesforce record. (Hence the “s” in sObject.)

If you haven’t (yet) read my post on collections in Apex, you may be curious why on earth we need a new name for something that we already know and love. It’s because objects in Apex mean something different than objects the in the Salesforce point-and-click environment. If you’re curious what that is (go on! You know you are!), then check out my previous post: How buying a major appliance can help you understand Object-Oriented Programming, where I  talk about objects (and classes and methods).

So I’ll say it one more way:

Variables are like containers. Image showing a container containing an opportunity. The container is the sObject.In Apex, sObjects refer to a variable that holds some kind of Salesforce record from a standard or custom Salesforce Object.

You may be wondering why I’m so excited to be talking about sObjects. Well, it’s because they give us a way to store an entire Salesforce record in a single variable.

We can also use sObjects to hold data about new records before we add them to our Salesforce database. Let’s dive into that code:

Account a= new Account();

With just those 26 characters, we have created a variable (container) called “a” and made it a new Account sObject. Let’s break it down:

Account a This is declaring (creating) a new variable called “a” of the sObject data type. But not just any generic sObject.  We specifically want the variable to hold an Account record.
= This is an assignment operator (we’ll talk more about them in another post), it assigns the bit on its left to the thing on its right.
new Account(); This is what we’re assigning our new variable; that is, we’re assigning it to be a new Account.

But our new variable, “a”, is not very special yet. It doesn’t hold anything other than an empty record. This record doesn’t even live in the database yet. It just lives in our Apex code. If we were to run this, it wouldn’t affect our Salesforce data at all.

But this wouldn’t be a very appropriate CWC post if I didn’t throw in a few food references, so let’s talk about how this would work with a custom Salesforce object.

Creating sObjects for custom Salesforce objects

Say we had a custom Recipe object in Salesforce to store all our fabulous recipes. As an admin, you probably know that the API name for all custom objects and fields are suffixed with “__c” (that’s underscore, underscore c). So what if we wanted to create a new recipe? Easy peasy pumpkin pie!

Recipe__c r = new Recipe__c();

It’s exactly the same as our first block of code, but we’re using the custom object’s API name of Recipe__c:Recipe Custom Object showing API name is Recipe__c

So, I’m sure you’re completely blown away by this, but wait, there’s more!

What if we wanted to create a new recipe and include the values we eventually want to insert as a new record in our Recipe object? Well, first we need to know what the fields are. Let’s look in our Salesforce setup (see below).

Showing custom and standard field setup in Salesforce

Here you can see that in addition to our Name field, which comes standard with every custom object, we also have created five custom fields:

  • Category__c (Picklist)
  • Cooking_Time__c (Number)
  • Level_of_Difficulty__c (Picklist)
  • Preparation_Time__c (Number)
  • Total_Time__c (Formula).

I’m using the API names on purpose, because it’s what we will be using in Apex.

So imagine we had a new recipe that we wanted to add to our Recipe Salesforce object:

Field Name Value
Name Pavlova
Category__c Dessert
Cooking_Time__c 3.5 (we’re going to assume these are fractions of hours)
Level_Of_Difficulty__c Easy
Preparation_Time__c 0.5 (again a fraction of an hour, i.e., 30 mins)
Total_Time__c We don’t need to worry about this because it is a calculated value

To create a new variable, which will hold this new recipe, our code would look like this:

Recipe__c r = new Recipe__c(
    Name='Pavlova',
    Category__c='Dessert',
    Cooking_Time__c=3.5,
    Level_Of_Difficulty__c='Easy',
    Preparation_Time__c=0.5
);

I’ve spread the code out so it’s a little easier to read. Let’s break it down:

Lines 1 & 7 are the same as in the code above.

What we’re doing with lines 2-6 are assigning a value to each of the fields in our Salesforce Recipe object:

Name equals ‘Pavlova’,

Category__c equals ‘Dessert’,

and so on.

Use single quotes around strings. Do not use quotes around numbers and boolean values.Note that in Apex, we use single quotes around string and date & time data types, but not around numbers or boolean values.

You can see the difference in lines 3 vs 4. Line 3 uses single quotes around recipe string category field: Dessert. While in in line 4, we do not put them around the numeric cooking time value.

I love errorsIf you did put quotes around the number value (i.e., Cooking_Time__c=’3.5’,), and tried to run the code, you’d get an error message. I want to emphasize that getting an error message is not a bad thing. I know, that may sound strange, but take it from me, if you code, you WILL see MANY error messages. It’s just part of the journey, and it will make you a better coder (for more on this, read Mary Scotton’s recent article: Coding is all about Failing).

You can see an example of the error below. At first glance, this may look like gobbledigook, but it’s actually telling us exactly what’s wrong: our database is expecting the field Cooking_Time__c to be a Decimal, and we sent it a string. Not only that, but it’s also telling us where we made the mistake (Line 4)!  So while Error messages may get a bad rap, they are really just trying to help us out (and mostly doing a great job).

Today I decided to write an entire blog post on how to read error messages. They can seem so scary at first (“OMG, I got it wrong! I’ll never get this!”*), but they’re actually really helpful when you’re learning to code. I have some great tips on how to code so that you can make the most of them. But enough of that, we’ll deal with error messages in a later blog.  Let’s get back to our new recipe?

* To which I answer, “Never give up! Never Surrender! Of course you’ll make it! It just takes time, and reading lots and lots of error messages.”

Adding our new recipe to our Salesforce database?

A quick question, do you think we have a record in our database yet?

The answer is, “Almost, but not quite.”

What we have done, is store our new recipe into a sObject variable, called “r”, that’s just hanging out waiting for further instructions. We need to take one last step to insert it into our Salesforce database. We will take that step using Apex Data Manipulation Language (or DML).

You might be asking, “How many #!?@?! languages do I need to know to code on Force.com?” **  but this one is super simple. You are going to be amazed at how simple!

** BTW, the answer to your question is three: Apex, DML and SOQL, but no freaking out allowed! One step at a time and as you’ll see, DML barely counts. There are more you can learn (like Visualforce), but at a minimum you’ll want to know these three.

But back to our coding.  All we have to do to add this record to our Salesforce database is use the following line of code:

insert r;

What! Are you kidding me?

Nope, that’s it. That tiny piece of DML will insert our brand new Pavlova recipe into our database. Voila!

DML inserts the sObject into Salesforce

So the full code would be:

//Create the new sObject variable
Recipe__c r = new Recipe__c(

//Put data into the variable
    Name='Pavlova',
    Category__c='Dessert',
    Cooking_Time__c=3.50,
    Level_Of_Difficulty__c='Easy',
    Preparation_Time__c=0.50
);

//Use DML code to insert the record
insert r;

And after running this code, we can see our wonderful new recipe (or at least the start of a wonderful new recipe) in our Recipe object. How satisfying is that? Way!

New recipe record for Pavlova in Salesforce

Is that really all I need to do?

It would be remiss of me if I didn’t point out that I’m not exactly following best practices in my Apex code above. What’s more, I’m not doing it on purpose. Don’t worry, I will write another post where I fix the problems, but I wanted to introduce the basic concepts of sObjects and DML without added complications. First, let me tell you shine a light on the issue.You are allowed to insert up to 150 records using DML in a single transaction.

The problem isn’t that the code won’t run (it will), but it will only run if we were only adding small number of records (under 150). It would not work if we were adding many, many records (e.g, doing a data import). This is because one of the basic tenets of Salesforce is that we all live together in one happy multi-tenant environment. Like a massive house with millions of roommates.Why Bulkify your code? Because if you add more than 150 records in a single transaction you will get an error.Execute Anonlymous Error: Line: 4, Column: 17. Invalid initial expression type for field Recipe__c.Cooking_Time__c, expecting: Decimal.

While our data is safely cordoned off from each other, ultimately, what I do affects you, and vice versa. That’s because we’re using the same computer processing space. So if I ran a very inefficient insert command, and tried to insert many thousands (or more) of records with it, it would slow down everyone.

Be a good housemate and take short showersIt would be the equivalent of taking a super long shower and using up all the hot water. Not good.

So to prevent this from happening, Salesforce (rightfully) puts some boundaries around how many records you can work with in a single transaction (think of a transaction as a single block of code like our example above).

But never fear, you can build your code correctly so that you can work with vast numbers of records (e.g., mass updates/inserts, etc); all through the process of Bulkification. What Bulkification does (apHow to Bulkify your code by creating an Apex collection of sObjects and using a single DML statement to insert the entire collection at once!art from make me smile every time I say it) is create a collection of sObjects (see a previous post: Amuse-bouche of Apex Collections (Lists, Sets, and Maps) and work with them as a single batch. You should do this, even if most of the time you’ll only be working with a one record at a time (e.g., when someone creates a new record directly in Salesforce). That’s because you never can tell when you might want do a mass import/update, and that is not the time to find out your code doesn’t work.

Sadly, that’s all I’m going to say about Bulkification for now. I know..I know, but you’ll just have to look forward to a future post where we can explore it fully together. If you can’t wait, then check out Salesforce’s Best Practice: Bulkify Your Code as a taste of what’s to come.

What else can you do with sObjects?

We know now that we can use sObjects (and DML) to insert a record into Salesforce. But that’s just the beginning; we can do all sorts of things with them beyond that, including:

  • Query your Salesforce database and store the results in a collection of sObjects
  • Use this collection to make a custom record list page on Salesforce
  • Modify the data in the collection and then send it back to Salesforce to update your records
  • Loop through your array to create child records related to the parent record in your sObject collection

Oh, there are soooo many things we could do. And that also, is a topic of one or more future posts. Baby steps right?

Summing upblog-sObjects-twitter2

I hope you’ve enjoyed this introduction to sObjects in Apex. Even more so, I hope you can see that they build on what you already know as an Awesome Salesforce Admin. They’re all about using variables to work with entire Salesforce records.

You have seen how to create a single sObject variable to hold a single new record, and how to send that variable up to Salesforce to insert a new record into your database.

You also know now that that inserting a single record in this way isn’t best practice, and you’re intrigued about when you’ll learn to bulkify your code. Go on, admit it!

Soon, I promise!

Until next time….

Bon Appetit!