Process billions of records with Async SOQL

Christmas time is closer but I would like to deliver this last post before end of the year.

Some months ago, I wrote an entry talking about BigObjects, a feature that was General Available by Winter ’18 and via a use case, I tried to explain it. Now, I would like to follow that post with a new way to create records, Async SOQL.

Async SOQL is half GA by Winter ’18 and half still in Pilot 

The use case talked about moving Code Review custom object records, into Code Review History big objects records, and release storage of custom objects one. We want to Archive records, and Async SOQL will help us to deal with big amounts of data.

What is Async SOQL?

Basically Async SOQL allows you to run SOQL in the background so that, you will get a response after a period of time, but at the same time, helps you to deal with millions or even billions of records without hitting time outs or governor limits.

How can I execute Async SOQL?

Async SOQL is implemented as REST full API and in order to execute this SOQL in the background we need to run a post request:

Captura de pantalla 2017-11-29 a las 21.51.22

And provide a body in JSON format in order to make the call. Find bellow a really easy example that helps you to create Vendor__c custom object records based on Accounts.

Captura de pantalla 2017-12-19 a las 9.40.12What can we highlight?

query: allows you to define a SOQL. On our case, the object I’m going to read, Account and the field I want to recover, Name.

operation: help us to define what we want to do, insert or upsert (please check big objects entry to understand Primary Key and upsert, as it works in the same way)

Basically that is the main difference between simple SOQL and Async SOQL. With this new feature we can read and create or update records in one go.

targetobject: object we want to use to create new records. In our case, Vendor__c.

Then, we need to specify from where we want to get record field values and where we want to store this info. For that we have 2 keys in this JSON code.

targetFieldMapping: allows you to define source field and target fields

and

targetValueMap: allows you to map a target field with a literal value, for instance, we want all records have Spain as Country__c field value.

How is the response?

When we do the post call, we get a similar response:

Captura de pantalla 2017-11-29 a las 22.01.12

It is also in JSON format and basically it provides similar information that you passed in the post call. Just highlight 3 keys:

jobId: remember this is an asynchronous call so there is an Id related to the background job. You can also use it in the post call via the global variable $Job_Id as part of key value on targetValueMap.

status: helps you to know where is the job. Moving from New to Running, Complete, Failed etc.

message: before executing the call, the code is analyzed. If it realizes about a possible issue, it doesn’t start the call and provides an error message in that field. For instance, below message. My VendorName__c field size was too short to store all Account Names.

Captura de pantalla 2017-11-29 a las 22.11.03.png

How can I stop the execution?

Async SOQL doesn’t provide a UI in Salesforce like other background jobs like Batch Apex or Queueable. But we can make an http delete call passing the jobId as part of the url.

Captura de pantalla 2017-11-29 a las 22.22.02

How can I check the progress?

Similar as before, as we do not have UI, we need to look for another way in order to get this information. For that, we have 2 options:

1º – Make a get post call: Similar to the cancel action, if we pass the JobId as part of the url, and do a get call, the response shows you information abut the background execution that is running in the system.

Captura de pantalla 2017-11-29 a las 22.32.33

2º – Make a SOQL against BatckgroundOperation object: This is a new object where we can see extra information about the job execution.

Captura de pantalla 2017-11-29 a las 22.32.42

But this is not the only new object that we can get in the system. We also have BackgroundOperationResult that will help you to identify any issue during the execution if the result is not the expected one. For instance. Bellow image shows an issue related to a field that is required but the source value is empty. In that case, a new error is logged on this table, but the execution doesn’t stop, it continues till the end.

Just keep in mind that this information would be removed after 7 days.

Captura de pantalla 2017-11-29 a las 22.32.55

And what about Archiving?

Yes, you are right. We promised to show you how to archive Code Review records but tried to explain the whole functionality with a really simple use case. Now it’s time to move to Code Review History use case.

As I mentioned before, we would like to create Code Review History records reading Code Review records. Similar as before we will do a post call but the body would be like this one:

Captura de pantalla 2017-11-29 a las 22.51.40

On BigObjects post, the object was called Test1CodeReviewHistory__b instead of CodeReviewHistory__b

And … that’s all. Simple, isn’t it?

Can I integrate this functionality into Apex?

Yes, of course, at the end we are just making http calls, so we only need to set the proper url, add it on my remote settings and create a string in JSON format for the body.

Captura de pantalla 2017-11-29 a las 22.42.57

Summary

Finally I would like to sum up some key concepts we have talked about.

  1. Async SOQL allows you to run SOQL in the background
  2. It takes some times but allows you to process millions or even billions of records
  3. You do not need to worry about governor or time out limitations
  4. It is implemented as REST full API
  5. You can make as many calls as you want per day but just a single one at a time
  6. You can read and create records in one go. Delete is out of scope
  7. This feature is part GA and part still in Pilot:
    1. Read Standard or Custom objects and create Standard, Custom or Big Objects is in Pilot
    2. Read Big Objects and create Standard, Custom or Big Objects is GA

Captura de pantalla 2017-11-29 a las 22.43.44

My First Lightning Component on Utility Bar via Eclipse

Note: I wrote this post in October 2016 but didn’t publish it because I was getting issues trying to making Eclipse work. However, after few months and do not find a solution, I decided to publish what I wrote. Maybe first steps could help others. An if you have the answer to my issue, I would really appreciate your help.

In addition I have included a super simple Lightning Component and how to integrate in the new Utility Bar that Spring ’17 bring to us.

When you develop some code, which is the tool you use for it? If you have never created some complex line of code, maybe you think that Developer Console allows you to do what you need. However, if your daily basis is programming, you need a tool outside of the org for that.

Nowadays I use Mavensmate, but on my early days I was an Eclipse fan, so when I knew that there is a beta version of Force.com IDE in order to create Lightning Components, I decided I had to check it. And this post is about it. Well, more about how to install it, as well as create a super simple Lightning Component.

First of all, I tried to open my Eclipse and create a project againts my org. But I got this error:

captura-de-pantalla-2016-10-08-a-las-12-18-48

Oh my God!! It’s true that long time ago since I don’t open Eclipse (Juno in my case) !!! So first of all, fix it. How? Here there is a link that explain you about this Salesforce change, but here is what I did on my Mac.

  1. Run java -version on cmd — old version as well !! So via System Preferences, click on Java icon and updated the version to 8 one there. And also download latest JDK.

Now java -version returned to me 8 one. So I tried again and this time it worked.

However I tried to install Force.com IDE for lightning and I got an error, so checked more instructions and I found this article and I realized that my version was older than 4.5, so decided to download a newer version. If this is not your case, jump next section

How to install eclipse

From here you can download latest Eclipse version (be sure you get it for Mac or PC depending on your machine OS). Well, actually you download an installer. When I executed it, I got an error message, so after looking at several blogs, like this one, I realized that I had to update the installer via the top right coner icon.

captura-de-pantalla-2016-11-11-a-las-14-20-53

Then just select Eclipse IDE for Java Developers and click on install. Again I got an error with Neon, so I decided to try with another Product which version is higher than 4.5, so I chose Mars

Captura de pantalla 2016-11-22 a las 17.16.09.png

How to install Force.com IDE

The installation is quite straight forward, you just need to follow below steps (find also the information here)

  1. In Eclipse, click Help > Install New Software.
  2. Add this new update site: https://developer.salesforce.com/media/force-ide/beta_eclipse45
  3. Be sure that Group items by category checkbox is not selected.
  4. Select the checkbox next to Force.com IDE (required).
  5. If you have Apex Debugger licenses, select the checkbox next to Force.com IDE Debugger.
  6. Select the checkbox next to Force.com Lightning Support
  7. Click Next and start the installation.

20170203 Note There is new link to Eclipse IDE because it is no beta anymore as well as you can also find more information on Salesforce page as well. I tried with them as well, but no luck, still does not work.

How to work with Eclipse

Now you can create the project as usual, but you will realize that the folder structure looks different. It also have the aura folder. If we want to add / create the aura element we will find the entry as well.

How to create a Lightning Component

As you can find lot of information related to Lightning Components creation (including Trailheads) I will not explain in deep what it is a Lightning Component and how to create it. Just show you how you can develop something super simple in Eclipse.

Use Case – Employee List

I have a custom object, Employee, in my organization

Captura de pantalla 2016-11-23 a las 10.49.10.png

