Using Apex to Work with Salesforce Records
The term sObject refers to any object that can be stored in Lightning Platform. This could be a standard object, such as Account, or a custom object that you create, such as a Merchandise object.
An sObject variable represents a row of data, also known as a record. To work with an object in Apex, declare it using the SOAP API name of the object. For example:
1Account a = new Account();
2MyCustomObject__c co = new MyCustomObject__c();For more information on working on records with Apex, see Working with Data in Apex.
This example controller persists an updated Account record. Note that the update method has the @AuraEnabled annotation, which enables it to be called as a server-side controller action.
1public with sharing class AccountController {
2
3 @AuraEnabled
4 public static void updateAnnualRevenue(String accountId, Decimal annualRevenue) {
5 Account acct = [SELECT Id, Name, BillingCity FROM Account WHERE Id = :accountId];
6 acct.AnnualRevenue = annualRevenue;
7
8 // Perform isAccessible() and isUpdateable() checks here
9 update acct;
10 }
11}Differences Between Lightning Data Service and Apex
The lightning:record*Form and force:recordData components are the easiest way to work with records. They are built on top of Lightning Data Service, which manages field-level security and sharing for you in addition to managing data loading and refresh. You can use these components for objects that are supported by User Interface API
Use Apex only if you’re working with a scenario listed at Using Apex, You can call the Apex method imperatively, such as in response to a button click, as shown in the Loading Record Data from a Standard Object section. Alternatively, to load record data during component initialization, use the init handler, as shown in the Loading Record Data By Criteria section. When using Apex to load or provision data, you must handle data refresh on your own by invoking the Apex method again.
Loading Record Data from an Object
Load records from an object in an Apex controller. The following Apex controller has methods that return a list of tasks. Task is an object that isn’t supported by Lightning Data Service and the User Interface API. Therefore, we recommend using Apex to load task record data.
1public with sharing class TaskController {
2
3 @AuraEnabled(cacheable=true)
4 public static List<Task> getTasks() {
5 return [SELECT Subject, Priority, Status FROM Task]; }
6}1<!-- apexForTasks.cmp -->
2<aura:component implements="flexipage:availableForAllPageTypes" controller="TaskController">
3 <aura:attribute name="tasks" type="Task[]"/>
4 <lightning:card iconName="standard:task">
5
6 <lightning:button label="Get Tasks" onclick="{!c.getMyTasks}"/>
7 <aura:iteration var="task" items="{!v.tasks}">
8 <p>{!task.Subject} : {!task.Priority}, {!task.Status}</p>
9 </aura:iteration>
10
11 </lightning:card>
12</aura:component>1// apexForTasksController.js
2({
3 getMyTasks: function(cmp){
4 var action = cmp.get("c.getTasks");
5 action.setCallback(this, function(response){
6 var state = response.getState();
7 if (state === "SUCCESS") {
8 cmp.set("v.tasks", response.getReturnValue());
9 }
10 });
11 $A.enqueueAction(action);
12 }
13})Loading Record Data By Criteria
As we’ve learned, to load a simple list of record data, you can use base components or force:recordData, as shown at Loading a Record. But to use a SOQL query to select certain records, use an Apex controller.
Remember that the method must be static, and global or public. The method must be decorated with @AuraEnabled(cacheable=true).
For example, query related cases based on an account Id and limit the result to 10 records.
1public with sharing class CaseController {
2 @AuraEnabled(cacheable=true)
3 public static List<Case> getCases(String accountId) {
4 return [SELECT AccountId, Id, Subject, Status, Priority, CaseNumber
5 FROM Case
6 WHERE AccountId = :accountId LIMIT 10];
7 }
8}The client-side controller loads related cases using the init handler. The action.setParams() method passes in the record Id of the account record being viewed to the Apex controller,
1// casesForAccountController.js
2({
3 init : function(cmp, evt) {
4 var action = cmp.get("c.getCases");
5 action.setParams({
6 "accountId": cmp.get("v.recordId")
7 });
8 action.setCallback(this, function(response){
9 var state = response.getState();
10 if (state === "SUCCESS") {
11 cmp.set("v.cases", response.getReturnValue());
12 }
13 });
14 $A.enqueueAction(action);
15 }
16})- Query the relevant cases and set the result to the component attribute v.cases.
- Iterate over the cases by passing in the case Id to the recordId attribute on lightning:recordEditForm.
1<!-- casesForAccount.cmp -->
2<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" controller="CaseController">
3 <aura:attribute name="cases" type="Case[]"/>
4 <aura:attribute name="recordId" type="Id" />
5 <aura:handler name="init" value="{! this }" action="{! c.init }"/>
6
7 <aura:iteration items="{!v.cases}" var="case">
8 <lightning:card title="{!case.Id}" iconName="standard:case">
9 <lightning:recordEditForm objectApiName="Case" recordId="{!case.Id}">
10 <lightning:inputField fieldName="Subject"/>
11 <lightning:inputField fieldName="Status"/>
12
13 <!– Read-only field -->
14 <lightning:outputField fieldName="Origin" variant="label-hidden"/>
15
16 <lightning:button label="Update case" type="submit"/>
17 </lightning:recordEditForm>
18 </lightning:card>
19 </aura:iteration>
20</aura:component>For read-only data, use lightning:outputField. To work with read-only data only, use lightning:recordViewForm or lightning:recordForm. For granular control of your UI, use force:recordData. For more information, see Lightning Data Service.