0% encontró este documento útil (0 votos)
51 vistas17 páginas

Fundamentos de Apex y SOQL en Salesforce

Este documento proporciona una introducción a los conceptos básicos de Apex y SOQL, incluyendo sintaxis de control de flujo, declaración de clases y métodos, tipos de datos, colecciones y consultas. También cubre temas como declarar y manipular objetos sObject, DML, relaciones entre objetos, consultas anidadas y funciones agregadas.

Cargado por

Osiris Fernandez
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
51 vistas17 páginas

Fundamentos de Apex y SOQL en Salesforce

Este documento proporciona una introducción a los conceptos básicos de Apex y SOQL, incluyendo sintaxis de control de flujo, declaración de clases y métodos, tipos de datos, colecciones y consultas. También cubre temas como declarar y manipular objetos sObject, DML, relaciones entre objetos, consultas anidadas y funciones agregadas.

Cargado por

Osiris Fernandez
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

// comentar

/**/ comentar varias lineas

|| OR

&& AND

Integer, Decimal, String, Boolean, Id TIPOS DE DATOS

System.debug(); Para monitorear el cambio de una variable o lista

Lists, Sets, Maps Colecciones de Salesforce

Las listas son ordenadas y los sets no

Maps son colecciones de records con keys value-key

String[] groceries = new String[4]; DECLARACION DE LISTA CON VALORES FIJOS O ARRAY

List<String> nombrelista = new List<String>(); DECLARACION DE LISTA DINAMICA

nombrelista.add(indexopcioonal,tipdedatoquequierameter); AÑADIR VALORES A LA LISTA

SINTAXIS IF