And I would like to create a Lightning Component that list all my Employees and be able to insert on the Home tab, for instance.

20170203 Note: I was not able to make Eclipse work, so this code has been developed in Salesforce Developer Console. Do you want me to help anyhow and get some credits? Find my question on stackExchange as well as Developer Forums

Super simple Employee List Lightning component

I will create 2 component.

The first one will just show the FirstName and Surname of an Employee

<!-- EmployeeListItem -->
<aura:component>
    <aura:attribute name="employee" type="Employee__c"/>
    <li>{!v.employee.FirstName__c}{!v.employee.Surname__c}</li>
</aura:component>

And the second one will iterate over a list of Employees and make calls to the above component in order to show the information.

<!-- EmployeeList -->
<aura:component controller="EmployeeController" 
                implements="flexipage:availableForAllPageTypes">
    <aura:attribute name="employees" type="Employee__c[]"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <h3>Employees</h3>
    <aura:iteration items="{!v.employees}" var="empl">
       <c:EmployeeListItem employee="{!empl}"/>
    </aura:iteration>
</aura:component>

But for that, it needs to retrieve the information somehow. That’s why we have the reference to the server side controller EmployeeController.

/**
* @agarciaodeian
**/

public with sharing class EmployeeController
{
    @AuraEnabled
    public static List<Employee__c> getEmployees()
    {
        List<Employee__c> listRetrieved = new List<Employee__c>();        
        if(Schema.sObjectType.Employee__c.isAccessible())
        {
               listRetrieved = [SELECT Id, Name, FirstName__c, 
                                       Role__c, Surname__c 
                                FROM Employee__c];
        }
        return listRetrieved;
    }
}

Finally, in order to get the result, in the EmployeeList we execute the action that initialize the list of employees making a call to the JavaScript controller

({
    doInit : function(component, event) {
       var action = component.get("c.getEmployees");
       action.setCallback(this, function(a) {
          component.set("v.employees", a.getReturnValue());
        });
        $A.enqueueAction(action);
    }
})

Once I have the code in the organization, I can create a project on Eclipse and I would see my components under the aura folder

captura-de-pantalla-2017-02-04-a-las-11-42-36

If I open EmployeeList, for instance, I can see also the EmployeeListController.js tab as well. So it is easier and it is sorter than in the Developer Console.

How to add my Lightning Component to the Utility Bar

captura-de-pantalla-2017-02-04-a-las-11-57-11

 

 

 

Once I have the Lighting Component, I can show the result in the Home page tab for instance

 

 

 

And now that Spring ’17 is arriving, we can include also our lighting components into the Utility Bar. Previously we had to create it via metadata and deploy but now it’s a matter of point and clicks.

Go to App Manager and edit your app. Now, one of its steps is the Utility Bar  and after clicking on Add button you can find same Lightning Components than in the App Builder.

captura-de-pantalla-2017-02-04-a-las-15-32-54

For instance, standard like Flow (Beta), Manage, and Custom. So I select my custom lighting Component Employee List.

And … that’s all!! Now I have my super simple LC in the Utility Bar, so that I can see the list of all Employees from everywhere, including Salesforce Setup page.

captura-de-pantalla-2017-02-04-a-las-15-36-51

Maps and Visualforce

Since I was checking Force.com documentation in order to pass Platform Developer Transition exam I had the opportunity to learn more about some topics that I don’t usually use on my daily job.

One of those are Maps, and I’m not talking about Collections (Lists, Sets and Maps). I would like to talk about locations on this post.

Till some releases ago, the only way to add a location into your visualforce page, was via JavaScript. Let’s see an example. (Bellow use case is based on this Salesforce Trailhead)

I’m working on a healthcare app, and we would like to show a map on every doctor’s record, so that, the customer would be able to find the location easily.

In order to get it, I will create a visualforce page with the map and include it in the standard layout.

JavaScript Map Version

First thing is to add the listener:

 google.maps.event.addDomListener(window, 'load', initialize);

that call an initialize function

 var map;
 
 function initialize() {
     var mapOptions = {
         center: new google.maps.LatLng(43.2616465, -2.9393368),
         zoom: 15
     };
     map = new google.maps.Map(document.getElementById("map-canvas"), 
                               mapOptions);
     loadDoctor();
 }

Where we define map properties, like latitude, longitude and zoom.

But this function call another, loadDoctor 

 function loadDoctor()
 {
     Visualforce.remoting.Manager.invokeAction(
         '{!$RemoteAction.DoctorsController.findTheDoctor}',
         '{!Id}',
         function(result, event)
         {
             if (event.status) {
                 var name = result.SurgeryName__c;
                 var lat = result.Location__Latitude__s;
                 var lng = result.Location__Longitude__s;
                 addMarker(name, lat, lng);
             } else {
                 alert(event.message);
             }
        },
        {escape: true}
     );
 }

Above function uses a RemoteAction method, so we know that a Controller is included on this page. This communication with the controller just returns information about the Doctor’s records like his place name and the Location. Maybe you are wondering what below line means.

Location__Latitude__s  and  Location__Longitude__s

Location is a Geolocation field, and, in the end, it is a Compound field, so in order to see the information, we need to decouple into its “elements”, Latitude and Longitude.

Finally, on above method, we have a call to another function that will add the marker on the google map

 function addMarker(name, lat, lng)
 {
     var marker = new google.maps.Marker
           ({
               position: new google.maps.LatLng(lat, lng),
               map: map,
               title: name
           });
 }

With this code, the result is this one:

Captura de pantalla 2016-07-30 a las 22.17.58

Apex Map Version

Is there a different way to get the same result? Yes !! Since Spring ’15 we have a new tag available on visualforce pages: apex:map and with this piece of code:

<apex:map width="100%" height="100%" mapType="roadmap" zoomLevel="15"
          center="43.2616465, -2.9393368">
    <apex:mapMarker title="{!Doctor__c.SurgeryName__c}" 
                    position="{!Doctor__c.Location__Latitude__s},
                              {!Doctor__c.Location__Longitude__s}">
    </apex:mapMarker>
</apex:map>

we can get exactly what we had on the javascript code as we can see on below image that compares both maps. Left side uses apex:maps whereas on the right side the map is created with javascripts.

Captura de pantalla 2016-07-30 a las 22.24.42

More about apex:map

Attributes

  • Height and Width could be defined as pixels or percentage
  • Center could be used with Location data, Address and also with JSON format. From my point of view, it would be easier to create a method in the controller with the data
public Map<String,Double> getDoctorsCenter()
{
    Map<String,Double> mapCenter = new Map<String,Double>
                                   {
                                      'latitude' => 43.2616465,
                                      'longitude' => -2.9393368
                                    };
    return mapCenter;
}

and use the method in the visualforce page.

<apex:map width="100%" height="100%" mapType="roadmap" 
          zoomLevel="15"
          center="{!doctorsCenter}">

Above example set geolocation with hardcode but if we have this information on data base, the code could be safer and don’t fail if there is any change on this data.

MapMarker

  • Similar as before, position attribute could be defined based on Address, JSON or using the Geolocation field. On above example, we directly used the compound sub-fields, but it would be also fine to get this information in the controller, create the map and call the method in the page as we show on center attribute.
  • If your idea is to show all doctors around your city, instead of adding an mapMarker per record, remember to use apex:repeat tag
<apex:map width="100%" height="100%" mapType="roadmap" zoomLevel="15"
          center="43.2616465, -2.9393368">
    <apex:repeat value="{!locations}" var="pos">
        <apex:mapMarker position="{!pos}"/>
    </apex:repeat>
</apex:map>
  • Another mapMarker attribute is icon that help us to show a different image than the red bubble that google offer to us. A good way to show it is using a static resource and make a call to it.
<apex:mapMarker title="{!Doctor__c.SurgeryName__c}" 
                position="{!Doctor__c.Location__Latitude__s},
                          {!Doctor__c.Location__Longitude__s}"
                icon="{!URLFOR($Resource.MapMarkers, 'myIcon.png')">
</apex:mapMarker>

MapInfoWindows

  • This is another tag to show even more information. So for instance, below code show the doctor’s name and phone if we click on the marker icon
