Lightning Connect 101

To introduce developers in my Salesforce developer classes to Lightning Connect (aka External Objects) I have created an exercise to make a simple one from scratch to a public oData service – ‘Northwind’.

Lightning Connect allows a Salesforce org to ‘Connect and access data from external sources with point and click simplicity. Incorporate data from legacy systems (SAP, Oracle, Microsoft, you name it) in real time in Salesforce application objects. Dramatically reduce integration time to unlock and modernize back-office systems.’ (See ‘How you integrate‘)

All this means is that we can query data not stored in our org just like we would query for data in our org. Anyone I have shown this to is as impressed with this as I was when I saw it at Dreamforce 14.

Exercise Steps:

  1. Login to a Developer Edition org.
  2. Navigate to Setup | Develop | External Data Sources

Screen Shot 2015-01-12 at 21.43.43

  1. New External Data Source
    Label: Northwind
    Name: Northwind
    Type: Lightning Connect: Odata 2.0
    Server URL:
    Format: JSON

Screen Shot 2015-01-12 at 22.12.46

  1. Save the External Data Source
  2. Click ‘Validate and Sync’ on the External Data Source. This process interogates the external data source model retrieving all tables we can query.
  3. Check the First Checkbox in the first column – selects all tables available in the Northwind remote data model.
  4. Click ‘Sync’. This will now generate external objects on our org.
  5. The list of External Objects is now displayed with fields corresponding to the tables and columns in the external data source.
  6. Click the ‘Invoices’ link to view the External Data Object definition. Note the API name of the sobject is ‘Invoices__x’ denoting an external object. Note the field names end in ‘__c’.
  7. Open the Developer Console via Name | Developer Console
  8. Click the Query Editor tab and enter (and run) the query
SELECT Country__c, CustomerName__c, ProductName__c, Quantity__c, UnitPrice__c
FROM Invoices__x
WHERE Country__c = 'Ireland'

The data returned is queried from the external source.

  1. Now let’s create a Visualforce Page and Controller to view all invoices for Ireland. We will also paginate the results using a StandardSetController.
  2. Create an Apex class called ‘Northwind_pagination’ with the following code:
public with sharing class Northwind_pagination {
    Public Integer noOfRecords{get; set;}
    Public Integer size{get;set;}
    public ApexPages.StandardSetController setCon {
            if(setCon == null){
                size = 10;              
                List<Invoices__x> accs = [SELECT Country__c, CustomerName__c, ProductName__c, Quantity__c, UnitPrice__c 
                FROM Invoices__x 
                WHERE Country__c = 'Ireland'];
                setCon = new ApexPages.StandardSetController(accs);
                noOfRecords = setCon.getResultSize();
            return setCon;
    Public List<Invoices__x> getInvoices(){
        List<Invoices__x> accList = new List<Invoices__x>();
        for(Invoices__x a : (List<Invoices__x>)setCon.getRecords())
        return accList;
    public pageReference refresh() {
        setCon = null;
        return null;


  1. Now create a Visualforce page with the following code:
<apex:page controller="Northwind_pagination">
<apex:form >
        <apex:pageBlock id="pb" title="Northwind Invoices for Ireland">
            <apex:pageBlockTable value="{!Invoices}" var="a">
                <apex:column headerValue="Country" value="{!a.Country__c}"/>
                <apex:column headerValue="Customer Name" value="{!a.CustomerName__c}"/>
                <apex:column headerValue="Product" value="{!a.ProductName__c}"/>
                <apex:column headerValue="Quantity" value="{!a.Quantity__c}"/>
                <apex:column headerValue="Unit Price" value="{!a.UnitPrice__c}"/>
            <apex:panelGrid columns="7">
                <apex:commandButton status="fetchStatus" reRender="pb" value="|<" action="{!setCon.first}" disabled="{!!setCon.hasPrevious}" title="First Page"/>
                <apex:commandButton status="fetchStatus" reRender="pb" value="<" action="{!setCon.previous}" disabled="{!!setCon.hasPrevious}" title="Previous Page"/>
                <apex:commandButton status="fetchStatus" reRender="pb" value=">" action="{!}" disabled="{!!setCon.hasNext}" title="Next Page"/>
                <apex:commandButton status="fetchStatus" reRender="pb" value=">|" action="{!setCon.last}" disabled="{!!setCon.hasNext}" title="Last Page"/>
                <apex:outputText >{!(setCon.pageNumber * size)+1-size}-{!IF((setCon.pageNumber * size)>noOfRecords, noOfRecords,(setCon.pageNumber * size))} of {!noOfRecords}</apex:outputText>
                <apex:commandButton status="fetchStatus" reRender="pb" value="Refresh" action="{!refresh}" title="Refresh Page"/>
                <apex:outputPanel style="color:#4AA02C;font-weight:bold">
                    <apex:actionStatus id="fetchStatus" startText="Fetching..." stopText=""/>

15. Preview the Visualforce page to see the list of invoices for Ireland.

Screen Shot 2015-01-12 at 23.42.06

There is a add-on fee for this service to use it in a Production org – based per annum per endpoint (please speak to your account manager) – but the power of this connector will eliminate the need to do a lot of development and maintenance on SOAP and REST callouts from your Salesforce org.

Lightning Connect is GA as of the Winter 15 release.