if(condition is true) {

//do this

}else if(condicion2){

//do this if condicion2

} else {

//do this si otra cosa que no sea c1 o c2

SINTAXIS DEL SWITCH

switch on expression {

when value1 { //single value

//code block 1

when value2, value3 { //multiple values

//code block 2

SINTAXIS DEL WHILE

While(mientrascondicion) {
//correr esto

SINTAXIS DO WHILE

Do {

//run this block of code

} while(seguirmientrascondicioncumpla)

DECLARAR CLASE:

public class nombredelaclase {

DECLARA METODO

public static void nombredelmetodo(parametros){

Un sObject es un datatype que corresponde a un objeto de Salesforce.

DECLARA sOBJECT

Account nombredelacuenta = new Account();

para usar el metodo de asignar el nombre a la cuenta:

nombredelacuenta.Name = 'The Tea Factory';

LENGUAJE DML(DATA MANIPULATION LENGAUGE)

 insert
 update
 upsert
 delete
 undelete
 merge

Cada metodo de estos acepta un solo record o una lista de ellos.

Por ejemplo:

insert nombredelobjeto; lo agrega a la base de datos


EJEMPLO DE CLASE QUE CREA ACCOUNT Y LA AGREGA
public class NewAccounts {
public static void sObjectsInsert(){
Account store = new Account();
store.Name = 'The Tea Factory';
store.AccountNumber = '356281';
store.Phone = '555-0158';
insert store;
}
}
Y en la Anonymous ósea en la consola:
NewAccounts.sObjectsInsert(); llamamos el metodo

EJEMPLO DE CLASE QUE CREA ACCOUNTS Y LAS AGREGA


public class NewAccounts {
public static void sObjectsInsert(Integer value){
Integer counter = 1;
//create a list to add our accounts
List<Account> teaFactoryAccounts = new List<Account>();
while(counter <= value){
//display the current counter value
System.debug('Counter Value before Incrementing ' +
counter);
//create a new account
Account store = new Account();
store.Name = 'The Tea Factory ' + counter;
store.AccountNumber = '35629' + counter;
teaFactoryAccounts.add(store);
System.debug(teaFactoryAccounts);
//increment the counter
counter = counter + 1;
System.debug('Counter Value after incrementing ' +
counter);
}
System.debug('Size of Account List: ' +
teaFactoryAccounts.size() );
System.debug('Elements in Account List: ' +
teaFactoryAccounts);
//insert all of the accounts in the list
insert teaFactoryAccounts;
}
}

Y en el Debug | Open Execute Anonymous Window:

NewAccounts.sObjectsInsert(3); 3 o el número que queramos

MAP Acepta valores duplicados igual que list, lo que no acepta son mismas
keys. Y puede tener diferentes datatypes.

Set no acepta valores duplicados y no tiene orden. Pero al igual que lista son del mismo
datatype.

Para agregar valores a un MAP:

Nombredelmapa.put(key,valor);

Para acceder a un valor de un MAP:

Nombredelmapa.get(key);

EJEMPLO DE MAP
public class Tea{
public static void orderTea(){
Map <String, String> teaTypes = new Map <String, String>();
teaTypes.put('Black', 'Earthy');
teaTypes.put('White', 'Sweet');
teaTypes.put('Herbal', 'Sweet');
system.debug(teaTypes);
}
}

FOR LOOP
1. for(Integer i = 0; i < 5; i++){

2. System.debug('The number is ' + i );

3. }

1) For loops are used when you know how many times the loop should run. If you want
the loop to stop based on a condition other than the number of times it runs you
should use the while loop.
2) For loops are more concise because they keep the three parts—the variable, the
condition, and the increment—together in one statement.

FOR LOOP IN COLLECTIONS


for ( tipodedato nombrevariablecontadora: nombredelistaoset){
}
EJEMPLO DE LOOP EN LIST
List <String> tea = new List<String>{'Black Tea', 'Green Tea', 'Chai
Tea'};

for(String t : tea){

System.debug('We have ' + t);

SOQL (Salesforce Object Query Language)

SELECT y FROM son las clauses requeridas

SIEMPRE SE USAN LAS API NAMES PARA REFERIR A LOS RECORDS(NO SE USAN LOS LABEL).

SELECT loscamposquesean FROM losobjetosquesean WHERE condición

Después del WHERE se puede usar los operadores AND, OR e IN si hay más de una
condición

IN

El IN se usa para simplificar lo que de otra manera serian muchos OR. Devuelve valores de
una lista o set.
SELECT Name, Email FROM Contact
WHERE LastName IN ('James', 'Barr', 'Nedaerk', 'Forbes')

LIMIT

The LIMIT keyword sets the maximum number of records to return. 

FROM Contact LIMIT 5

ORDER BY

El ORDER BY también va después de del where y ordena los resultados de 3 formas.


ORDER BY campo ASC(ascendente) DESC(descendente) NULLS LAST/FIRST(valores nulos)

QUERIES EN APEX

Para asignarle los valores de una consulta a una lista encerramos la consulta en [ ] e igualamos
la lista = [la query] y punto y coma.
List<Contact> nombredelalista = [SELECT FirstName, LastName FROM Contact];

Para especificar un field de un objeto se usa

objeto.field

String targetDepartment = 'Wingo';


Contact[] techContacts = [SELECT FirstName,LastName
FROM Contact WHERE
Department=:targetDepartment];

QUERIE DE OBJETO PADRE E HIJO

DE HIJO A PADRE
SELECT Name, Account.Name FROM Contact

En el select ponemos el

Objetopadre.elcampoquequeremos FROM Objeto hijo

DE PADRE A HIJO
Para haces un padre hijo tenemos que hacer una subquery para el hijo dentro de la main
query.

SE USA EL NOMBRE DE HIJO DEL OBJETO HIJO EN ESTA CASO CONTACTS Y NO SU NOMBRE API
CONTACT
SELECT Name, (SELECT Name FROM Contacts) FROM Account WHERE Id IN
(SELECT AccountId FROM Contact WHERE LastName = 'Forbes')
Primero va a la subquery del where, después al where en si y después a
la subquery en los fields y después repite por cada uno.

The API name for a custom object is the custom object name with __c [underscore
underscore c] added at the end. Los standard no.

QUERY A UNA LOOKUP RELATIONSHIP CHILD TO PARENT

En este caso Property es hijo y Broker es padre.

1. SELECT Address__c, Picture__c, Broker__r.Name FROM Property__c

Se usa Brooker__r.Name
QUERY A UNA LOOKUP RELATIONSHIP PARENT TO CHILD

1. SELECT Name, (SELECT Address__c, Price__c FROM Properties__r) FROM


Broker__c

BIND VARIABLE usa :

Integer maxHomeValue = 200000;

List<Property__c> property = [SELECT Name, Price__c FROM Property__c

WHERE Price__c < :maxHomeValue];

COUNT() Returns the number of SELECT COUNT(Name) FROM Broker__c


rows that are associated
with the field
COUNT_DISTINCT( Returns the number of SELECT COUNT_DISTINCT(City__c) FROM Property__c
) unique rows that match
the query criteria
MIN() Returns the minimum SELECT MIN(Days_On_Market__c) FROM Property__c
value of a field
MAX() Returns the maximum SELECT MAX(Beds__c) FROM Property__c
value of a field
AVG() Returns the average SELECT City__c, AVG(Days_On_Market__c) FROM
value of a numeric field Property__c GROUP BY City__c

SUM() Returns the total value SELECT SUM(Price__c), Broker__r.Name FROM


of a numeric field Property__c GROUP BY Broker__r.Name

AGGREGATE FUNCTIONS

The HAVING clause filters the results returned by an aggregate function. 

HAVING EN VEZ DE WHERE SI HAY AGGREGATE FUNCTION

 The WHERE clause filters records in a SOQL query that has no aggregate
function.
 The HAVING clause filters the results after data is aggregated by an
aggregate function.

What Is a SOSL Search?


SOSL (Salesforce Object Search Language) is a language that performs text
searches in records. Unlike SOQL, SOSL can query multiple types of objects at
the same time. SOSL can also use a word match to match fields, while SOQL
needs the exact phrase.

When you run a SOSL search for contact records using the word “Crisis,” your
search looks through all contact fields and returns any record containing that
word. But if you try the same in a SOQL query, you need to specify the fields to
search and a complete word or phrase to search for. You can also use  LIKE  or
wildcards to narrow down SOQL or SOSL searches

EJEMPLO SOQL QUERY


SELECT Name, Phone, Email, Title FROM Contact
WHERE (Department = 'Specialty Crisis
Management')

EJEMPLO MISA SOQL QUERY EN APEX


Contact[] theseContacts = [SELECT Name, Phone, Email, Description FROM
Contact
WHERE (Department='Specialty Crisis
Management')
ORDER BY Name];
// Log a count of how many contacts were found
System.debug(theseContacts.size() + ' contact(s) returned.');
// Log all values in the array of contacts
System.debug(theseContacts);
EJEMPLO SOSL QUERY
FIND {Crisis} IN ALL FIELDS RETURNING Contact(FirstName, LastName,
Phone, Email, Title)

EJEMPLO MISMA SOSL QUERY EN APEX


List<List<sObject>> searchList = [FIND 'Crisis' IN ALL FIELDS
RETURNING Contact(FirstName,
LastName,
Phone, Email, Description)];
Contact[] searchContacts = (Contact[])searchList[0];
System.debug('Found the following contacts:');
for (Contact c : searchContacts) {
System.debug(c.LastName + ', ' + c.FirstName);
}
Un record es un registro es decir como cuando entramos los datos para
crear un contacto, ese contacto que guardamos es un record, los fields
son los campos, ósea las columnas. Al crear un record basicamente
creamos un sObject.

Every record in Salesforce is natively represented as an sObject in Apex. For example,


the Acme account record corresponds to an Account sObject in Apex. The fields of the
Acme record that you can view and modify in the user interface can be read and
modified directly on the sObject as well.

Para declarar un sObject:

tipodesObject nombre = new tipodesObject();

The fields of a generic sObject can be accessed only through the put() and get() methods.

Se le puede asignar a un sObject genérico cualquier sObject especifico si se tiene un método


del cual no se sabe que sObject especifico pide:
sObject sobj1 = new Account(Name='Trailhead');
sObject sobj2 = new Book__c(Name='Workbook 1');

Para castear un sObject genérico a un sObject especifico:

En este caso acct es una variable sObject genérica y la casteamos a sObject Account asi puede
usar el llamado de métodos con punto lo cual no puede hacerse con sObject genérico.
Account acct = (Account)myGenericSObject;
// Now, you can use the dot notation to access fields on Account
String name = acct.Name;
String phone = acct.Phone;

The  upsert  DML operation creates new records and updates sObject records
within a single statement, using a specified field to determine the presence of
existing objects, or the ID field if no field is specified.
The  merge  statement merges up to three records of the same sObject type into
one of the records, deleting the others, and re-parenting any related records.

Al insertar un sObject el sistema le asigna una id a ese record insertado, y además se lo asigna
a la variable sObject auxiliar que se creo en el código esa misma id, por lo que para saber la id
del sObject que insertamos, podemos simplemente hacer un system.debug de esa variable
auxiliar después de que la insertamos para poder verla. También puedes seguir usándola en el
código para hacer otras operaciones DML.
// Create the account sObject
Account acct = new Account(Name='Acme', Phone='(415)555-1212',
NumberOfEmployees=100);
// Insert the account by using DML
insert acct;
// Get the new ID on the inserted sObject argument
ID acctID = acct.Id;
// Display this ID in the debug log
System.debug('ID = ' + acctID);

BULK DML

Básicamente se usan las operaciones DML sobre una lista de sObjects de forma que solo
cuente como una operación DML sola y no pasar el limite de 150 operaciones DML.

El upsert no solo actualiza e inserta los objetos sino que chequea la id del objeto por default o
el field que tu elijas para evitar duplicados. Para custom objects se especificia un custom field
marcado como external id. Para los standard cualquiera que tenga idLookup en true. Si el id es
matched se modifica, si no es matched se inserta y si se matchea muchas veces no hace nada
porque hay muchos duplicados existentes.

Upsert Syntax

upsert sObject | sObject[] field(el field es opcional)

Por ej:
upsert sObjectList Account.Fields.MyExternalId;

DELETE

El delete no borra sino que los deja en la papelera por 15 dias por si se quiere restaurar. A
continuacion un ejemplo de como borrar una cantidad de contactos filtrados por una consulta.
Contact[] contactsDel = [SELECT Id FROM Contact WHERE
LastName='Smith'];
delete contactsDel;

DATABASE METHODS

 Database.insert()
 Database.update()
 Database.upsert()
 Database.delete()
 Database.undelete()
 Database.merge()

Estos métodos tienen un parámetro para que sea todo o nada, si hay errores no hace nada, si
este se pone en false, si hay errores se pasan los que no tuvieron errores y los que tuvieron
errores se muestran.
Database.insert(recordList, false);

Estos errores son devueltos como objetos llamados SaveResult, y pueden ser guardados en un
array.
Database.SaveResult[] results = Database.insert(recordList, false);
Upser devuelve UpsertResults y delete DeleteResults.

¿Entonces debo usar DML O DATABASE?

Se usa dml si se quiere que el bloque se interrumpa usando herramientas de Flow control
como try y catch. Se usa Database si se quiere que se haya éxito parcial en los records que no
presenten errores y sean insertados igual o la operación que sea. Y con los que fallen después
se puede inspeccionar a ver por que fallaron para no tener errores de excepción de DML
nunca.

INSERTAR RECORDS RELACIONADOS

Se puede solo si la relación ya ha sido establecida sea lookup o masterdetail. Estos se asocian
mediante una foreign key.
Account acct = new Account(Name='SFDC Account');
insert acct;
// Once the account is inserted, the sObject will be
// populated with an ID.
// Get this ID.
ID acctID = acct.ID;
// Add a contact to this account.
Contact mario = new Contact(
FirstName='Mario',
LastName='Ruiz',
Phone='415.555.1212',
AccountId=acctID);
insert mario;

RELATED RECORD FIELD NO PUEDE SER MODIFICADOS EN LA MISMA OPERACIÓN DML SE


NECESITAN DOS
El delete sin embargo si el padre es borrado borra a los hijos también si estos pueden ser
eliminados.

QUERY RECORD IN BATCHES BY USING SOQL FOR LOOPS


for (variablelistosingle : [soql_query]) {
code_block
}

 Use SOQL to retrieve records for a single object.


 Use SOSL to search fields across multiple objects. SOSL queries can
search most text fields on an object.

En el query editor se busca FIND {talcosa} pero cuando lo pones en ápex va con FIND ‘talcosa’

SOSL allows you to specify the following search criteria:

 Text expression (single word or a phrase) to search for


 Scope of fields to search
 List of objects and fields to retrieve
 Conditions for selecting rows in the source objects

FIND 'SearchQuery' [IN SearchGroup] [RETURNING ObjectsAndFields]

SearchQuery is the text to search for (a single word or a phrase). Search terms can be
grouped with logical operators (AND, OR) and parentheses. Also, search terms can
include wildcard characters (*, ?). The * wildcard matches zero or more characters at the
middle or end of the search term. The ? wildcard matches only one character at the
middle or end of the search term.

SearchGroup is optional. It is the scope of the fields to search. If not specified, the
default search scope is all fields. SearchGroup can take one of the following values

 ALL FIELDS
 NAME FIELDS
 EMAIL FIELDS
 PHONE FIELDS
 SIDEBAR FIELDS

ObjectsAndFields is optional. It is the information to return in the search result—a list of


one or more sObjects and, within each sObject, list of one or more fields, with optional
values to filter against. If not specified, the search results contain the IDs of all objects
found.

A SearchQuery contains two types of text:


 Single Word— single word, such as  test  or  hello . Words in
the  SearchQuery  are delimited by spaces, punctuation, and changes from
letters to digits (and vice-versa). Words are always case insensitive.
 Phrase— collection of words and spaces surrounded by double quotes
such as  "john smith" . Multiple words can be combined together with
logic and grouping operators to form a more complex query.

Trigger Syntax
La sintaxis del trigger es trigger elnombredeltrigger on objetoquequieras y entre
paréntesis las condiciones que lo triggerean.

trigger TriggerName on ObjectName (trigger_events) {


code_block
}
Posibles eventos para poner en trigger_events:

 before insert

 before update

 before delete

 after insert

 after update

 after delete

 after undelete

 Before triggers are used to update or validate record values before


they’re saved to the database.
 After triggers are used to access field values that are set by the system
(such as a record's  Id  or  LastModifiedDate  field), and to affect changes in
other records. The records that fire the after trigger are read-only.

 To access the records that caused the trigger to fire, use context
variables. For example,  Trigger.New  contains all the records that were
inserted in insert or update triggers.  Trigger.Old  provides the old version
of sObjects before they were updated in update triggers, or a list of
deleted sObjects in delete triggers. Triggers can fire when one record is
inserted, or when many records are inserted in bulk via the API or Apex.
Therefore, context variables, such as  Trigger.New , can contain only one
record or multiple records. You can iterate over  Trigger.New  to get each
individual sObject.

Este trigger itera por cada cuenta en un for loop y modifica el description field
trigger HelloWorldTrigger on Account (before insert) {
for(Account a : Trigger.New) {
a.Description = 'New description';
}
}

Se usan variables de context que retornan booleanos por ejemplo para indicar si el trigger si
disparo por algún evento, estos son un buen uso cuando el trigger maneja muchos eventos.

LOS TRIGGERS PUEDEN LLAMAR METODOS PUBLIC

Calling  addError()  in a trigger causes the entire set of operations to roll back,
except when bulk DML is called with partial success.

 If a DML statement in Apex spawned the trigger, any error rolls back the
entire operation. However, the runtime engine still processes every
record in the operation to compile a comprehensive list of errors.

 If a bulk DML call in the Lightning Platform API spawned the trigger, the
runtime engine sets the bad records aside. The runtime engine then
attempts a partial save of the records that did not generate errors.

Las llamadas a web services externos se llaman CALLOUTS.

Cuando se hace un callout desde un trigger se tiene que hacer asincrónicamente para que el
proceso del trigger no te bloquee de trabajar mientras esperas la respuesta del servicio
externo. Por lo que se hace en un background process. Para hacer un callout desde un trigger
se llama a un método futuro que es un método que se ejecuta asincrónicamente y se anota
con @future(callout=true)

BULKIFY IMPORTANTE
1) Siempre se opera en record sets no en single record en los triggers.
2) Aprovechar al máximo las SOQL queries para no pasar el limite de 100 queries para el
ápex sincrónico y 200 para el asincrónico.
3) NO HACER QUERIES DENTRO DE UN FOR loop que vaya por cada sObject de un set que
haya activado el trigger, sino que hacer la query ANTES en el set para filtrar los valores
que se quieran y después ahí realizar el for. Así logrando realizar UNA query y no una
por cada record del set que hizo saltar el trigger.
4) Hacer las operaciones DML en listas fuera de los for, hacerlo al final. Usar un for para
iterar sobre el set que triggereo y usar una lista auxiliar para ir guardando los records y
después hacer la operación DML en la lista auxiliar.
Sintaxis TESTING
@isTest static void testName() {
// code_block
}

Los test no llevan public o private en su sintaxis ya que se puede acceder de todas formas a los
métodos de testing.

Los test deben estar definidos dentro de clases de test.


@isTest
private class MyTestClass {
@isTest static void myTest() {
// code_block
}
}

System.assertEquals() method, Se usa para el testing unitario. which takes two


parameters: the first is the expected value, and the second is the actual value. There is
another version of this method that takes a third parameter—a string that describes the
comparison being done, which is used in testBoilingPoint(). This optional string is
logged if the assertion fails.

Test Suite
A test suite is a collection of Apex test classes that you run together.

Even though it is not a best practice to do so, there are times when a test method
needs access to pre-existing data. To access org data, annotate the test method with
@isTest(SeeAllData=true). The test method examples in this unit don’t access org
data and therefore don’t use the SeeAllData parameter.

 SOSL searches performed in a test return empty results. To ensure


predictable results, use Test.setFixedSearchResults() to define the records
to be returned by the search.

@testsetup
StartTest y StopTest
The test method contains the Test.startTest() and Test.stopTest() method pair, which
delimits a block of code that gets a fresh set of governor limits. In this test, test-data
setup uses two DML statements before the test is performed. To test that Apex code
runs within governor limits, isolate data setup’s limit usage from your test’s. To isolate
the data setup process’s limit usage, enclose the test call within the Test.startTest() and
Test.stopTest() block. Also use this test block when testing asynchronous Apex.

También podría gustarte