<apex:map width="100%" height="100%" mapType="roadmap" zoomLevel="15"
          center="43.2616465, -2.9393368">
    <apex:mapMarker title="{!Doctor__c.SurgeryName__c}" 
                    position="{!Doctor__c.Location__Latitude__s},
                              {!Doctor__c.Location__Longitude__s}">
        <apex:mapInfoWindow >
            <apex:outputPanel layout="block" style="font-weight: bold;">
                <apex:outputText >{!Doctor__c.SurgeryName__c}
                </apex:outputText>
            </apex:outputPanel>
            <apex:outputPanel>
                <apex:outputText >{!Doctor__c.Phone__c}
                </apex:outputText>
            </apex:outputPanel>
        </apex:mapInfoWindow>
    </apex:mapMarker>
 </apex:map>

 

Captura de pantalla 2016-08-02 a las 17.58.24.png

JavaScript vs apex:map

  1. Unfortunately, we cannot create a page with map tag in a Developer Edition, however JavaScript is available on Developer editions. But if you want to give it a try, create your own Trial edition.
  2. As JavaScript is executed on the client side, the map is loaded quicker than the one that use apex:map.
  3. On the other side, Salesforce takes care of any apex tag so any change on code versions, or browser, etc. that could make the code fail, Salesforce will deal with it.
  4. JavaScripts needs a method in the controller in order to get Location information dynamically and if we want to show the map inside a Standard layout, we must define the RemoteAction method as global that makes you define the class as global as well. This is not important till you add the code inside a package. As a reminder, global classes are available to everybody that install your package and maybe this is not your desire.
  5. RemoteAction is not able to get parameters from url. So I cannot do something like
Id currentDoctorId = controller.getId()

and then use it on the RemoteAction method. However,  in our case, we can use directly the Id of the record on the visualforce page as a workaround:

Visualforce.remoting.Manager.invokeAction(
         '{!$RemoteAction.DoctorsController.findTheDoctor}',
         '{!Id}',
         function(result, event){....});

Resources

  1. Apex:map Salesforce documentation
  2. Github Repository with code used on above examples

Platform Developer Certification – Transition Exam

As a developer, I wanted to learn as much as possible and a good way to do it is getting any of the certifications that Salesforce offers to us.

I was able to get 401 and 501 credentials, so I decided to share some tips about them writing an entry some months ago.

However a year ago, Salesforce decided to modify certifications and 401 and 501 were not available anymore.

So what could I do? Do I lose my credentials? No at all. I still can say that I got these certifications. However Salesforce also advices to us to move to the new one.

In order to do it we have different paths as you can see on below image:

Captura de pantalla 2016-07-12 a las 15.09.09

I decided to go for the combo Transition Exam, but lot of questions came to my mind. So let me share all answers I got. Maybe they can also help you.

Q – How is the Exam?

A – This is a test exam. We have 30 minutes to answer 16 multi-choice questions, and we need to get 63% (11 questions) right to pass the exam. Per my experience, don’t waste the time. Read carefully and if you are not completely sure, mark to review it later and move to the next one.

Q – When do I get the results?

A – After submitting the exam. As usual, we would get the Pass or Fail response. Unfortunately we don’t get the score. You can only see if you passed it or not.

Q – Is this a proctored exam?

A – Yes !! So take care and prepare your place for the exam in advance.

Q – What can I do if I fail the exam?

A – Good questions!! That also worried to me. This is a free exam and you can try to pass it as many times as you need. The only thing that you need to take into account is that you cannot try it more than 3 times per release. This mean. Salesforce deliver 3 releases a year, so you have 9 opportunities to do it per year.

Q – What should I study to pass it? 

A – There is no guide to know what you need. To be honest, you should get Platform Developer I and II guides and check what it is required for them and study the same. I reviewed all the material that I used to pass 501 exam. And in addition, I checked:

Obviously, Trailheads are also very useful to remember certain contents for example Life cycle one.

Q – Should I look for any other material?

A – Something I didn’t find on above documents and I was asked for was about:

  • Compounds fields
  • Certifications, kind of certifications depending on device …
  • Streaming API

Actually the exam was a challenged and that also helped me to learn even more.

Q – What kind of questions could I find?

A – This test exam provided different options and you need to select one or many responses.

An example could be (This is not a question of my exam. This is an example I have created based on what I found during the exam)

Having this piece of code:

@RestResource(urlMapping='/user_defined_type_example/*')
global with sharing class MyOwnTypeRestResource 
{
   @HttpPost
   global static MyUserDefinedClass echoMyType(MyUserDefinedClass ic)
   {
      return ic;
   }

   global class MyUserDefinedClass
   {
      global String string1;
      global String string2 { get; set; }
      private String privateString;
      global transient String transientString;
      global String staticString;
   }
}

And these JSON calls:

1. 
{
   "ic" : {
             "string1" : "value for string1",
             "string2" : "value for string2",
             "privateString" : "value for privateString"
          }
}

2.
{
   "ic" : {
             "string1" : "value for string1",
             "string2" : "value for string2"
          }
}

3.
{
   "ic" : {
             "string1" : "value for string1",
             "string2" : "value for string2",
             "transientString" : "value for transientString",
             "staticString" : "value for staticString"
           }
}

Which is the correct call?
a) 1
b) 2
c) 3
d) 1 and 3
e) 1 and 2
f) 1, 2 and 3

Q – Once I pass the exam. Do I have to do anything else? Assignment or any other test?

A – No !! Since that moment you get your new credentials and you only need to do the maintenance exam as usual 3 times a year.

Q – I have Force.com Developer (401) certification. Does the maintenance exam cover also that one?

A – I’m afraid that Platform Developers maintenance don’t cover 401 certifications, so you would have to do 2 exams per release. But nothing to worry too much.

Do you have any other question? You can open a case here.

Once you get it you can also check your certification in the verification page. Something that I will miss from this page is my Advance Developer logo.

Captura de pantalla 2016-07-12 a las 15.03.17

By the way, the correct answer on above question is option e).

Lightning Connect and Apex Connector Framework

After publishing 2 entries talking about

On this one I would like to go one step further on Lightning Connect feature – Apex Connector Framework

As you know, Lightning Connect would allow us to link an external repository to our Salesforce organization. In order to do this connection we can use an existing OData provider or create something by ourselves like we can read on the first Lightning Connect post.

However, since Summer’15 we have the new Apex Connector Framework General Available, so everybody can use it and get advantage of it. At the end we are going to create the connection all in apex so we can forget any other language.

Checa Hotel – Use Case

Let’s back to the same example that we have talked about till now, Checa Hotel one and its reservations.

In order to work with Apex Connector we need to create 2 classes:

HotelReservationConnection

This class must extend DataSource.Connection and although Salesforce documentation shows it as global, you could check on this example that it works properly if we make it public. My advice is to create a global class if we want to expose the code outside of our package, otherwise, it could not be desirable.

public with sharing class HotelReservationConnection extends DataSource.Connection
{
    private DataSource.ConnectionParams connectionInfo;
    public HotelReservationConnection(DataSource.ConnectionParams connectionParams)
    {
        this.connectionInfo = connectionParams;
    }
}

Now we need to override 3 methods:

Sync

This method will create the new object and its fields. At the end when we click on Sync And Validate button during the creation of the External Data Source, this method would be called.


override public List<DataSource.Table> sync()
{
    List<DataSource.Table> tables = new List<DataSource.Table>();
    List<DataSource.Column> columns;

    columns = new List<DataSource.Column>();

    //Standard fields
    columns.add(DataSource.Column.url('DisplayUrl'));
    columns.add(DataSource.Column.text('ExternalId',255));

    //Custom fields
    columns.add(DataSource.Column.get('Name', 'Name', 'Name Field for the table', true, true, DataSource.DataType.STRING_SHORT_TYPE, 10, 0));
    columns.add(DataSource.Column.get('EndDate', 'End Date', '',true, true, DataSource.DataType.STRING_SHORT_TYPE, 10, 0));
    columns.add(DataSource.Column.get('GuestName', 'Guest Name', 'Name of the Guest', true, true, DataSource.DataType.STRING_LONG_TYPE, 80, 0));
    columns.add(DataSource.Column.get('Paid', 'Paid', '',true, true, DataSource.DataType.BOOLEAN_TYPE, 255, 0));
    columns.add(DataSource.Column.get('Price', 'Price', '',true, true, DataSource.DataType.NUMBER_TYPE, 18, 2));
    columns.add(DataSource.Column.get('RoomNumber', 'Room Number', '',true, true, DataSource.DataType.NUMBER_TYPE, 18, 0));
    columns.add(DataSource.Column.get('SpecialRequirement', 'Special Requirement', '',true, true, DataSource.DataType.STRING_LONG_TYPE, 255, 0));
    columns.add(DataSource.Column.get('StartDate', 'Start Date', '',true, true, DataSource.DataType.STRING_SHORT_TYPE, 10, 0));

    //Table creation
    DataSource.Table newTable = new DataSource.Table();
    newTable.labelSingular = 'New Hotel Reservation';
    newTable.labelPlural = 'New Hotel Reservations';
    newTable.name = 'NewHotelReservation';
    newTable.description = 'Hotel Reservations via Apex Connector';
    newTable.nameColumn = 'Name';
    newTable.columns = columns;

    tables.add(newTable);

    return tables;
}

We can highlight 3 blocks

  • Standard Fields: We only have to define 2 columns and specify their API Names. These 2 rows are required:
    • Display ULR that at end is a link.
    • External Id that will help us to set the uniqueness across the whole organization.
  • Custom Fields: At this point we are going to specify all fields that we want to show in our object. There are 2 ways to specify every single column:

columns.add(DataSource.Column.text(‘GuestName’,255));

We only specify the API name and its Length.

columns.add(DataSource.Column.get(‘GuestName’,
‘Guest Name’,
‘Name of the Guest’,
true, true,
DataSource.DataType.STRING_LONG_TYPE,
80, 0));

In the case we want to add more information the the field. On above line we can see the API Name, Label, Description, Filtering Disabled field, Sorting Disabled field, Data type and Length.

  • Table creation: We will specify some features of the new object. Maybe the one that we are not so use to see is the “name” field. With it we will specify the column that will help us to open every single record instead of having to do it with just the External Id one. Similar as before we can also create the table with a single line, but we would not specify all characteristics as we can do before.

tables.add(DataSource.Table.get(‘NewHotelReservation’,’Name’,columns));

Query

This method will help us to make queries in the organization. It means SOQL and also in the User Interface.

But here we need to specify how can I retrieve and show a single record in the case that we click on the External Id or Name field link (if part of below code) and also how can I show all records if I open the object List View (else piece of code).


override public DataSource.TableResult query(DataSource.QueryContext context)
{
    if (context.tableSelection.columnsSelected.size() == 1
&& context.tableSelection.columnsSelected.get(0).aggregation == DataSource.QueryAggregation.COUNT)
    {
        List<Map<String,Object>> rows = getRows(context);
        List<Map<String,Object>> response =
DataSource.QueryUtils.filter(context, getRows(context));
        List<Map<String, Object>> countResponse = new List<Map<String, Object>>();
        Map<String, Object> countRow = new Map<String, Object>();
        countRow.put(context.tableSelection.columnsSelected.get(0).columnName,response.size());
        countResponse.add(countRow);
        return DataSource.TableResult.get(context,countResponse);
    }
    else
    {
        List<Map<String,Object>> filteredRows = DataSource.QueryUtils.filter(context, getRows(context));
        List<Map<String,Object>> sortedRows = DataSource.QueryUtils.sort(context, filteredRows);
        List<Map<String,Object>> limitedRows = DataSource.QueryUtils.applyLimitAndOffset(context,sortedRows);
        return DataSource.TableResult.get(context, limitedRows);
    }
}

Search

Similar as before, this method will help us to make searches that include SOSL as well as global searches throw the User Interface in the organization.


override public List<DataSource.TableResult> search(DataSource.SearchContext context)
{
    List<DataSource.TableResult> results = new List<DataSource.TableResult>();
    for(DataSource.TableSelection tableSelection : context.tableSelections)
    {
        results.add(DataSource.TableResult.get(tableSelection,getRows(context)));
    }
    return results;
}

HotelReservationProvider

Similar as before, this class must extend another, DataSource.Provider and override 3 methods. If you take a look at documentation, this class is also global, but you can see on below example that public is more than enough

public with sharing class HotelReservationProvider extends DataSource.Provider
{
    public HotelReservationProvider() {}
}

getAuthenticationCapabilities

This method help us to set up authentication credentials.

override public List<DataSource.AuthenticationCapability> getAuthenticationCapabilities()
{
    List<DataSource.AuthenticationCapability> capabilities = new List<DataSource.AuthenticationCapability>();
    capabilities.add(DataSource.AuthenticationCapability.ANONYMOUS);
    return capabilities;
}

In our case, as the google sheet is public, open to everybody, the authentication is anonymous, but we can determine others like

  • Basic
  • Certificate
  • OAuth

getCapabilities

This second method would allow us to determine what the Datasource is capable during a SOQL or SOSL.

override public List<DataSource.Capability> getCapabilities()
{
    List<DataSource.Capability> capabilities = new List<DataSource.Capability>();

    capabilities.add(DataSource.Capability.ROW_QUERY);
    capabilities.add(DataSource.Capability.SEARCH);

    return capabilities;
}

Although we can find some others like

  • ROW_CREATE
  • ROW_UPDATE
  • ROW_DELETE

getConnection

Finally the method that creates the connection making a call to our Conector class

override public DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams)
{
    return new HotelReservationConnection(connectionParams);
}

How to retrieve data

If you copy-paste above code, it would not compile.

You will find that there is method, getRows, that doesn’t exist. Obviously the name is not the important thing. The most important is the content of the method.

Here is where you are going to define the data, all values you will show in your organization. To highlight, the returned list, a map where the key is the API name of the field that we want to populate and the value is that, a value we will assign to the field.

My advice is to start with some hardcode first, so you can see that all your code is working fine, and then move to read the google sheet.

private List<Map<String,Object>> getRows(DataSource.ReadContext context)
{
    List<Map<String, Object>> rows = new List<Map<String, Object>>();

    List<HotelReservationGoogleSheetReader.HotelReservation> reservations;
    reservations = HotelReservationGoogleSheetReader.readHotelReservations();

    Integer counter = 0;
    for(HotelReservationGoogleSheetReader.HotelReservation resv : reservations)
    {
        rows.add(new Map<String,Object>
                   {
                      'ExternalId' => resv.ItemId,
                      'DisplayUrl' => 'http://www.salesforce.com/hotelReservation/2015/',
                      'Name' => 'NHR-00000' + counter,
                      'EndDate' => resv.EndDate,
                      'GuestName' => resv.GuestName,
                      'Paid' => resv.Paid,
                      'Price' => resv.Price,
                      'RoomNumber' => resv.RoomNumber,
                      'SpecialRequirement' => resv.SpecialRequirement,
                      'StartDate' => resv.StartDate
                   });
        counter++;
    }
}

In my case, I have another class HotelReservationGoogleSheetReader where we will find an inner class HotelReservation with the data of the hotel. And a method readHotelReservations that will use google API to read sheet information and populate HotelReservations lines.

As part of your investigations, I will leave you to find how to read the google sheet, but I can show you a small piece of code. At the end I only make a Http request to get access to google and once I have its cells I will use Salesforce XMLStreamReader to iterate over there.

Apex Connector framework provides lot REST API examples in order to access Google Drive in general so take a look at them.

Http http = new Http();

HttpRequest reqCell = new HttpRequest();
reqCell.setEndpoint(CELL_URL);
reqCell.setMethod('GET');
reqCell.setHeader('content-type', 'application/atom+xml' );
reqCell.setHeader('X-If-No-Redirect', '1');
reqCell.setHeader('Authorization','AuthSub token="'+TOKEN+'"');

HttpResponse resCell = http.send(reqCell);
String bodyCell = resCell.getBody();

XMLStreamReader reader = new XMLStreamReader(bodyCell);

External Data Source creation

Once I have everything, it’s time to create the External Data Source and its External Object

Similar as before go to:

Setup | AppSetup | Develop | External Data Sources

and click on New.

This time, the Type drop down list will include your Provider class. So after selecting it, just click on Validate and Sync button and your new External Object will be created.

On below image you can find some other Providers, as I have more than one in my organization

Captura de pantalla 2015-12-19 a las 12.54.20

Summary

This post explain to you what is Apex Connector Framework and how to use it with a simple example.

You can also take a look at my latest session at Dreamforce’15 where I explain step by step how to use Apex Connector Framework – Make Anything a Salesforce Object

Now it is your turn to continue doing some investigations around this topic.

Data Pipeline and Salesforce – Do not break the rules

Captura de pantalla 2015-09-14 a las 16.19.20

Salesforce is working in a new feature called Data Pipeline that help us to integrate Apache Pig into Salesforce. Previous link can give you lot of information about what is Apache Pig but basically it is a Open Source technology that gives you mechanism for parallel processing of MapReduce jobs in a Hadoop cluster.

Here we can find 2 main keywords:

  • MapReduce: Software framework to write programs to execute large amount of unstructured data in parallel.
  • Hadoop Cluster: A special type of cluster that helps you to analyze and store large amount of unstructured data.

At the end we will say that:

Data Pipeline will help you to execute processes with large amount of data in parallel in Salesforce. 

Ok, I know what you are thinking right now. It sounds interesting but, I can get the same with other Salesforce features like @future, Queueable or Batch Apex. And that’s right. But the main thing here is that performance is much better and instead of having to wait maybe an hour in order to complete an asynchronous execution, Data Pipeline provides results in few minutes.

And how can we use it in Salesforce? We only need to create a single Pig Script using Pig Latin language (forget Apex) via Developer Console. And once we have it, click on Submit Data Pipeline button to execute the process.

Captura de pantalla 2015-09-11 a las 18.29.00

If you already know Apache Pig probably you know how to use Pig Latin and this pilot will be quite simple for your. But if this is not your case, I would like to start with 2 examples.

One of them will show you how to insert records and avoid getting an unexpected situation due to a validation.

The second one will help us to create records related by a Master – Detail relationship.

1st Use Case – How to create records avoiding breaking Salesforce rules

I have a new custom object called Header__c and I need to create some records taking Opportunity records as resource. The Pig script will look like this one. Something simple, where I retrieve some fields from Opportunity object and after doing a filter by Opportunity Name, store the result in the new Header custom object record.

Captura de pantalla 2015-09-10 a las 10.49.50

As you can see, the result is successful.

Captura de pantalla 2015-09-10 a las 10.50.03

And this is the new record in the list view

Captura de pantalla 2015-09-11 a las 17.38.16

But what does it happen if Header object has a validation that avoid any insertion if amount is not greater than 100? This is the validation rule:

Captura de pantalla 2015-09-10 a las 10.52.07

And if we run the same script, but using Opportunity2 as a source, this is what developer console returns.

Captura de pantalla 2015-09-11 a las 17.43.32

Ok, what is going on? The process finishes successfully. And what about the list view?

Captura de pantalla 2015-09-11 a las 17.38.16

Same as before. Just a single line. So how can we explain this?

We need to remember that Data Pipeline is going to execute records in batch, so if there is any failure during the script execution, and a record cannot be inserted, the process will continue with the rest, and finish successfully. We could compare it with Batch Apex, where the Apex Job screen shows us that an execution has finished properly without errors even if this means that some records where not inserted due to some validations that we have added in our code.

And how can we avoid this situation and not break the rules? Imagine this use case. This time we have 2 opportunities with the same name, but one of them has an amount less than 100.

Captura de pantalla 2015-09-11 a las 17.54.59

If I execute above script, just filtering by the new Opportunity Names, just one of them will be inserted

Captura de pantalla 2015-09-11 a las 18.05.29

But do we have a nicer and cleaner way to do it? We can also filter by amounts so we will avoid hitting the validation:

Captura de pantalla 2015-09-11 a las 18.22.44

Getting the below result

Captura de pantalla 2015-09-11 a las 18.26.18

2nd Use Case – Create a Master-Detail relationship

Another common situation is the use case where we need to create two records related by a Master-Detail relationship.

With above code examples we can think that this is not a big deal, but we have to keep in mind that this Pig Scripts doesn’t provide handle errors on the current release, and if for any reason the header is not created and we try to create lines related to them, the process can fail without our knowledge (as we show before).

So how can we solve this situation? Salesforce advice is to create 2 scripts, so after running the one that create Headers, we can run another that will create records of my new custom object called Line__c.

Captura de pantalla 2015-11-16 a las 19.34.36

What can we find on above script?

  • First of all we look for all Headers that we have in the Organization right now.
  • Look for all Opportunity Lines we have in the Organization as well.
  • Execute a Join by Opportunity Id, as both, Header__c and OpportunityLineItem have this field.
  • Finally I will sort the joined result, because we don’t need all fields for my new Line__c registers.
  • And Store, save, the information in the custom object.

And this is the result:

Captura de pantalla 2015-11-16 a las 19.41.25

Yes, so simple. Something to keep in mind? List fields on Store in the same order as we have defined in the variable that we will use for the population.

But looking at this code, we can think, why don’t do it in the same script? Remember that the process is asynchronous, so by the time we query Header__c records, maybe they are not inserted yet in the organization.

Anything to highlight?

  • Salesforce Data Pipeline is still in Pilot so in order to use it you need to ask Salesforce to give you access to it.
  • When will it be GA? My latest news, Summer ’16 but as always, Safe Harbor.
  • Cost? Price? Yes, it will have an extra cost apart from the licenses, but I don’t have the information to tell you how much.
  • Advantages?
    • Salesforce ensures that these executions would be faster than other asynchronous processes like Batch Apex or @Future.
    • Running Apache Pig into Salesforce help us to do this execution in a multi-tenant environment. However if we run a process in Apache Pig outside of Salesforce, executions are for a single user.
    • As we are not using Apex, we will not hit governor limits.
    • We will be able to add these scripts into packages so our customers can also run these processes.
  • Disadvantages?
    • We cannot create scripts with more than 20 operators, 20 loads and 10 stores.
    • Although we will not hit governor limits, we need to keep in mind that Store (Insert / Update) is done via Bulk API, so any restriction still apply.
    • Unfortunately we cannot call Pig Scripts from Apex. Only from Developer Console and from API 33.0 onwards, during deployment.
    • It doesn’t offer a debug tool, so if we are in the first use case and a record is not inserted, it would not be easy to find the reason quickly.
    • You cannot handle errors easily, it means, you cannot add something in your code like try / catch.

But this is not all. If you want to know more about Data Pipeline, you can also look at the presentation that Carolina Ruíz and myself run at Dreamforce ’15. Find the video Data Pipelines: Big Data Meets Salesforce.

External Objects – What Lightning Connect offers to us

On my previous post, I talked about Lightning Connect and tried to explain with the Checa Hotel example how it worked.

This post is going to explain what you can do with one of the most important elements of Lightning Connect: External Objects.

What is an External Object?

This is a new type of object that will help us to visualize the information that we have in a external repository after creating a connection between Salesforce and this repo.

As a quick reminder from the previous post. We will be able to create an External Data Source linked to the External place and we will be able to create one or many External objects from there.

Captura de pantalla 2015-10-03 a las 19.00.55

How can we define it?

Captura de pantalla 2015-10-17 a las 11.35.08

These external objects will be created:

  • Automatically: via the Validate and Sync button that we can find in the External Data Source.
  • Manually: via its entry on the menu.

But in any case my advice is to take advantage of the automatic creation and use the manual one just in case you need to modify something.

How does an External Object look like?

We are going to continue with the same example as the previous post, the Checa Hotel reservations. And this is the external object.

Captura de pantalla 2015-10-19 a las 15.04.17

At a first sight it is similar to a custom one.

External Object vs Custom Object – Differences:

  1. API Name: It ends with __x instead of __c
  2. External Data Source: This field is populated with the External Data Source from where we have created the object. This field is required if you create the object manually.
  3. Table Name: This name is automatically created when you click on Validate and Sync button and is the name of the table found in the external repository once we have created the connection. This field is required if you create the object manually.
  4. Name Field: Here we will specify the field that will help us to open every single record when we create a tab related to this object. At least I couldn’t find a way to modify the value of this field, and the default value is the External ID standard field. However I can also say that if you create the connection via a Custom Connector instead of using Heroku, for instance, this value could be a different one. But this is something we will talk about in a future blog entry.
  5. All checkboxes that you can find on below image and belongs to a Custom object, here are missed. So we can now know that Reports are not provided. That could sound disappointing to some of you, but remember that this can change in the future, and also, you can always move this external object data to a custom object and create these reports and dashboards that you need.

Captura de pantalla 2015-10-17 a las 12.04.48

External Objects Sections:

Standard Fields

Captura de pantalla 2015-10-19 a las 15.08.41

I know what you are thinking. Where are the other fields like Created By, Last Modify By etc. ? Remember that these records till Summer’15 are not writable, so we don’t really need this information. We are just showing what we have in the external repository.

Here we will only find 2 fields:

  1. External ID: This field will help us to keep the uniqueness across the whole organization. This does not mean that the ID concept that Custom Object has are not applicable here. These records will also have an ID and we will see it later, but at the same time this External Id is required.
  2. Display URL: This is a link and if you click on it, in my case where I have read the information from the Google Spreadsheet, I will have the data in XML format of the record where I clicked this field.

Captura de pantalla 2015-10-17 a las 12.31.18

So, if we click on the Display URL field, we would get this information:

<?xml version='1.0' encoding='utf-8'?>
    <entry xmlns="http://www.w3.org/2005/Atom" 
           xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
           xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
           xml:base="http://<namehavebyheroku>.herokuapp.com/InMemoryProducerExample.svc/">
      <id>
         http://<namehavebyheroku>.herokuapp.com/InMemoryProducerExample.svc/HotelReservation(1)
      </id>
      <title type="text"/>
      <updated>2015-10-17T10:31:28Z</updated>
      <author>
          <name/>
      </author>
      <link rel="edit" title="HotelReservation" href="HotelReservation(1)"/>
      <category term="InMemoryProducerExample.HotelReservation" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
      <content type="application/xml">
          <m:properties>
               <d:StartDate m:type="Edm.DateTime">2015-09-01T00:00</d:StartDate>
               <d:Price m:type="Edm.Double">125.0</d:Price>
               <d:ExternalId m:type="Edm.Int32">1</d:ExternalId>
               <d:Paid m:type="Edm.Boolean">true</d:Paid>
               <d:EndDate m:type="Edm.DateTime">2015-09-03T00:00</d:EndDate>
               <d:GuestName>Anne Kalen</d:GuestName>
               <d:RoomNumber m:type="Edm.Int32">1</d:RoomNumber>
               <d:SpecialRequirement>Balcony please</d:SpecialRequirement>
          </m:properties>
     </content>
    </entry>

Custom Fields & Relationships

This is the section that looks like more similar to a custom object. Here we can find all the fields that the object will have. We will be able to define different types and different features. And if my Heroku application didn’t allow me to specify all that I really needed, I can make any change manually just clicking the Edit link beside the field.

Captura de pantalla 2015-10-17 a las 12.15.04

What could we miss?

We don’t see any relationship on above image, but we can really create Lookups for instance. What we would not allow to do is to create a Master-Detail relationship. But Salesforce give us a couple of workarounds to solve this situation.

  • External Lookup: This field type will help me to link 2 external objects, so if for any reason I have 2 different objects in my google spreadsheet and now I can see both in my Salesforce organization, I can link them via this field type that must be created manually because this is a Salesforce type that Java is not aware of it.
  • Indirect Lookup: This field type will help me to link an external object to a custom or standard one. Let’s talk more about this type with an example.

Captura de pantalla 2015-10-03 a las 20.12.08

Based on this image, I want to have somehow more information about my guests, in this case, Kim Rosenber. So that, I can save her information in order to send information about the hotel when we have special offers, or give her special discounts based on the number of reservations she has made with us. Because of that, I will create an Account per guest.

Captura de pantalla 2015-10-17 a las 13.03.29

Now, I would like to be able to click on my Guest Name in the HotelReservation record and go directly to the Account. Also I would like to be able to get all reservations related to each Account, so that, I can decide if this person deserves a special discount.

How can I get it? First of all we will need to create a field on Account object. The only requirement is that it should be External Id and it must be unique.

Captura de pantalla 2015-10-17 a las 13.26.29

Captura de pantalla 2015-10-17 a las 13.12.47

Secondly, we need to populate it with the information of my guest. This data should be the same as I have in the external object, so this time would be the name.

Finally on the External Object we need to modify the Guest Name field type from Text to Indirect Lookup and link it to Account object. As a tip, if for any reason, you don’t create the field on Account properly, it will not appear in the drop down list and you would not have the option to link your Hotel Reservation to Account.

Captura de pantalla 2015-10-19 a las 15.25.39And how does it look like?

Guest name has a link instead of being a simple Text field

Captura de pantalla 2015-10-17 a las 15.43.58

And if we add the related list in the Account object, we can also check all reservations that this person has made

Captura de pantalla 2015-10-17 a las 15.48.35

We could think that this is similar to usual Lookup fields. The main difference is that in this case I can click on the real Guest Name and navigate to the account. However, with a Lookup, we will need to have an Id value in the External Object in order to make the navigation possible.

Page Layout

Like custom objects, this section helps us to modify the look and feel of my record, changing the way that fields are sorted, if I want to add a new section, or blank space.

Captura de pantalla 2015-10-17 a las 12.15.54

Compact Layout and Search Layout

Simple, we have the option to create new Compact Layouts and determine if I require to add any custom button in the List View.

Captura de pantalla 2015-10-17 a las 12.16.23

Buttons, Links, and Actions

We can also perform another actions with these external objects. How? For instance, creating a button with some Apex Code in the background. At the end we could work with them as they were custom or standard objects.

Now, the use case is that every time a guest leaves the hotel, we need to print the invoice in pdf format.

Let’s think that we are doing this job for a custom object. So what should we do first?

  • Create a Custom Controller
public with sharing class HotelReservationController
{
   public ApexPages.StandardController controller;
 
   public Decimal amount {get; private set;}
   public Decimal totalAmount {get; private set;}
   public HotelReservation__x reservationInfo {get; private set;}
 
   public HotelReservationController(ApexPages.StandardController stdController)
   {
     controller = stdController;
     Id reservationId = controller.getRecord().Id;
     calculateReservation(reservationId);
     amount = calculateAmount(reservationInfo.Price__c);
     totalAmount = calculateTotalAmount(reservationInfo.Price__c);
   }
 
   public void calculateReservation(Id reservationId)
   {
     HotelReservation__x reservation = [Select EndDate__c, 
                                               GuestName__c, 
                                               Price__c, 
                                               RoomNumber__c, 
                                               StartDate__c 
                                         From HotelReservation__x
                                         Where Id = :reservationId
                                         Limit 1];
     reservationInfo = reservation;
   }
 
   public Decimal calculateAmount(Decimal amount)
   {
     return amount.setScale(2, RoundingMode.HALF_UP);
   }
 
   public Decimal calculateTotalAmount(Decimal amount)
   {
     Decimal tax = (amount * 21) / 100;
     Decimal totalAmt = amount + tax;
     return totalAmt.setScale(2, RoundingMode.HALF_UP);
   }
}

As you can see on above code, the controller is really simple. It starts getting the Id of the record so YES!! we can also use getRecord() method with External Object.

And continue doing some calculations. The most important thing is the method where we run a SOQL query. HOW?? Yes, even we don’t have any data stored in our organization, Lightning Connect will allow us to perform such actions as well as SOSL. Also I would like to highlight that even we filter by the Id that we retrieved from the Controller, we would be able to use the External ID field as this is also have a unique field value.

  • Create a Visualforce page

My Visualforce page will be a pdf with the invoice for the guest. First of all the Standard Controller will be the External Object. And secondly we will extend the functionality with the Controller that we created above. The rest, simple, just call Controller methods and fields in order to show data that we need.

Captura de pantalla 2015-10-20 a las 8.30.28

So, is it not allowed to use visualforce tags like <apex:outputField> ? Of course you can use them. Imagine you want to create a Visualforce page with some Reservation data, go for it!! it will show the name of the field as well as the type that belongs to the data. However as this is a pdf, my option was to use directly divs with all data.

  • Create a button linked to the Visualforce page that we have just created and add it to the External Object Page Layout.

Captura de pantalla 2015-10-17 a las 16.02.53

At the end, this is the result. After clicking on the Invoice Print Invoice button

Captura de pantalla 2015-10-17 a las 16.54.35

We get this pdf ready to print and share with the customer

Captura de pantalla 2015-10-17 a las 16.53.14

Field Sets

We can also create a field set related to our External Object and show it in a Visualforce page, for instance.

My field set will not provide different information from the current page layout, but this is a good example to show how Field Sets also works.

First of all we will create the Field Set

Captura de pantalla 2015-10-17 a las 17.15.50

Secondly we are going to create a Visualforce page that we will use to override View mode on this External Object.

<apex:page standardController="HotelReservation__x" extensions="HotelReservationController">
  <apex:form >
    <apex:pageBlock title="Hotel Reservation">
      <apex:pageBlockSection title="Information">
        <apex:repeat value="{!fields}" var="f">
          <apex:outputField value="{!HotelReservationFieldSet[f.fieldPath]}"/>
        </apex:repeat>
      </apex:pageBlockSection>
    </apex:pageBlock>
  </apex:form> 
</apex:page>

Similar as before we will use the HotelReservation__x as standard controller and the extension will be the same as before. This time we are going to show dynamically all fields that we have included in the FieldSet. As right now we can find all of them, this is a good page to override the view mode of any Hotel Reservation record. If in the future we need to include more fields or make some modifications, code will be exactly the same, because, as I said before, we get data dynamically.

In the controller we have just added these 2 methods and their calls in the constructor:

public List<Schema.FieldSetMember> getFields()
{
  return SObjectType.HotelReservation__x.FieldSets.ReservationInformation.getFields();
}
 
public HotelReservation__x calculateReservationFieldSets(Id reservationId)
{
  String qry = 'Select ';
  for(Schema.FieldSetMember f : getFields())
  {
    qry += f.getFieldPath() + ', ';
  }
  qry += 'Id, ExternalId From HotelReservation__x Where Id = :reservationId limit 1';
  return Database.query(qry);
}

And this is the result

Captura de pantalla 2015-10-18 a las 8.41.03

What else can I do?

If you are one of these persons that usually works with portable devices like tablets and smartphones, you don’t need to worry about this new type of objects because Salesforce1 app and Lightning Connect also allow you to see this data.

IMG_0305

IMG_0306

Limitations

Finally I would like to highlight some limitations (based on Summer ’15 release)

  • We can only have 100 External Objects per org
  • It doesn’t allow Master-Detail relationship, but as we show above, Lightning Connect offers 2 workarounds, External Lookups and Indirect Lookups
  • We cannot create reports and dashboards with their information. If this is really required for us we can always move the data to a custom object using some apex code, and then create the report from this object.
  • Triggers are not allow. I think that the reason is that actually we are not able to control what can happens outside of Salesforce.
  • Although we can perform SOSL and SOQL, we still have some limitations, like For Update is not allow today.
  • These objects are read only. It means, we cannot edit it and see the change in my google drive, for instance. I have already realized that Winter ’16 give us this functionality, but this is something that I will talk about in a future entry after doing some more researches.

I hope this post was useful for you and understand better what you can do with these new object types and how.

Snippet about my Dreamforce ’15 sessions

Dreamforce is the most important conference about Salesforce around the world, I’m sure that you already know about it, but if not, look at my first blog entry talking about my experience on such amazing place.

Do you go to Dreamforce’15 this year?

If not, don’t be upset. You can follow it in streaming and start thinking about a good strategy to be there next year. This article is quite useful to convince your manager to send to you 🙂

However, if you answer is yes, then …. I’m looking forward to knowing you in person!!! How can we do it?

Maybe we are lucky and meet in Moscone West center. But this is a big place, so maybe it is difficult to find each other. But I have an idea. What about if you register to attend my sessions?

1. Apex Connector for Lightning Connect – Make anything a Salesforce object

When? Tuesday 15th of September, 4.30pm

I’m sure you already know that in order to read an external repository and show that data in real time in your Salesforce org, you can use Lightning Connect. But how? First of all we need to create a connection, and this could be done by an existing OData provider or create it via OData protocol, Java and Heroku, for instance.

But since Summer ’15 we have a third option, use Apex Connector Framework that would help us to do this job just using Apex and all integrated in Force.com.

What should I do in order to create my connection in Apex? It is really simple. You will only need 2 classes.

Below image shows you a skeleton of the first one, the Connector, and how I need to override 3 methods:

Captura de pantalla 2015-08-10 a las 14.42.39

This second image will help you to understand how is the second class, the Provider where we also have to override 3 methods:

Captura de pantalla 2015-08-10 a las 14.43.20

Do you want to know more about that? Don’t miss my session. Remember, Tuesday 15th of September, Moscone West, at 4.30pm.

Will you not be able to attend? Don’t worry, Salesforce always publish sessions, so I will add a link to mine as soon as it is ready. Also don’t forget to follow my blog as I’m planning a new entry talking about Apex Connector.

2. Data Pipelines – Big Data meets Salesforce

When? Thursday 17th of September, 1.30pm

Actually I will share this session with the MVP Carolina Ruiz (@carolenlanube), and she will post an entry with some explanations about it on her blog soon. So follow Carol Code and Vogue and don’t miss it.

But as a quick summary, Data Pipeline is a feature that is under pilot program and helps to integrate Apache Pig and Salesforce. Having that, we will be able to execute Pig Scripts via the Developer Console, for instance, and process large amount of data asynchronously and in parallel.

Also, another advantage is the performance, that is much better than any other asynchronous feature that Salesforce offers to us right now.

Does it sound really cool? Yes, it is!! So don’t miss the chance to look us in action and show you how to create a Pig Script and get advantage of this pilot.

Remember!! 17th of September, 1.30pm Moscone West center.

See you there!!!

Salesforce Trailheads – What’s new?

Since Salesforce released Trailheads, I have been looking for a good opportunity to write about them, and I think today is the day.

First of all, what are Trailheads? It’s a new and funny way to learn more about Salesforce. You can find different modules that help you to go step by step and know more about an specific topic. For instance, Formulas & Validations, will explain you what is a formula, how to create them, different use case to use them in a really easy way. You can just read the notes the trailhead offers, watch a video to understand better some parts of the functionality, and finally, a challenge is offered to you, so you can see if you really have understood what you have read.

And now you can think, and why do you say this is so fun? Because after completing every challenge, you can win some points and if you complete a whole trail, you get a badges, so at the end you can feel like Mario Bros jumping to get some coins.

Captura de pantalla 2015-08-06 a las 17.24.16

Trailheads are divided by role (Administrator, Developer) as well as knowledge level (Beginner and Intermediate). But if you are looking for a specific module, Salesforce also offers the Module option, where you can select the option that helps you to increase your skills, maybe Apex Testing, or Triggers. Just choose the best for you.

Finally, if you think you know quite good different features of Salesforce, you also have the chance to check it with the Project option. For instance, Quick Start: Lightning Process Builder project.

So now it is your turn to decide how you can start!!

Captura de pantalla 2015-08-06 a las 17.19.13

I have already completed one of the newest Trails, Dreamforce one, and I really recommend to you if you are planning to attend it, and most of all, if this is your first time. Last year was my first Dreamforce ever and such kind of reading could be very valuable for me.

What you can find on Dreamforce Trail?

There are 3 sections:

Get Ready for Dreamforce

Where you can read about the whole event, what you can expect and see, how you can register, help you to develop your strategy for the whole week. A really high level instructions about Dreamforce.

Admin and Developers

Ok, Partners are important, customer are really important and there are lot of spaces for them, but what about those who works every single day with the platform? Salesforce doesn’t forget us and there is a big space for Administrators and Developers. On this section you can get some information about what your role could learn as well as how having fun at Dreamforce.

Maximize your Experience

Finally on this section you can find lot of tips like wear the most comfortable shoes you have.

But one of my favorites advices is bring pen and paper. And now you think,

Really? We are technicals!! We have lot of devices that we can use!!

But can you always trust on them? Think about this use case. You are in a session and try to take some notes. Switch on your laptop and …. no battery!! There are lot of places where you can charge it, but no plug closer to you. Ok, you have your smartphone, so you can take some notes. Have you disabled autocomplete feature? I’m Spanish so every time I try to write “brings” the autocomplete feature writes “brigada” that means squad, so remove it and try again … “brigada” again!!! Ok , it doesn’t matter, take a picture of the slide …. speaker was faster than myself and now he is explaining another thing. So bring (instead of brigada) an agenda and take quick notes about whatever you want.

But please, go section by section of this Trail and discover everything by yourself. Again, this is a must read before Dreamforce ’15.

Would I like to add anything else?

As the Trail said, you can feel overwhelmed by the time you go into the Moscone center and sadly you cannot clone yourself, so I’m completely sure you will miss something, but don’t feel upset. It happens to everybody. Because of that you need to develop your strategy and the first section of the Trail gives you a good example of different things you should do, but it doesn’t match with exactly anything in the real agenda, so if this is your first time, you can be a bit confused.

This is my opinion as developer:

  1. There are some Workshops that helps you to train your skills, start developing new functionality or learn about new features. That’s the first thing you have to look for and register as soon as the Agenda is released because places are really limited, so don’t doubt and join to a couple of them.
  2. Think about what is the most existing thing you have worked or heard during the last year. Look for a couple of sessions about it!! It could be Breakout sessions (40 minutes) or 30 minutes sessions on Dev Zone. It doesn’t matter, I’m sure both will be useful for you.
  3. Attend a couple of keynotes, and one must be Developer keynote. I’m sure they will make a big announcement about something really special and amazing for next year. During DF’14 they talked about Lightning, and today this is a common word on our vocabulary. Once it is finished, check sessions again and look for any related to latest announcement!! I’m sure there will be some seats waiting for you and be one of the first to know more about it.
  4. Look for a single session related to a topic that you already know and you are used to work on it. Sometimes, the fact of listening what someone else has to say about it, can give you another perspective of  a feature / product / language, etc.

At this point we could have:

  • 2 workshops
  • 2 sessions about a topic you are interested to attend
  • 2 keynotes
  • 2 new sessions from keynotes
  • 1 session about a well known topic

Do you think 9 sessions are not too many? Go ahead and schedule some others, but don’t feel very stressed about it. Book also some free time for yourself to walk around the Moscone center and some other areas, sitting down and think about the last session. Talk with someone at Community Lounge or at MVP area!! Do you know that all your super heroes would be around there? Don’t miss the opportunity to know them and resolve your questions!!

And above all, have fun!!! See you at Dreamfoce ’15.

Mi primera Visualforce

This entry will talk about how to start working with Visualforce and Apex. We can find thousand of blogs in English that talk about this topic, however it is more difficult to find information in Spanish. Because of that, this entry will be in my home language so it will try to help Salesforce newbies in my country.

Esta será la primera de una serie de entradas que hablarán sobre Visualforce y Apex. Escribir una única entrada contando todo lo que me gustaría compartir, podría llegar a ser un post difícil de seguir, ó incluso llegar a aburrirte cerrando la ventana antes de terminar, y eso es lo que quiero evitar.

Aunque la entrada está escrita en Español, seguiré usando los términos ingleses por si tu entorno está en ese idioma.

Comencemos por el principio. Una vez que ya tienes tu entorno (org) Salesforce te ofrece ya algunos objetos que llamamos Standard. Dependiendo de la organización que tengas, podrás acceder a unos u otros, pero en principio tendrás acceso por lo menos a Accounts y Opportunities, así que vamos a utilizar esto dos objetos para los casos prácticos.

Cómo puedes leer en esta entrada, Salesforce se basa en el patrón MVC – Modelo Vista – Controlador. Cuando un usuario interactúa con una página, cualquier acción se manda al controlador el cual se encarga de ejecutar el proceso que la acción necesita con la ayuda del Modelo, y cuando éste finaliza, devuelve a la página el resultado para que lo pueda mostrar. Esto se puede hacer de dos formas, utilizando la funcionalidad Standard y la Custom. Recuerda estas dos palabras porque vamos a hacer referencia a ellas en muchos sitios.

  • ¿Qué significa Standar? Todo aquello que Salesforce te ofrece y puedes utilizar sin añadir una sola línea de código.
  • ¿Qué significa Custom? Si lo que Salesforce te ofrece no es lo que necesitas, lo puedes modificar. Para ello Salesforce te ofrece la posibilidad de hacerlo con sólo clicks de ratón, ó usando Apex y Visualforce.

Todo objeto en Salesforce, ya sea Standard ó Custom (el que creas tú con clicks de ratón) ofrece una vista que puedes utilizar en tu aplicación. Este es un ejemplo de un registro del objeto Account.

Account Record

Esta vista se puede modificar sin una línea de código. ¿Cómo? Edita el Page Layout del objeto hasta conseguir el look and feel que desees.

  • Si es un objeto Standar, cómo Account, ve a Setup | App Setup | Customize |  | Page Layout
  • Si lo has creado tú, es decir, es un objeto Custom, ve a Setup | App Setup | Create | Objects . En esta página, selecciona tu objeto y busca la sección Page Layout

Pero como hemos dicho anteriormente, puede que necesites algo más que ordenar los campos en el Page Layout del objeto.

Para ello crearemos una página visualforce que llamaremos accountview ya que nos servirá para mostrar los datos de la cuenta en modo lectura.

Esta página la enlazaremos con un controlador, y al igual que antes, todo objeto, Standard y Custom tiene su propio Controlador Standard y para usarlo, sólo tenemos que indicar el API name del object que vamos a usar. Posteriormente añadiremos una cuantas secciones con los tags pageBlock (para definir la cabecera la página) y pageBlockSection (nos ayuda a definir una sección) NOTA: podemos añadir tantos bloques y secciones en nuestra página, aunque lo más normal suele tener un único bloque con múltiples secciones.

<!-- accountview -->
<apex:page standardController="Account">
    <apex:form>
        <apex:pageBlock title="Vista Cuenta">
            <apex:pageBlockSection title="Campos Cuenta">
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>     

¿Cómo lo visualizamos en nuestro entorno? Simplemente tendremos que añadir a la URL /apex/, en nuestro caso: https://c.eu2.visual.force.com/apex/accountview y este es el resultado: Captura de pantalla 2015-02-08 a las 14.06.29 Nuestro siguiente paso será añadir campos a la sección Campos Cuenta utilizando el tag outputField. Vamos a crear una página con una apariencia similar a la que nos ofrece Salesforce, pero este ejemplo te puede ayudar a empezar a buscar cómo conseguir el look and feel que realmente quieres. Revisa los links que ofrezco para saber más de los tags que utilizamos en estos ejemplos. Todos ofrecen distintos atributos para personalizar la vista de la página.

<!-- accountview -->
<apex:page standardController="Account">
    <apex:form>
        <apex:pageBlock title="Vista Cuenta">
            <apex:pageBlockSection title="Campos Cuenta">
                <apex:outputField value="{!account.name}"/>
                <apex:outputField value="{!account.site}"/>
                <apex:outputField value="{!account.type}"/>
                <apex:outputField value="{!account.accountNumber}"/>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Y si volvemos a refrescar la página, vemos como en la sección Campos Cuenta aparece lo que hemos añadido, el Nombre, Tipo, Site y Número de Cuenta.

Captura de pantalla 2015-02-08 a las 14.13.08

Viendo esta imagen nos pueden surgir dos dudas.

  1. ¿Por qué el nombre de los campos viene en inglés? Porque estamos usando el controlador Standard de objeto Account, y la llamada account. traerá la etiqueta que hemos definido para ese campo. Mi entorno está en inglés, de ahí el obtener Account Name en vez de Nombre de Cuenta.
  2. ¿Por qué sólo veo la etiqueta de los campos y no el valor? Para poder mostrar los valores, debemos indicarle qué cuenta quiero mostrar. Salesforce asigna un identificador único (15 ó 18 caracteres) a todos sus registro. Es lo que llamaremos Id. Si añadimos ese id al final de la URL, le estamos diciendo a Salesforce que queremos ver la información relacionada a ese registro.
    1. ¿Cómo obtenemos este Id? Muy fácil, si abrimos el registro que queremos, pero usando su vista Standard, la URL nos lo proporciona.

Captura de pantalla 2015-02-08 a las 15.03.03

Después, podemos usar ese Id en nuestra nueva URL quedando así: https://c.eu2.visual.force.com/apex/accountview?id=001b000000Cw7X8 

Captura de pantalla 2015-02-08 a las 15.06.23

Podría seguir contándoos más cosas sobre las páginas Visualforce, pero creo que por hoy os he dado bastante información. En futuros post partiremos de este ejemplo para complicar la personalización de esta página.

Mi recomendación antes del próximo post:

  1. Lee y asimila cómo funciona el Modelo Vista Controlador de Salesforce.
  2. Familiarízate con los objetos Standard, su campos, sus Page Layout, etc.
  3. Crea algún objeto custom por ti mimo.
  4. Crea tu primera página Visualforce usando el Controlador Standard.
    1. Investiga los tags de hoy:
      1. apex:page
      2. apex:form
      3. apex:pageBlock
      4. apex:pageBlockSection
      5. apex:outputField

Hasta la próxima!!