Apex - Guía rápida
¿Qué es Apex?
Apex es un lenguaje propietario desarrollado por Salesforce.com. Según la definición oficial, Apex es un lenguaje de programación orientado a objetos fuertemente tipado que permite a los desarrolladores ejecutar las declaraciones de control de flujo y transacciones en el servidor de la plataforma Force.com junto con llamadas a la API de Force.com.
Tiene una sintaxis similar a Java y actúa como procedimientos almacenados de base de datos. Permite a los desarrolladores agregar lógica empresarial a la mayoría de los eventos del sistema, incluidos los clics en los botones, las actualizaciones de registros relacionados y Visualforce.pages.ApexEl código se puede iniciar mediante solicitudes de servicios web y desde desencadenantes en objetos. Apex se incluye en Performance Edition, Unlimited Edition, Enterprise Edition y Developer Edition.
Características de Apex como lenguaje
Analicemos ahora las características de Apex como lenguaje:
Integrado
Apex ha incorporado soporte para operaciones DML como INSERT, UPDATE, DELETE y también manejo de excepciones DML. Tiene soporte para el manejo de consultas SOQL y SOSL en línea que devuelve el conjunto de registros sObject. Estudiaremos sObject, SOQL, SOSL en detalle en capítulos futuros.
Java como la sintaxis y fácil de usar
Apex es fácil de usar ya que usa la sintaxis como Java. Por ejemplo, declaración de variable, sintaxis de bucle y declaraciones condicionales.
Fuertemente integrado con datos
Apex está enfocado en datos y diseñado para ejecutar múltiples consultas y declaraciones DML juntas. Emite múltiples declaraciones de transacciones en la base de datos.
Fuertemente mecanografiado
Apex es un lenguaje fuertemente tipado. Utiliza una referencia directa a objetos de esquema como sObject y cualquier referencia no válida falla rápidamente si se elimina o si tiene un tipo de datos incorrecto.
Entorno multiusuario
Apex se ejecuta en un entorno multiusuario. En consecuencia, el motor de tiempo de ejecución de Apex está diseñado para protegerse de cerca contra el código fuera de control, evitando que monopolice los recursos compartidos. Cualquier código que viole los límites falla con mensajes de error fáciles de entender.
Actualiza automáticamente
Apex se actualiza como parte de las versiones de Salesforce. No tenemos que actualizarlo manualmente.
Prueba fácil
Apex proporciona soporte integrado para la creación y ejecución de pruebas unitarias, incluidos los resultados de las pruebas que indican cuánto código se cubre y qué partes de su código pueden ser más eficientes.
¿Cuándo debe el desarrollador elegir Apex?
Apex debe usarse cuando no podemos implementar la compleja funcionalidad comercial utilizando las funcionalidades predefinidas y existentes listas para usar. A continuación, se muestran los casos en los que necesitamos utilizar apex sobre la configuración de Salesforce.
Aplicaciones de Apex
Podemos usar Apex cuando queramos:
Crear servicios Web integrando otros sistemas.
Cree servicios de correo electrónico para correo electrónico masivo o configuración de correo electrónico.
Realice una validación compleja sobre varios objetos al mismo tiempo y también una implementación de validación personalizada.
Cree procesos comerciales complejos que no sean compatibles con la funcionalidad o los flujos de flujo de trabajo existentes.
Cree lógica transaccional personalizada (lógica que ocurre en toda la transacción, no solo con un solo registro u objeto) como usar los métodos de la base de datos para actualizar los registros.
Realice alguna lógica cuando se modifique un registro o modifique el registro del objeto relacionado cuando haya algún evento que haya provocado el disparo del disparador.
Estructura de trabajo de Apex
Como se muestra en el diagrama a continuación (Referencia: Documentación para desarrolladores de Salesforce), Apex se ejecuta completamente bajo demanda Plataforma Force.com
Flujo de acciones
Hay dos secuencias de acciones cuando el desarrollador guarda el código y cuando un usuario final realiza alguna acción que invoca el código Apex como se muestra a continuación:
Acción del desarrollador
Cuando un desarrollador escribe y guarda código Apex en la plataforma, el servidor de aplicaciones de la plataforma primero compila el código en un conjunto de instrucciones que el intérprete de tiempo de ejecución de Apex puede entender y luego guarda esas instrucciones como metadatos.
Acción del usuario final
Cuando un usuario final activa la ejecución de Apex, al hacer clic en un botón o al acceder a una página de Visualforce, el servidor de aplicaciones de la plataforma recupera las instrucciones compiladas de los metadatos y las envía a través del intérprete en tiempo de ejecución antes de devolver el resultado. El usuario final no observa diferencias en el tiempo de ejecución en comparación con la solicitud de plataforma de aplicación estándar.
Dado que Apex es el lenguaje propietario de Salesforce.com, no es compatible con algunas funciones que sí admite un lenguaje de programación general. A continuación se muestran algunas funciones que Apex no admite:
No puede mostrar los elementos en la interfaz de usuario.
No puede cambiar la funcionalidad estándar proporcionada por SFDC y tampoco es posible evitar la ejecución de la funcionalidad estándar.
Tampoco es posible crear varios hilos, ya que podemos hacerlo en otros idiomas.
Comprensión de la sintaxis de Apex
El código Apex generalmente contiene muchas cosas con las que podríamos estar familiarizados en otros lenguajes de programación.
Declaración de variable
Como lenguaje fuertemente tipado, debe declarar cada variable con tipo de datos en Apex. Como se ve en el código a continuación (captura de pantalla a continuación), lstAcc se declara con el tipo de datos como Lista de cuentas.
Consulta SOQL
Esto se utilizará para recuperar los datos de la base de datos de Salesforce. La consulta que se muestra en la captura de pantalla a continuación está obteniendo datos del objeto Cuenta.
Declaración de bucle
Esta declaración de bucle se utiliza para iterar sobre una lista o para iterar sobre un fragmento de código durante un número específico de veces. En el código que se muestra en la captura de pantalla a continuación, la iteración será la misma que la cantidad de registros que tenemos.
Declaración de control de flujo
La instrucción If se utiliza para el control de flujo en este código. En función de cierta condición, se decide si se ejecuta o se detiene la ejecución de la pieza de código en particular. Por ejemplo, en el código que se muestra a continuación, verifica si la lista está vacía o contiene registros.
Declaración DML
Realiza la operación de inserción, actualización, actualización y eliminación de registros en los registros de la base de datos. Por ejemplo, el código que se proporciona a continuación ayuda a actualizar Cuentas con un nuevo valor de campo.
A continuación, se muestra un ejemplo de cómo se verá un fragmento de código de Apex. Vamos a estudiar todos estos conceptos de programación de Apex más a fondo en este tutorial.
En este capítulo, comprenderemos el entorno para nuestro desarrollo de Salesforce Apex. Se supone que ya tiene configurada una edición de Salesforce para realizar el desarrollo de Apex.
Puede desarrollar el código Apex en la edición Sandbox o Developer de Salesforce. Una organización Sandbox es una copia de su organización en la que puede escribir código y probarlo sin correr el riesgo de modificar los datos o alterar la funcionalidad normal. Según la práctica industrial estándar, debe desarrollar el código en Sandbox y luego implementarlo en el entorno de producción.
Para este tutorial, usaremos la edición Developer de Salesforce. En la edición Developer, no tendrá la opción de crear una organización Sandbox. Las funciones de Sandbox están disponibles en otras ediciones de Salesforce.
Herramientas de desarrollo de código Apex
En todas las ediciones, podemos utilizar cualquiera de las siguientes tres herramientas para desarrollar el código:
- Consola de desarrollador de Force.com
- IDE de Force.com
- Editor de código en la interfaz de usuario de Salesforce
Note − Utilizaremos Developer Console a lo largo de nuestro tutorial para la ejecución de código, ya que es simple y fácil de usar para aprender.
Consola de desarrollador de Force.com
Developer Console es un entorno de desarrollo integrado con una colección de herramientas que puede utilizar para crear, depurar y probar aplicaciones en su organización de Salesforce.
Siga estos pasos para abrir Developer Console:
Step 1 − Vaya a Nombre → Consola de desarrollador
Step 2 − Haga clic en "Consola de desarrollador" y aparecerá una ventana como en la siguiente captura de pantalla.
A continuación, se muestran algunas operaciones que se pueden realizar con Developer Console.
Writing and compiling code −Puede escribir el código utilizando el editor de código fuente. Cuando guarda un disparador o una clase, el código se compila automáticamente. Se informará de cualquier error de compilación.
Debugging −Puede escribir el código utilizando el editor de código fuente. Cuando guarda un disparador o una clase, el código se compila automáticamente. Se informará de cualquier error de compilación.
Testing − Puede ver los registros de depuración y establecer puntos de control que ayuden a depurar.
Checking performance −Puede ejecutar pruebas de clases de prueba específicas o de todas las clases de su organización, y puede ver los resultados de las pruebas. Además, puede inspeccionar la cobertura del código.
SOQL queries − Puede inspeccionar los registros de depuración para localizar cuellos de botella en el rendimiento.
Color coding and autocomplete − El editor de código fuente utiliza un esquema de colores para facilitar la lectura de los elementos del código y proporciona autocompletado para los nombres de clases y métodos.
Ejecutar código en Developer Console
Todos los fragmentos de código mencionados en este tutorial deben ejecutarse en la consola del desarrollador. Siga estos pasos para ejecutar los pasos en Developer Console.
Step 1 - Inicie sesión en Salesforce.com utilizando login.salesforce.com. Copie los fragmentos de código mencionados en el tutorial. Por ahora, usaremos el siguiente código de muestra.
String myString = 'MyString';
System.debug('Value of String Variable'+myString);
Step 2 - Para abrir la Consola de desarrollador, haga clic en Nombre → Consola de desarrollador y luego haga clic en Ejecutar anónimo como se muestra a continuación.
Step 3 - En este paso, aparecerá una ventana y podrás pegar el código allí.
Step 4 - Cuando hacemos clic en Execute, se abrirán los registros de depuración. Una vez que el registro aparezca en la ventana como se muestra a continuación, haga clic en el registro de registro.
Luego, escriba 'USUARIO' en la ventana como se muestra a continuación y la declaración de salida aparecerá en la ventana de depuración. Esta declaración de 'USUARIO' se utiliza para filtrar la salida.
Básicamente, seguirá todos los pasos mencionados anteriormente para ejecutar cualquier fragmento de código en este tutorial.
Ejemplo de desarrollo de aplicaciones empresariales
Para nuestro tutorial, implementaremos la aplicación CRM para una empresa de procesamiento y equipos químicos. Esta empresa trata con proveedores y brinda servicios. Trabajaremos pequeños fragmentos de código relacionados con este ejemplo a lo largo de nuestro tutorial para comprender cada concepto en detalle.
Para ejecutar el código en este tutorial, necesitará tener dos objetos creados: los objetos Cliente y Factura. Si ya sabe cómo crear estos objetos en Salesforce, puede omitir los pasos que se indican a continuación. De lo contrario, puede seguir la guía paso a paso a continuación.
Crear objeto de cliente
Primero configuraremos el objeto Cliente.
Step 1- Vaya a Configuración y luego busque 'Objeto' como se muestra a continuación. Luego haga clic en el enlace Objetos como se muestra a continuación.
Step 2 - Una vez que se abre la página del objeto, haga clic en 'Create New Object'como se muestra a continuación.
Step 3- Después de hacer clic en el botón, aparecerá la página de creación de nuevo objeto y luego ingrese todos los detalles del objeto como se ingresa a continuación. El nombre del objeto debe ser Cliente. Solo tiene que ingresar la información en el campo como se muestra en la captura de pantalla a continuación y mantener otras cosas predeterminadas como están.
Ingrese la información y luego haga clic en el botón 'Guardar' -
Siguiendo los pasos anteriores, hemos creado con éxito el objeto Cliente.
Crear el objeto Campos personalizados para cliente
Ahora que tenemos nuestro objeto Cliente configurado, crearemos un campo 'Activo' y luego puede crear los otros campos siguiendo pasos similares. El nombre y el nombre de la API del campo se proporcionarán en la captura de pantalla.
Step 1- Crearemos un campo llamado 'Activo' de tipo de datos como Casilla de verificación. Vaya a Configuración y haga clic en él.
Step 2 - Busque 'Objeto' como se muestra a continuación y haga clic en él.
Step 3 - Haga clic en el objeto 'Cliente'.
Step 4 - Una vez que haya hecho clic en el enlace del objeto Cliente y aparezca la página de detalles del objeto, haga clic en el botón Nuevo.
Step 5 - Ahora, seleccione el tipo de datos como Casilla de verificación y haga clic en Siguiente.
Step 6 - Ingrese el nombre del campo y la etiqueta como se muestra a continuación.
Step 7 - Haga clic en Visible y luego haga clic en Siguiente.
Step 8 - Ahora haga clic en 'Guardar'.
Siguiendo los pasos anteriores, se crea nuestro campo personalizado 'Activo'. Debe seguir todos los pasos de creación de campos personalizados anteriores para los campos restantes. Esta es la vista final del objeto del cliente una vez que se crean todos los campos:
Creación de objeto de factura
Step 1 - Vaya a Configuración y busque 'Objeto' y luego haga clic en el enlace Objetos como se muestra a continuación.
Step 2 - Una vez que se abre la página del objeto, haga clic en el botón 'Crear nuevo objeto' como se muestra a continuación.
Step 3- Después de hacer clic en el botón, aparecerá la página de creación de nuevos objetos como se muestra en la captura de pantalla a continuación. Debes ingresar los detalles aquí. El nombre del objeto debe ser Factura. Esto es similar a cómo creamos el objeto Cliente anteriormente en este tutorial.
Step 4 - Ingrese la información como se muestra a continuación y luego haga clic en el botón 'Guardar'.
Siguiendo estos pasos, se creará su objeto Factura.
Creación de campos personalizados para el objeto Factura
Crearemos el campo Descripción en el objeto Factura como se muestra a continuación:
Step 1 - Vaya a Configuración y haga clic en él.
Step 2 - Busque 'Objeto' como se muestra a continuación y haga clic en él.
Step 3 - Haga clic en el objeto 'Factura'.
Y luego haga clic en 'Nuevo'.
Step 4 - Seleccione el tipo de datos como Área de texto y luego haga clic en el botón Siguiente.
Step 5 - Introduzca la información que se indica a continuación.
Step 6 - Haga clic en Visible y luego en Siguiente.
Step 7 - Haga clic en Guardar.
Del mismo modo, puede crear los otros campos en el objeto Factura.
Con esto, hemos creado los objetos que se necesitan para este tutorial. Aprenderemos varios ejemplos en los capítulos siguientes basados en estos objetos.
Comprensión de los tipos de datos
El lenguaje Apex está fuertemente tipado, por lo que cada variable en Apex se declarará con el tipo de datos específico. Todas las variables de ápice se inicializan a nulo inicialmente. Siempre se recomienda que un desarrollador se asegure de que se asignen los valores adecuados a las variables. De lo contrario, dichas variables, cuando se utilizan, arrojarán excepciones de puntero nulo o cualquier excepción no controlada.
Apex admite los siguientes tipos de datos:
Primitivo (entero, doble, largo, fecha, fecha y hora, cadena, ID o booleano)
Colecciones (listas, conjuntos y mapas) (se tratará en el capítulo 6)
sObject
Enums
Clases, objetos e interfaces (se tratarán en los capítulos 11, 12 y 13)
En este capítulo, veremos todos los tipos de datos primitivos, sObjects y Enums. Analizaremos Colecciones, Clases, Objetos e Interfaces en los próximos capítulos, ya que son temas clave para aprender individualmente.
Tipos de datos primitivos
En esta sección, discutiremos los tipos de datos primitivos compatibles con Apex.
Entero
Un número de 32 bits que no incluye ningún punto decimal. El rango de valores para esto comienza desde -2,147,483,648 y el valor máximo es hasta 2,147,483,647.
Example
Queremos declarar una variable que almacenará la cantidad de barriles que deben enviarse al comprador de la planta de procesamiento químico.
Integer barrelNumbers = 1000;
system.debug(' value of barrelNumbers variable: '+barrelNumbers);
los System.debug() La función imprime el valor de la variable para que podamos usar esto para depurar o para saber qué valor tiene la variable actualmente.
Pegue el código anterior en la consola del desarrollador y haga clic en Ejecutar. Una vez generados los registros, se mostrará el valor de la variable "barrelNumbers" como 1000.
Booleano
Esta variable puede ser verdadera, falsa o nula. Muchas veces, este tipo de variable se puede utilizar como bandera en la programación para identificar si la condición particular está establecida o no.
Example
Si el envío booleanoDispatched se va a establecer como verdadero, entonces se puede declarar como:
Boolean shipmentDispatched;
shipmentDispatched = true;
System.debug('Value of shipmentDispatched '+shipmentDispatched);
Fecha
Este tipo de variable indica una fecha. Esto solo puede almacenar la fecha y no la hora. Para guardar la fecha junto con la hora, necesitaremos almacenarla en la variable DateTime.
Example
Considere el siguiente ejemplo para comprender cómo funciona la variable Fecha.
//ShipmentDate can be stored when shipment is dispatched.
Date ShipmentDate = date.today();
System.debug('ShipmentDate '+ShipmentDate);
Largo
Este es un número de 64 bits sin punto decimal. Se usa cuando necesitamos un rango de valores más amplio que los proporcionados por Integer.
Example
Si se van a almacenar los ingresos de la empresa, utilizaremos el tipo de datos como Long.
Long companyRevenue = 21474838973344648L;
system.debug('companyRevenue'+companyRevenue);
Objeto
Podemos referirnos a esto como cualquier tipo de datos que sea compatible con Apex. Por ejemplo, la variable de clase puede ser un objeto de esa clase, y el tipo genérico sObject también es un objeto y el tipo de objeto específico similar, como Account, también es un objeto.
Example
Considere el siguiente ejemplo para comprender cómo funciona la variable bject.
Account objAccount = new Account (Name = 'Test Chemical');
system.debug('Account value'+objAccount);
Note - También puede crear un objeto de clase predefinida, como se indica a continuación -
//Class Name: MyApexClass
MyApexClass classObj = new MyApexClass();
Este es el objeto de clase que se utilizará como variable de clase.
Cuerda
Cadena es cualquier conjunto de caracteres entre comillas simples. No tiene ningún límite para el número de caracteres. Aquí, el tamaño del montón se utilizará para determinar el número de caracteres. Esto pone un freno al monopolio de los recursos por parte del programa Apex y también asegura que no sea demasiado grande.
Example
String companyName = 'Abc International';
System.debug('Value companyName variable'+companyName);
Hora
Esta variable se usa para almacenar el tiempo en particular. Esta variable siempre debe declararse con el método estático del sistema.
Gota
El Blob es una colección de datos binarios que se almacena como objeto. Esto se utilizará cuando queramos almacenar el archivo adjunto en Salesforce en una variable. Este tipo de datos convierte los archivos adjuntos en un solo objeto. Si el blob se va a convertir en una cadena, entonces podemos hacer uso de los métodos toString y valueOf para el mismo.
sObject
Este es un tipo de datos especial en Salesforce. Es similar a una tabla en SQL y contiene campos que son similares a columnas en SQL. Hay dos tipos de sObjects: estándar y personalizado.
Por ejemplo, Account es un sObject estándar y cualquier otro objeto definido por el usuario (como el objeto Customer que creamos) es un sObject personalizado.
Example
//Declaring an sObject variable of type Account
Account objAccount = new Account();
//Assignment of values to fields of sObjects
objAccount.Name = 'ABC Customer';
objAccount.Description = 'Test Account';
System.debug('objAccount variable value'+objAccount);
//Declaring an sObject for custom object APEX_Invoice_c
APEX_Customer_c objCustomer = new APEX_Customer_c();
//Assigning value to fields
objCustomer.APEX_Customer_Decscription_c = 'Test Customer';
System.debug('value objCustomer'+objCustomer);
Enum
Enum es un tipo de datos abstracto que almacena un valor de un conjunto finito de identificadores especificados. Puede utilizar la palabra clave Enum para definir un Enum. Enum se puede utilizar como cualquier otro tipo de datos en Salesforce.
Example
Puede declarar los posibles nombres de los compuestos químicos ejecutando el siguiente código:
//Declaring enum for Chemical Compounds
public enum Compounds {HCL, H2SO4, NACL, HG}
Compounds objC = Compounds.HCL;
System.debug('objC value: '+objC);
Java y Apex son similares en muchos aspectos. La declaración de variables en Java y Apex también es bastante similar. Discutiremos algunos ejemplos para entender cómo declarar variables locales.
String productName = 'HCL';
Integer i = 0;
Set<string> setOfProducts = new Set<string>();
Map<id, string> mapOfProductIdToName = new Map<id, string>();
Tenga en cuenta que a todas las variables se les asigna el valor nulo.
Declaring Variables
Puede declarar las variables en Apex como String e Integer de la siguiente manera:
String strName = 'My String'; //String variable declaration
Integer myInteger = 1; //Integer variable declaration
Boolean mtBoolean = true; //Boolean variable declaration
Apex variables are Case-Insensitive
Esto significa que el código dado a continuación arrojará un error ya que la variable 'm' ha sido declarada dos veces y ambas serán tratadas como iguales.
Integer m = 100;
for (Integer i = 0; i<10; i++) {
integer m = 1; //This statement will throw an error as m is being declared
again
System.debug('This code will throw error');
}
Scope of Variables
Una variable de Apex es válida desde el punto en que se declara en el código. Por lo tanto, no está permitido volver a definir la misma variable y en bloque de código. Además, si declara cualquier variable en un método, el alcance de esa variable se limitará solo a ese método en particular. Sin embargo, se puede acceder a las variables de clase en toda la clase.
Example
//Declare variable Products
List<string> Products = new List<strings>();
Products.add('HCL');
//You cannot declare this variable in this code clock or sub code block again
//If you do so then it will throw the error as the previous variable in scope
//Below statement will throw error if declared in same code block
List<string> Products = new List<strings>();
Cadena en Apex, como en cualquier otro lenguaje de programación, es cualquier conjunto de caracteres sin límite de caracteres.
Example
String companyName = 'Abc International';
System.debug('Value companyName variable'+companyName);
Métodos de cadena
La clase de cadena en Salesforce tiene muchos métodos. Echaremos un vistazo a algunos de los métodos de cadena más importantes y de uso frecuente en este capítulo.
contiene
Este método devolverá verdadero si la cadena dada contiene la subcadena mencionada.
Syntax
public Boolean contains(String substring)
Example
String myProductName1 = 'HCL';
String myProductName2 = 'NAHCL';
Boolean result = myProductName2.contains(myProductName1);
System.debug('O/p will be true as it contains the String and Output is:'+result);
es igual a
Este método devolverá verdadero si la cadena dada y la cadena pasada en el método tienen la misma secuencia binaria de caracteres y no son nulas. También puede comparar la identificación del registro SFDC utilizando este método. Este método distingue entre mayúsculas y minúsculas.
Syntax
public Boolean equals(Object string)
Example
String myString1 = 'MyString';
String myString2 = 'MyString';
Boolean result = myString2.equals(myString1);
System.debug('Value of Result will be true as they are same and Result is:'+result);
equalsIgnoreCase
Este método devolverá verdadero si stringtoCompare tiene la misma secuencia de caracteres que la cadena dada. Sin embargo, este método no distingue entre mayúsculas y minúsculas.
Syntax
public Boolean equalsIgnoreCase(String stringtoCompare)
Example
El siguiente código devolverá verdadero ya que los caracteres de cadena y la secuencia son los mismos, ignorando la distinción entre mayúsculas y minúsculas.
String myString1 = 'MySTRING';
String myString2 = 'MyString';
Boolean result = myString2.equalsIgnoreCase(myString1);
System.debug('Value of Result will be true as they are same and Result is:'+result);
eliminar
Este método elimina la cadena proporcionada en stringToRemove de la cadena dada. Esto es útil cuando desea eliminar algunos caracteres específicos de la cadena y no conoce el índice exacto de los caracteres que desea eliminar. Este método distingue entre mayúsculas y minúsculas y no funcionará si se produce la misma secuencia de caracteres pero las mayúsculas y minúsculas son diferentes.
Syntax
public String remove(String stringToRemove)
Example
String myString1 = 'This Is MyString Example';
String stringToRemove = 'MyString';
String result = myString1.remove(stringToRemove);
System.debug('Value of Result will be 'This Is Example' as we have removed the MyString
and Result is :'+result);
removeEndIgnoreCase
Este método elimina la cadena proporcionada en stringToRemove de la cadena dada, pero solo si ocurre al final. Este método no distingue entre mayúsculas y minúsculas.
Syntax
public String removeEndIgnoreCase(String stringToRemove)
Example
String myString1 = 'This Is MyString EXAMPLE';
String stringToRemove = 'Example';
String result = myString1.removeEndIgnoreCase(stringToRemove);
System.debug('Value of Result will be 'This Is MyString' as we have removed the 'Example'
and Result is :'+result);
comienza con
Este método devolverá verdadero si la cadena dada comienza con el prefijo proporcionado en el método.
Syntax
public Boolean startsWith(String prefix)
Example
String myString1 = 'This Is MyString EXAMPLE';
String prefix = 'This';
Boolean result = myString1.startsWith(prefix);
System.debug(' This will return true as our String starts with string 'This' and the
Result is :'+result);
Las matrices en Apex son básicamente las mismas que las listas en Apex. No hay una distinción lógica entre las matrices y las listas, ya que su estructura de datos y métodos internos también son los mismos, pero la sintaxis de la matriz es poco tradicional como Java.
A continuación se muestra la representación de una matriz de productos:
Index 0 - HCL
Index 1 - H2SO4
Index 2 - NACL
Index 3 - H2O
Index 4 - N2
Index 5 - U296
Sintaxis
<String> [] arrayOfProducts = new List<String>();
Ejemplo
Supongamos que tenemos que almacenar el nombre de nuestros productos; podemos usar la matriz en la que almacenaremos los nombres de los productos como se muestra a continuación. Puede acceder al Producto en particular especificando el índice.
//Defining array
String [] arrayOfProducts = new List<String>();
//Adding elements in Array
arrayOfProducts.add('HCL');
arrayOfProducts.add('H2SO4');
arrayOfProducts.add('NACL');
arrayOfProducts.add('H2O');
arrayOfProducts.add('N2');
arrayOfProducts.add('U296');
for (Integer i = 0; i<arrayOfProducts.size(); i++) {
//This loop will print all the elements in array
system.debug('Values In Array: '+arrayOfProducts[i]);
}
Accediendo al elemento de la matriz mediante el índice
Puede acceder a cualquier elemento de la matriz utilizando el índice como se muestra a continuación:
//Accessing the element in array
//We would access the element at Index 3
System.debug('Value at Index 3 is :'+arrayOfProducts[3]);
Como en cualquier otro lenguaje de programación, las constantes son las variables que no cambian su valor una vez declaradas o asignadas un valor.
En Apex, las constantes se utilizan cuando queremos definir variables que deben tener un valor constante durante toda la ejecución del programa. Las constantes de Apex se declaran con la palabra clave 'final'.
Ejemplo
Considere un CustomerOperationClass clase y una variable constante regularCustomerDiscount dentro de ella -
public class CustomerOperationClass {
static final Double regularCustomerDiscount = 0.1;
static Double finalPrice = 0;
public static Double provideDiscount (Integer price) {
//calculate the discount
finalPrice = price - price * regularCustomerDiscount;
return finalPrice;
}
}
Para ver la salida de la clase anterior, debe ejecutar el siguiente código en la ventana anónima de la consola de desarrollo:
Double finalPrice = CustomerOperationClass.provideDiscount(100);
System.debug('finalPrice '+finalPrice);
Las estructuras de toma de decisiones requieren que el programador especifique una o más condiciones para ser evaluadas o probadas por el programa, junto con una declaración o declaraciones que se ejecutarán si se determina que la condición es verdadera y, opcionalmente, otras declaraciones que se ejecutarán si el se determina que la condición es falsa.
En este capítulo, estudiaremos la estructura básica y avanzada de la toma de decisiones y las declaraciones condicionales en Apex. La toma de decisiones es necesaria para controlar el flujo de ejecución cuando se cumple o no determinada condición. A continuación se muestra la forma general de una estructura típica de toma de decisiones que se encuentra en la mayoría de los lenguajes de programación.
No Señor. | Declaración y descripción |
---|---|
1 | si declaración Una instrucción if consta de una expresión booleana seguida de una o más declaraciones. |
2 | declaración if ... else Una sentencia if puede ir seguida de una else declaración, que se ejecuta cuando la expresión booleana es falsa. |
3 | if ... elseif ... declaración else Una sentencia if puede ir seguida de una else if...else declaración, que es muy útil para probar varias condiciones usando una sola declaración if ... else if. |
4 | declaración if anidada Puedes usar uno if or else if declaración dentro de otra if or else if declaración (es). |
Los bucles se utilizan cuando una pieza de código en particular debe repetirse con el número deseado de iteraciones. Apex admite el bucle for tradicional estándar, así como otros tipos avanzados de bucles. En este capítulo, analizaremos en detalle los bucles en Apex.
Una declaración de bucle nos permite ejecutar una declaración o grupo de declaraciones varias veces y, a continuación, se encuentra la forma general de una declaración de bucle en la mayoría de los lenguajes de programación:
Las siguientes tablas enumeran los diferentes bucles que manejan los requisitos de bucle en el lenguaje de programación Apex. Haga clic en los siguientes enlaces para verificar su detalle.
No Señor. | Tipo de bucle y descripción |
---|---|
1 | en bucle Este ciclo realiza un conjunto de declaraciones para cada elemento de un conjunto de registros. |
2 | SOQL para bucle Ejecute una secuencia de declaraciones directamente sobre el conjunto devuelto o consulta SOQL. |
3 | Bucle for similar a Java Ejecute una secuencia de sentencias en sintaxis tradicional similar a Java. |
4 | while loop Repite una declaración o un grupo de declaraciones mientras una condición determinada es verdadera. Prueba la condición antes de ejecutar el cuerpo del bucle. |
5 | hacer ... mientras bucle Como una instrucción while, excepto que prueba la condición al final del cuerpo del bucle. |
Colecciones es un tipo de variable que puede almacenar varios registros. Por ejemplo, List puede almacenar varios registros del objeto Cuenta. Tengamos ahora una descripción detallada de todos los tipos de colecciones.
Liza
La lista puede contener cualquier número de registros primitivos, colecciones, sObjects, definidos por el usuario y construidos en tipo Apex. Este es uno de los tipos de recopilación más importantes y, además, tiene algunos métodos del sistema que se han diseñado específicamente para usar con List. El índice de lista siempre comienza con 0. Esto es sinónimo de la matriz en Java. Una lista debe declararse con la palabra clave 'Lista'.
Example
A continuación se muestra la lista que contiene la Lista de un tipo de datos primitivo (cadena), que es la lista de ciudades.
List<string> ListOfCities = new List<string>();
System.debug('Value Of ListOfCities'+ListOfCities);
Declarar los valores iniciales de la lista es opcional. Sin embargo, aquí declararemos los valores iniciales. A continuación se muestra un ejemplo que muestra lo mismo.
List<string> ListOfStates = new List<string> {'NY', 'LA', 'LV'};
System.debug('Value ListOfStates'+ListOfStates);
Lista de cuentas (sObject)
List<account> AccountToDelete = new List<account> (); //This will be null
System.debug('Value AccountToDelete'+AccountToDelete);
También podemos declarar la Lista anidada. Puede subir hasta cinco niveles. Esto se llama lista multidimensional.
Esta es la lista de conjuntos de números enteros.
List<List<Set<Integer>>> myNestedList = new List<List<Set<Integer>>>();
System.debug('value myNestedList'+myNestedList);
La lista puede contener cualquier número de registros, pero hay una limitación en el tamaño del montón para evitar problemas de rendimiento y monopolizar los recursos.
Métodos para listas
Hay métodos disponibles para las listas que podemos utilizar durante la programación para lograr algunas funcionalidades como calcular el tamaño de la lista, agregar un elemento, etc.
A continuación se muestran algunos de los métodos más utilizados:
- size()
- add()
- get()
- clear()
- set()
El siguiente ejemplo demuestra el uso de todos estos métodos.
// Initialize the List
List<string> ListOfStatesMethod = new List<string>();
// This statement would give null as output in Debug logs
System.debug('Value of List'+ ListOfStatesMethod);
// Add element to the list using add method
ListOfStatesMethod.add('New York');
ListOfStatesMethod.add('Ohio');
// This statement would give New York and Ohio as output in Debug logs
System.debug('Value of List with new States'+ ListOfStatesMethod);
// Get the element at the index 0
String StateAtFirstPosition = ListOfStatesMethod.get(0);
// This statement would give New York as output in Debug log
System.debug('Value of List at First Position'+ StateAtFirstPosition);
// set the element at 1 position
ListOfStatesMethod.set(0, 'LA');
// This statement would give output in Debug log
System.debug('Value of List with element set at First Position' + ListOfStatesMethod[0]);
// Remove all the elements in List
ListOfStatesMethod.clear();
// This statement would give output in Debug log
System.debug('Value of List'+ ListOfStatesMethod);
También puede usar la notación de matriz para declarar la Lista, como se indica a continuación, pero esto no es una práctica general en la programación de Apex:
String [] ListOfStates = new List<string>();
Conjuntos
Un conjunto es un tipo de colección que contiene varios registros únicos desordenados. Un conjunto no puede tener registros duplicados. Al igual que las listas, los conjuntos se pueden anidar.
Example
Definiremos el conjunto de productos que vende la empresa.
Set<string> ProductSet = new Set<string>{'Phenol', 'Benzene', 'H2SO4'};
System.debug('Value of ProductSet'+ProductSet);
Métodos para conjuntos
Set admite métodos que podemos utilizar durante la programación como se muestra a continuación (estamos ampliando el ejemplo anterior):
// Adds an element to the set
// Define set if not defined previously
Set<string> ProductSet = new Set<string>{'Phenol', 'Benzene', 'H2SO4'};
ProductSet.add('HCL');
System.debug('Set with New Value '+ProductSet);
// Removes an element from set
ProductSet.remove('HCL');
System.debug('Set with removed value '+ProductSet);
// Check whether set contains the particular element or not and returns true or false
ProductSet.contains('HCL');
System.debug('Value of Set with all values '+ProductSet);
Mapas
Es un par clave-valor que contiene la clave única para cada valor. Tanto la clave como el valor pueden ser de cualquier tipo de datos.
Example
El siguiente ejemplo representa el mapa del nombre del producto con el código del producto.
// Initialize the Map
Map<string, string> ProductCodeToProductName = new Map<string, string>
{'1000'=>'HCL', '1001'=>'H2SO4'};
// This statement would give as output as key value pair in Debug log
System.debug('value of ProductCodeToProductName'+ProductCodeToProductName);
Métodos para mapas
A continuación, se muestran algunos ejemplos que demuestran los métodos que se pueden usar con Map:
// Define a new map
Map<string, string> ProductCodeToProductName = new Map<string, string>();
// Insert a new key-value pair in the map where '1002' is key and 'Acetone' is value
ProductCodeToProductName.put('1002', 'Acetone');
// Insert a new key-value pair in the map where '1003' is key and 'Ketone' is value
ProductCodeToProductName.put('1003', 'Ketone');
// Assert that the map contains a specified key and respective value
System.assert(ProductCodeToProductName.containsKey('1002'));
System.debug('If output is true then Map contains the key and output is:'
+ ProductCodeToProductName.containsKey('1002'));
// Retrieves a value, given a particular key
String value = ProductCodeToProductName.get('1002');
System.debug('Value at the Specified key using get function: '+value);
// Return a set that contains all of the keys in the map
Set SetOfKeys = ProductCodeToProductName.keySet();
System.debug('Value of Set with Keys '+SetOfKeys);
Los valores del mapa pueden estar desordenados y, por lo tanto, no debemos confiar en el orden en el que se almacenan los valores e intentar acceder al mapa siempre utilizando claves. El valor del mapa puede ser nulo. Las claves de mapa cuando se declara String distinguen entre mayúsculas y minúsculas; por ejemplo, ABC y abc se considerarán claves diferentes y se tratarán como únicas.
¿Qué es una clase?
Una clase es una plantilla o plano a partir del cual se crean los objetos. Un objeto es una instancia de una clase. Ésta es la definición estándar de Clase. Las clases de Apex son similares a las clases de Java.
Por ejemplo, InvoiceProcessorclass describe la clase que tiene todos los métodos y acciones que se pueden realizar en la factura. Si crea una instancia de esta clase, representará la factura única que se encuentra actualmente en contexto.
Creando clases
Puede crear una clase en Apex desde Developer Console, Force.com Eclipse IDE y también desde la página de detalles de Apex Class.
Desde Developer Console
Siga estos pasos para crear una clase de Apex desde Developer Console:
Step 1 - Vaya a Nombre y haga clic en Developer Console.
Step 2 - Haga clic en Archivo ⇒ Nuevo y luego haga clic en la clase Apex.
De Force.com IDE
Siga estos pasos para crear una clase desde Force.com IDE:
Step 1 - Abra Force.com Eclipse IDE
Step 2 - Cree un nuevo proyecto haciendo clic en Archivo ⇒ Nuevo ⇒ Clase Apex.
Step 3 - Proporcione el nombre de la clase y haga clic en Aceptar.
Una vez hecho esto, se creará la nueva clase.
Desde la página de detalles de la clase de Apex
Siga estos pasos para crear una clase desde la página de detalles de clase de Apex:
Step 1 - Haga clic en Nombre ⇒ Configuración.
Step 2- Busque 'Apex Class' y haga clic en el enlace. Se abrirá la página de detalles de la clase Apex.
Step 3 - Haga clic en 'Nuevo' y luego proporcione el Nombre de la clase y luego haga clic en Guardar.
Estructura de clases de Apex
A continuación se muestra la estructura de muestra para la definición de clase de Apex.
Syntax
private | public | global
[virtual | abstract | with sharing | without sharing]
class ClassName [implements InterfaceNameList] [extends ClassName] {
// Classs Body
}
Esta definición utiliza una combinación de modificadores de acceso, modos de uso compartido, nombre de clase y cuerpo de clase. Analizaremos todas estas opciones más a fondo.
Example
A continuación se muestra una estructura de muestra para la definición de clase de Apex:
public class MySampleApexClass { //Class definition and body
public static Integer myValue = 0; //Class Member variable
public static String myString = ''; //Class Member variable
public static Integer getCalculatedValue () {
// Method definition and body
// do some calculation
myValue = myValue+10;
return myValue;
}
}
Modificadores de acceso
Privado
Si declara el modificador de acceso como 'Privado', entonces esta clase se conocerá solo localmente y no podrá acceder a esta clase fuera de esa pieza en particular. Por defecto, las clases tienen este modificador.
Público
Si declara la clase como 'Pública', esto implica que esta clase es accesible para su organización y su espacio de nombres definido. Normalmente, la mayoría de las clases de Apex se definen con esta palabra clave.
Global
Si declara la clase como 'global', todos los códigos de ápice podrán acceder a ella independientemente de su organización. Si tiene un método definido con la palabra clave del servicio web, debe declarar la clase contenedora con la palabra clave global.
Modos de compartir
Analicemos ahora los diferentes modos de compartir.
Con compartir
Esta es una función especial de las clases de Apex en Salesforce. Cuando una clase se especifica con la palabra clave 'Con uso compartido', tiene las siguientes implicaciones: Cuando la clase se ejecute, respetará la configuración de acceso del usuario y el permiso de perfil. Supongamos que la acción del usuario ha activado la actualización de registros para 30 registros, pero el usuario tiene acceso a solo 20 registros y 10 registros no son accesibles. Luego, si la clase está realizando la acción para actualizar los registros, solo se actualizarán 20 registros a los que el usuario tiene acceso y el resto de 10 registros no se actualizarán. Esto también se denomina modo de usuario.
Sin compartir
Incluso si el Usuario no tiene acceso a 10 registros de 30, todos los 30 registros se actualizarán mientras la Clase se ejecuta en el modo Sistema, es decir, se ha definido con la palabra clave Sin compartir. A esto se le llama Modo Sistema.
Virtual
Si usa la palabra clave 'virtual', indica que esta clase se puede extender y se permiten anulaciones. Si es necesario anular los métodos, las clases deben declararse con la palabra clave virtual.
Resumen
Si declara la clase como 'abstracta', solo contendrá la firma del método y no la implementación real.
Variables de clase
Syntax
[public | private | protected | global] [final] [static] data_type
variable_name [= value]
En la sintaxis anterior:
- El tipo de datos y el nombre de la variable son obligatorios
- Los modificadores de acceso y el valor son opcionales.
Example
public static final Integer myvalue;
Métodos de clase
Hay dos modificadores para los métodos de clase en Apex: público o protegido. El tipo de retorno es obligatorio para el método y si el método no devuelve nada, debe mencionar void como el tipo de retorno. Además, Body también es necesario para el método.
Syntax
[public | private | protected | global]
[override]
[static]
return_data_type method_name (input parameters) {
// Method body goes here
}
Explicación de la sintaxis
Los parámetros mencionados entre corchetes son opcionales. Sin embargo, los siguientes componentes son esenciales:
- return_data_type
- method_name
Modificadores de acceso para métodos de clase
Utilizando modificadores de acceso, puede especificar el nivel de acceso para los métodos de clase. Por ejemplo, se podrá acceder al método público desde cualquier lugar de la clase y fuera de ella. El método privado será accesible solo dentro de la clase. Global será accesible para todas las clases de Apex y se puede exponer como un método de servicio web accesible para otras clases de Apex.
Example
//Method definition and body
public static Integer getCalculatedValue () {
//do some calculation
myValue = myValue+10;
return myValue;
}
Este método tiene un tipo de retorno como Integer y no toma ningún parámetro.
Un método puede tener parámetros como se muestra en el siguiente ejemplo:
// Method definition and body, this method takes parameter price which will then be used
// in method.
public static Integer getCalculatedValueViaPrice (Decimal price) {
// do some calculation
myValue = myValue+price;
return myValue;
}
Constructores de clases
Un constructor es un código que se invoca cuando se crea un objeto a partir del plano de la clase. Tiene el mismo nombre que el nombre de la clase.
No necesitamos definir el constructor para cada clase, ya que por defecto se llama a un constructor sin argumentos. Los constructores son útiles para la inicialización de variables o cuando se debe realizar un proceso en el momento de la inicialización de la clase. Por ejemplo, le gustará asignar valores a ciertas variables Integer como 0 cuando se llame a la clase.
Example
// Class definition and body
public class MySampleApexClass2 {
public static Double myValue; // Class Member variable
public static String myString; // Class Member variable
public MySampleApexClass2 () {
myValue = 100; //initialized variable when class is called
}
public static Double getCalculatedValue () { // Method definition and body
// do some calculation
myValue = myValue+10;
return myValue;
}
public static Double getCalculatedValueViaPrice (Decimal price) {
// Method definition and body
// do some calculation
myValue = myValue+price; // Final Price would be 100+100=200.00
return myValue;
}
}
También puede llamar al método de clase a través del constructor. Esto puede resultar útil al programar Apex para el controlador de fuerza visual. Cuando se crea el objeto de clase, se llama al constructor como se muestra a continuación:
// Class and constructor has been instantiated
MySampleApexClass2 objClass = new MySampleApexClass2();
Double FinalPrice = MySampleApexClass2.getCalculatedValueViaPrice(100);
System.debug('FinalPrice: '+FinalPrice);
Constructores de sobrecarga
Los constructores pueden estar sobrecargados, es decir, una clase puede tener más de un constructor definido con diferentes parámetros.
Example
public class MySampleApexClass3 { // Class definition and body
public static Double myValue; // Class Member variable
public static String myString; // Class Member variable
public MySampleApexClass3 () {
myValue = 100; // initialized variable when class is called
System.debug('myValue variable with no Overaloading'+myValue);
}
public MySampleApexClass3 (Integer newPrice) { // Overloaded constructor
myValue = newPrice; // initialized variable when class is called
System.debug('myValue variable with Overaloading'+myValue);
}
public static Double getCalculatedValue () { // Method definition and body
// do some calculation
myValue = myValue+10;
return myValue;
}
public static Double getCalculatedValueViaPrice (Decimal price) {
// Method definition and body
// do some calculation
myValue = myValue+price;
return myValue;
}
}
Puede ejecutar esta clase como la hemos ejecutado en el ejemplo anterior.
// Developer Console Code
MySampleApexClass3 objClass = new MySampleApexClass3();
Double FinalPrice = MySampleApexClass3.getCalculatedValueViaPrice(100);
System.debug('FinalPrice: '+FinalPrice);
Una instancia de clase se llama Objeto. En términos de Salesforce, el objeto puede ser de clase o también puede crear un objeto de sObject.
Creación de objetos desde clase
Puede crear un objeto de clase como podría haberlo hecho en Java u otro lenguaje de programación orientado a objetos.
A continuación se muestra una clase de ejemplo llamada MyClass:
// Sample Class Example
public class MyClass {
Integer myInteger = 10;
public void myMethod (Integer multiplier) {
Integer multiplicationResult;
multiplicationResult = multiplier*myInteger;
System.debug('Multiplication is '+multiplicationResult);
}
}
Esta es una clase de instancia, es decir, para llamar o acceder a las variables o métodos de esta clase, debe crear una instancia de esta clase y luego puede realizar todas las operaciones.
// Object Creation
// Creating an object of class
MyClass objClass = new MyClass();
// Calling Class method using Class instance
objClass.myMethod(100);
sCreación de objetos
sObjects son los objetos de Salesforce en los que almacena los datos. Por ejemplo, Cuenta, Contacto, etc., son objetos personalizados. Puede crear instancias de objeto de estos sObjects.
A continuación se muestra un ejemplo de inicialización de sObject y se muestra cómo puede acceder al campo de ese objeto en particular usando notación de puntos y asignar los valores a los campos.
// Execute the below code in Developer console by simply pasting it
// Standard Object Initialization for Account sObject
Account objAccount = new Account(); // Object initialization
objAccount.Name = 'Testr Account'; // Assigning the value to field Name of Account
objAccount.Description = 'Test Account';
insert objAccount; // Creating record using DML
System.debug('Records Has been created '+objAccount);
// Custom sObject initialization and assignment of values to field
APEX_Customer_c objCustomer = new APEX_Customer_c ();
objCustomer.Name = 'ABC Customer';
objCustomer.APEX_Customer_Decscription_c = 'Test Description';
insert objCustomer;
System.debug('Records Has been created '+objCustomer);
Inicialización estática
Los métodos y variables estáticos se inicializan solo una vez cuando se carga una clase. Las variables estáticas no se transmiten como parte del estado de vista de una página de Visualforce.
A continuación se muestra un ejemplo de método estático y variable estática.
// Sample Class Example with Static Method
public class MyStaticClass {
Static Integer myInteger = 10;
public static void myMethod (Integer multiplier) {
Integer multiplicationResult;
multiplicationResult = multiplier * myInteger;
System.debug('Multiplication is '+multiplicationResult);
}
}
// Calling the Class Method using Class Name and not using the instance object
MyStaticClass.myMethod(100);
Static Variable Use
Las variables estáticas se instanciarán solo una vez cuando se cargue la clase y este fenómeno se puede usar para evitar la recursividad del disparador. El valor de la variable estática será el mismo dentro del mismo contexto de ejecución y cualquier clase, disparador o código que se esté ejecutando puede referirse a él y evitar la recursividad.
Una interfaz es como una clase de Apex en la que no se ha implementado ninguno de los métodos. Solo contiene las firmas del método, pero el cuerpo de cada método está vacío. Para usar una interfaz, otra clase debe implementarla proporcionando un cuerpo para todos los métodos contenidos en la interfaz.
Las interfaces se utilizan principalmente para proporcionar la capa de abstracción para su código. Separan la implementación de la declaración del método.
Tomemos un ejemplo de nuestra empresa química. Supongamos que necesitamos proporcionar el descuento a los clientes Premium y Ordinarios y los descuentos para ambos serán diferentes.
Crearemos una interfaz llamada DiscountProcessor.
// Interface
public interface DiscountProcessor {
Double percentageDiscountTobeApplied(); // method signature only
}
// Premium Customer Class
public class PremiumCustomer implements DiscountProcessor {
//Method Call
public Double percentageDiscountTobeApplied () {
// For Premium customer, discount should be 30%
return 0.30;
}
}
// Normal Customer Class
public class NormalCustomer implements DiscountProcessor {
// Method Call
public Double percentageDiscountTobeApplied () {
// For Premium customer, discount should be 10%
return 0.10;
}
}
Cuando implementa la interfaz, es obligatorio implementar el método de esa interfaz. Si no implementa los métodos de interfaz, arrojará un error. Debe utilizar Interfaces cuando desee que la implementación del método sea obligatoria para el desarrollador.
Interfaz estándar de Salesforce para Batch Apex
SFDC tiene interfaces estándar como Database.Batchable, Schedulable, etc. Por ejemplo, si implementa la interfaz Database.Batchable, entonces debe implementar los tres métodos definidos en la Interfaz: Inicio, Ejecución y Finalización.
A continuación, se muestra un ejemplo de la interfaz de base de datos estándar provista por Salesforce que envía correos electrónicos a los usuarios con el estado del lote. Esta interfaz tiene 3 métodos, Iniciar, Ejecutar y Finalizar. Usando esta interfaz, podemos implementar la funcionalidad Batchable y también proporciona la variable BatchableContext que podemos usar para obtener más información sobre el Batch que se está ejecutando y para realizar otras funcionalidades.
global class CustomerProessingBatch implements Database.Batchable<sobject7>,
Schedulable {
// Add here your email address
global String [] email = new String[] {'[email protected]'};
// Start Method
global Database.Querylocator start (Database.BatchableContext BC) {
// This is the Query which will determine the scope of Records and fetching the same
return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c,
APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today
&& APEX_Active__c = true');
}
// Execute method
global void execute (Database.BatchableContext BC, List<sobject> scope) {
List<apex_customer__c> customerList = new List<apex_customer__c>();
List<apex_customer__c> updtaedCustomerList = new List<apex_customer__c>();
for (sObject objScope: scope) {
// type casting from generic sOject to APEX_Customer__c
APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ;
newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job';
newObjScope.APEX_Customer_Status__c = 'Processed';
// Add records to the List
updtaedCustomerList.add(newObjScope);
}
// Check if List is empty or not
if (updtaedCustomerList != null && updtaedCustomerList.size()>0) {
// Update the Records
Database.update(updtaedCustomerList); System.debug('List Size
'+updtaedCustomerList.size());
}
}
// Finish Method
global void finish(Database.BatchableContext BC) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
// get the job Id
AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors,
a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById,
a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()];
System.debug('$$$ Jobid is'+BC.getJobId());
// below code will send an email to User about the status
mail.setToAddresses(email);
// Add here your email address
mail.setReplyTo('[email protected]');
mail.setSenderDisplayName('Apex Batch Processing Module');
mail.setSubject('Batch Processing '+a.Status);
mail.setPlainTextBody('The Batch Apex job processed
'+a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item
processed are'+a.JobItemsProcessed);
Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail});
}
// Scheduler Method to scedule the class
global void execute(SchedulableContext sc) {
CustomerProessingBatch conInstance = new CustomerProessingBatch();
database.executebatch(conInstance,100);
}
}
Para ejecutar esta clase, debe ejecutar el siguiente código en Developer Console.
CustomerProessingBatch objBatch = new CustomerProessingBatch ();
Database.executeBatch(objBatch);
En este capítulo, discutiremos cómo realizar las diferentes funcionalidades de modificación de la base de datos en Salesforce. Hay dos dice con los que podemos realizar las funcionalidades.
Declaraciones DML
DML son las acciones que se realizan para realizar la operación de inserción, actualización, eliminación, actualización, restauración de registros, combinación de registros o conversión de clientes potenciales.
DML es una de las partes más importantes de Apex, ya que casi todos los casos comerciales implican cambios y modificaciones en la base de datos.
Métodos de base de datos
Todas las operaciones que puede realizar utilizando declaraciones DML también se pueden realizar utilizando métodos de base de datos. Los métodos de base de datos son los métodos del sistema que puede utilizar para realizar operaciones DML. Los métodos de base de datos proporcionan más flexibilidad en comparación con las declaraciones DML.
En este capítulo, veremos el primer enfoque utilizando declaraciones DML. Veremos los métodos de la base de datos en un capítulo posterior.
Declaraciones DML
Consideremos ahora nuevamente el caso de la empresa proveedora de productos químicos. Nuestros registros de facturas tienen campos como Estado, Monto pagado, Monto restante, Próxima fecha de pago y Número de factura. Las facturas que se han creado hoy y tienen su estado como 'Pendiente', deben actualizarse a 'Pagadas'.
Insertar operación
La operación de inserción se utiliza para crear nuevos registros en la base de datos. Puede crear registros de cualquier objeto estándar o personalizado utilizando la instrucción Insert DML.
Example
Podemos crear nuevos registros en el objeto APEX_Invoice__c a medida que se generan nuevas facturas para los pedidos de nuevos clientes todos los días. Primero crearemos un registro de Cliente y luego podemos crear un registro de Factura para ese nuevo registro de Cliente.
// fetch the invoices created today, Note, you must have at least one invoice
// created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c WHERE createdDate = today];
// create List to hold the updated invoice records
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test ABC';
//DML for Inserting the new Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
if (objInvoice.APEX_Status__c == 'Pending') {
objInvoice.APEX_Status__c = 'Paid';
updatedInvoiceList.add(objInvoice);
}
}
// DML Statement to update the invoice status
update updatedInvoiceList;
// Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);
// Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;
// DML which is creating the new Invoice record which will be linked with newly
// created Customer record
insert objNewInvoice;
System.debug('New Invoice Id is '+objNewInvoice.id+' and the Invoice Number is'
+ objNewInvoice.Name);
Operación de actualización
La operación de actualización consiste en realizar actualizaciones en los registros existentes. En este ejemplo, actualizaremos el campo Estado de un registro de factura existente a 'Pagado'.
Example
// Update Statement Example for updating the invoice status. You have to create
and Invoice records before executing this code. This program is updating the
record which is at index 0th position of the List.
// First, fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
// Update the first record in the List
invoiceList[0].APEX_Status__c = 'Pending';
updatedInvoiceList.add(invoiceList[0]);
// DML Statement to update the invoice status
update updatedInvoiceList;
// Prints the value of updated invoices
System.debug('List has been updated and updated values of records are'
+ updatedInvoiceList[0]);
Operación Upsert
Upsert Operation se utiliza para realizar una operación de actualización y, si los registros que se actualizarán no están presentes en la base de datos, también se crearán nuevos registros.
Example
Supongamos que los registros de clientes en el objeto Cliente deben actualizarse. Actualizaremos el registro de Cliente existente si ya está presente; de lo contrario, crearemos uno nuevo. Esto se basará en el valor del campo APEX_External_Id__c. Este campo será nuestro campo para identificar si los registros ya están presentes o no.
Note - Antes de ejecutar este código, cree un registro en el objeto Cliente con el valor del campo de Id externo como '12341' y luego ejecute el código que se proporciona a continuación -
// Example for upserting the Customer records
List<apex_customer__c> CustomerList = new List<apex_customer__c>();
for (Integer i = 0; i < 10; i++) {
apex_customer__c objcust=new apex_customer__c(name = 'Test' +i,
apex_external_id__c='1234' +i);
customerlist.add(objcust);
} //Upserting the Customer Records
upsert CustomerList;
System.debug('Code iterated for 10 times and created 9 records as one record with
External Id 12341 is already present');
for (APEX_Customer_c objCustomer: CustomerList) {
if (objCustomer.APEX_External_Id_c == '12341') {
system.debug('The Record which is already present is '+objCustomer);
}
}
Eliminar operación
Puede realizar la operación de eliminación utilizando Delete DML.
Example
En este caso, eliminaremos las facturas que se han creado con el propósito de probar, es decir, las que contienen el nombre como 'Prueba'.
También puede ejecutar este fragmento desde la consola del desarrollador sin crear la clase.
// fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c WHERE createdDate = today];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';
// Inserting the Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
if (objInvoice.APEX_Status__c == 'Pending') {
objInvoice.APEX_Status__c = 'Paid';
updatedInvoiceList.add(objInvoice);
}
}
// DML Statement to update the invoice status
update updatedInvoiceList;
// Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);
// Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;
// DML which is creating the new record
insert objNewInvoice;
System.debug('New Invoice Id is' + objNewInvoice.id);
// Deleting the Test invoices from Database
// fetch the invoices which are created for Testing, Select name which Customer Name
// is Test.
List<apex_invoice__c> invoiceListToDelete = [SELECT id FROM APEX_Invoice__c
WHERE APEX_Customer__r.Name = 'Test'];
// DML Statement to delete the Invoices
delete invoiceListToDelete;
System.debug('Success, '+invoiceListToDelete.size()+' Records has been deleted');
Recuperar operación
Puede recuperar el registro que se ha eliminado y está presente en la Papelera de reciclaje. También se restaurarán todas las relaciones que tiene el registro eliminado.
Example
Supongamos que es necesario restaurar los registros eliminados en el ejemplo anterior. Esto se puede lograr usando el siguiente ejemplo. El código del ejemplo anterior se ha modificado para este ejemplo.
// fetch the invoice created today
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c WHERE createdDate = today];
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';
// Inserting the Customer Records
insert objCust;
for (APEX_Invoice__c objInvoice: invoiceList) {
if (objInvoice.APEX_Status__c == 'Pending') {
objInvoice.APEX_Status__c = 'Paid';
updatedInvoiceList.add(objInvoice);
}
}
// DML Statement to update the invoice status
update updatedInvoiceList;
// Prints the value of updated invoices
System.debug('List has been updated and updated values are' + updatedInvoiceList);
// Inserting the New Records using insert DML statement
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Amount_Paid__c = 1000;
objNewInvoice.APEX_Customer__c = objCust.id;
// DML which is creating the new record
insert objNewInvoice;
System.debug('New Invoice Id is '+objNewInvoice.id);
// Deleting the Test invoices from Database
// fetch the invoices which are created for Testing, Select name which Customer Name
// is Test.
List<apex_invoice__c> invoiceListToDelete = [SELECT id FROM APEX_Invoice__c
WHERE APEX_Customer__r.Name = 'Test'];
// DML Statement to delete the Invoices
delete invoiceListToDelete;
system.debug('Deleted Record Count is ' + invoiceListToDelete.size());
System.debug('Success, '+invoiceListToDelete.size() + 'Records has been deleted');
// Restore the deleted records using undelete statement
undelete invoiceListToDelete;
System.debug('Undeleted Record count is '+invoiceListToDelete.size()+'. This should
be same as Deleted Record count');
Los métodos de clase de base de datos son otra forma de trabajar con declaraciones DML que son más flexibles que declaraciones DML como insertar, actualizar, etc.
Diferencias entre métodos de base de datos y declaraciones DML
Declaraciones DML | Métodos de base de datos |
---|---|
No se permite la actualización parcial. Por ejemplo, si tiene 20 registros en la lista, se actualizarán todos los registros o ninguno. | Se permite la actualización parcial. Puede especificar el método Parameter in Database como verdadero o falso, verdadero para permitir la actualización parcial y falso para no permitir lo mismo. |
No puede obtener la lista de registros correctos y fallidos. | Puede obtener la lista de registros correctos y fallidos como hemos visto en el ejemplo. |
Example - insertar listName | Example - Database.insert (listName, False), donde falso indica que no se permite la actualización parcial. |
Insertar operación
Insertar nuevos registros a través de métodos de base de datos también es bastante simple y flexible. Consideremos el escenario anterior en el que hemos insertado nuevos registros utilizando las declaraciones DML. Insertaremos lo mismo usando métodos de base de datos.
Ejemplo
// Insert Operation Using Database methods
// Insert Customer Records First using simple DML Statement. This Customer Record will be
// used when we will create Invoice Records
APEX_Customer__c objCust = new APEX_Customer__C();
objCust.Name = 'Test';
insert objCust; // Inserting the Customer Records
// Insert Operation Using Database methods
APEX_Invoice__c objNewInvoice = new APEX_Invoice__c();
List<apex_invoice__c> InvoiceListToInsert = new List<apex_invoice__c>();
objNewInvoice.APEX_Status__c = 'Pending';
objNewInvoice.APEX_Customer__c = objCust.id;
objNewInvoice.APEX_Amount_Paid__c = 1000;
InvoiceListToInsert.add(objNewInvoice);
Database.SaveResult[] srList = Database.insert(InvoiceListToInsert, false);
// Database method to insert the records in List
// Iterate through each returned result by the method
for (Database.SaveResult sr : srList) {
if (sr.isSuccess()) {
// This condition will be executed for successful records and will fetch the ids
// of successful records
System.debug('Successfully inserted Invoice. Invoice ID: ' + sr.getId());
// Get the invoice id of inserted Account
} else {
// This condition will be executed for failed records
for(Database.Error objErr : sr.getErrors()) {
System.debug('The following error has occurred.');
// Printing error message in Debug log
System.debug(objErr.getStatusCode() + ': ' + objErr.getMessage());
System.debug('Invoice oject field which are affected by the error:'
+ objErr.getFields());
}
}
}
Operación de actualización
Consideremos ahora nuestro ejemplo de caso de negocio utilizando los métodos de base de datos. Supongamos que necesitamos actualizar el campo de estado del objeto Factura pero, al mismo tiempo, también necesitamos información como el estado de los registros, ID de registros fallidos, recuento de éxitos, etc. para conocer el estado de nuestra operación.
Ejemplo
Actualizaremos el campo 'Estado' de la factura si está en estado 'Pendiente' y la fecha de creación es hoy.
El código que se proporciona a continuación ayudará a actualizar los registros de facturas utilizando el método Database.update. Además, cree un registro de factura antes de ejecutar este código.
// Code to update the records using the Database methods
List<apex_invoice__c> invoiceList = [SELECT id, Name, APEX_Status__c,
createdDate FROM APEX_Invoice__c WHERE createdDate = today];
// fetch the invoice created today
List<apex_invoice__c> updatedInvoiceList = new List<apex_invoice__c>();
for (APEX_Invoice__c objInvoice: invoiceList) {
if (objInvoice.APEX_Status__c == 'Pending') {
objInvoice.APEX_Status__c = 'Paid';
updatedInvoiceList.add(objInvoice); //Adding records to the list
}
}
Database.SaveResult[] srList = Database.update(updatedInvoiceList, false);
// Database method to update the records in List
// Iterate through each returned result by the method
for (Database.SaveResult sr : srList) {
if (sr.isSuccess()) {
// This condition will be executed for successful records and will fetch
// the ids of successful records
System.debug('Successfully updated Invoice. Invoice ID is : ' + sr.getId());
} else {
// This condition will be executed for failed records
for(Database.Error objErr : sr.getErrors()) {
System.debug('The following error has occurred.');
// Printing error message in Debug log
System.debug(objErr.getStatusCode() + ': ' + objErr.getMessage());
System.debug('Invoice oject field which are affected by the error:'
+ objErr.getFields());
}
}
}
En este tutorial solo veremos las operaciones Insertar y Actualizar. Las otras operaciones son bastante similares a estas operaciones y a lo que hicimos en el capítulo anterior.
Cada negocio o aplicación tiene la funcionalidad de búsqueda como uno de los requisitos básicos. Para esto, Salesforce.com proporciona dos enfoques principales que utilizan SOSL y SOQL. Analicemos el enfoque SOSL en detalle en este capítulo.
SOSL
La búsqueda de la cadena de texto en el objeto y en el campo se realizará mediante SOSL. Este es el lenguaje de búsqueda de objetos de Salesforce. Tiene la capacidad de buscar una cadena particular en múltiples objetos.
Las sentencias SOSL se evalúan en una lista de sObjects, en donde, cada lista contiene los resultados de búsqueda para un tipo de sObject en particular. Las listas de resultados siempre se devuelven en el mismo orden en que se especificaron en la consulta SOSL.
Ejemplo de consulta SOSL
Considere un caso de negocios en el que necesitamos desarrollar un programa que pueda buscar una cadena específica. Supongamos que necesitamos buscar la cadena 'ABC' en el campo Nombre del cliente del objeto Factura. El código es el siguiente:
Primero, debe crear un solo registro en el objeto Factura con el nombre del cliente como 'ABC' para que podamos obtener un resultado válido cuando se busque.
// Program To Search the given string in all Object
// List to hold the returned results of sObject generic type
List<list<SObject>> invoiceSearchList = new List<List<SObject>>();
// SOSL query which will search for 'ABC' string in Customer Name field of Invoice Object
invoiceSearchList = [FIND 'ABC*' IN ALL FIELDS RETURNING APEX_Invoice_c
(Id,APEX_Customer_r.Name)];
// Returned result will be printed
System.debug('Search Result '+invoiceSearchList);
// Now suppose, you would like to search string 'ABC' in two objects,
// that is Invoice and Account. Then for this query goes like this:
// Program To Search the given string in Invoice and Account object,
// you could specify more objects if you want, create an Account with Name as ABC.
// List to hold the returned results of sObject generic type
List<List<SObject>> invoiceAndSearchList = new List<List<SObject>>();
// SOSL query which will search for 'ABC' string in Invoice and in Account object's fields
invoiceAndSearchList = [FIND 'ABC*' IN ALL FIELDS RETURNING APEX_Invoice__c
(Id,APEX_Customer__r.Name), Account];
// Returned result will be printed
System.debug('Search Result '+invoiceAndSearchList);
// This list will hold the returned results for Invoice Object
APEX_Invoice__c [] searchedInvoice = ((List<APEX_Invoice_c>)invoiceAndSearchList[0]);
// This list will hold the returned results for Account Object
Account [] searchedAccount = ((List<Account>)invoiceAndSearchList[1]);
System.debug('Value of searchedInvoice'+searchedInvoice+'Value of searchedAccount'
+ searchedAccount);
SOQL
Esto es casi lo mismo que SOQL. Puede usar esto para recuperar los registros de objetos de un objeto solo a la vez. Puede escribir consultas anidadas y también recuperar los registros del objeto principal o secundario en el que está consultando ahora.
Exploraremos SOQL en el próximo capítulo.
Este es el lenguaje de consulta de objetos de Salesforce diseñado para funcionar con la base de datos SFDC. Puede buscar un registro en un criterio dado solo en un solo sObject.
Al igual que SOSL, no puede buscar en varios objetos, pero admite consultas anidadas.
Ejemplo SOQL
Considere nuestro ejemplo continuo de Chemical Company. Supongamos que necesitamos una lista de registros que se crean hoy y cuyo nombre de cliente no es 'prueba'. En este caso, tendremos que usar la consulta SOQL como se indica a continuación:
// fetching the Records via SOQL
List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
InvoiceList = [SELECT Id, Name, APEX_Customer__r.Name, APEX_Status__c FROM
APEX_Invoice__c WHERE createdDate = today AND APEX_Customer__r.Name != 'Test'];
// SOQL query for given criteria
// Printing the fetched records
System.debug('We have total '+InvoiceList.size()+' Records in List');
for (APEX_Invoice__c objInvoice: InvoiceList) {
System.debug('Record Value is '+objInvoice);
// Printing the Record fetched
}
Puede ejecutar la consulta SOQL a través del Editor de consultas en la consola del desarrollador como se muestra a continuación.
Ejecute la consulta que se indica a continuación en Developer Console. Busque los registros de facturas creados hoy.
SELECT Id, Name, APEX_Customer__r.Name, APEX_Status__c FROM APEX_Invoice__c
WHERE createdDate = today
Debe seleccionar los campos para los que necesita los valores, de lo contrario, puede arrojar errores de tiempo de ejecución.
Atravesando campos de relaciones
Esta es una de las partes más importantes en SFDC, ya que muchas veces necesitamos atravesar la relación de objeto padre-hijo.
Además, puede haber casos en los que necesite insertar dos registros de objetos asociados en la base de datos. Por ejemplo, el objeto Factura tiene relación con el objeto Cliente y, por lo tanto, un Cliente puede tener muchas facturas.
Supongamos que está creando la factura y luego necesita relacionar esta factura con el Cliente. Puede utilizar el siguiente código para esta funcionalidad:
// Now create the invoice record and relate it with the Customer object
// Before executing this, please create a Customer Records with Name 'Customer
// Creation Test'
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
// Relating Invoice to customer via id field of Customer object
objInvoice.APEX_Customer__c = [SELECT id FROM APEX_Customer__c WHERE Name =
'Customer Creation Test' LIMIT 1].id;
objInvoice.APEX_Status__c = 'Pending';
insert objInvoice; //Creating Invoice
System.debug('Newly Created Invoice'+objInvoice); //Newly created invoice
Ejecute este fragmento de código en Developer Console. Una vez ejecutado, copie el ID de la factura desde la consola del desarrollador y luego abra el mismo en SFDC como se muestra a continuación. Puede ver que el registro principal ya se ha asignado al registro de factura como se muestra a continuación.
Obteniendo registros secundarios
Consideremos ahora un ejemplo en el que todas las facturas relacionadas con el registro de un cliente en particular deben estar en un solo lugar. Para ello, debe conocer el nombre de la relación secundaria. Para ver el nombre de la relación secundaria, vaya a la página de detalles del campo en el objeto secundario y verifique el valor "Relación secundaria". En nuestro ejemplo, son las facturas agregadas por __r al final.
Ejemplo
En este ejemplo, necesitaremos configurar datos, crear un cliente con el nombre como registro 'Cliente ABC' y luego agregar 3 facturas a ese cliente.
Ahora, buscaremos las facturas que tiene el Cliente 'Cliente ABC'. A continuación se muestra la consulta para el mismo:
// Fetching Child Records using SOQL
List<apex_customer__c> ListCustomers = [SELECT Name, Id,
(SELECT id, Name FROM Invoices__r) FROM APEX_Customer__c WHERE Name = 'ABC Customer'];
// Query for fetching the Child records along with Parent
System.debug('ListCustomers '+ListCustomers); // Parent Record
List<apex_invoice__c> ListOfInvoices = ListCustomers[0].Invoices__r;
// By this notation, you could fetch the child records and save it in List
System.debug('ListOfInvoices values of Child '+ListOfInvoices);
// Child records
Puede ver los valores de registro en los registros de depuración.
Obteniendo registro principal
Supongamos que necesita obtener el nombre del cliente de la factura cuya fecha de creación es hoy, luego puede usar la consulta que se proporciona a continuación para la misma:
Ejemplo
Obtenga el valor del registro principal junto con el objeto secundario.
// Fetching Parent Record Field value using SOQL
List<apex_invoice__c> ListOfInvoicesWithCustomerName = new List<apex_invoice__c>();
ListOfInvoicesWithCustomerName = [SELECT Name, id, APEX_Customer__r.Name
FROM APEX_Invoice__c LIMIT 10];
// Fetching the Parent record's values
for (APEX_Invoice__c objInv: ListOfInvoicesWithCustomerName) {
System.debug('Invoice Customer Name is '+objInv.APEX_Customer__r.Name);
// Will print the values, all the Customer Records will be printed
}
Aquí hemos utilizado la notación APEX_Customer__r.Name, donde APEX_Customer__r es el nombre de la relación principal, aquí debe agregar el __r al final del campo principal y luego puede obtener el valor del campo principal.
Funciones agregadas
SOQL tiene una función agregada como la tenemos en SQL. Las funciones agregadas nos permiten acumular y resumir los datos. Entendamos ahora la función en detalle.
Suponga que desea saber cuál es el ingreso promedio que obtenemos del Cliente 'Cliente ABC', luego puede usar esta función para tomar el promedio.
Ejemplo
// Getting Average of all the invoices for a Perticular Customer
AggregateResult[] groupedResults = [SELECT
AVG(APEX_Amount_Paid__c)averageAmount FROM APEX_Invoice__c WHERE
APEX_Customer__r.Name = 'ABC Customer'];
Object avgPaidAmount = groupedResults[0].get('averageAmount');
System.debug('Total Average Amount Received From Customer ABC is '+avgPaidAmount);
Verifique el resultado en los registros de depuración. Tenga en cuenta que cualquier consulta que incluya una función agregada devuelve sus resultados en una matriz deAggregateResultobjetos. AggregateResult es un sObject de solo lectura y solo se usa para resultados de consultas. Es útil cuando necesitamos generar el Informe sobre datos grandes.
También hay otras funciones agregadas que puede utilizar para realizar un resumen de datos.
MIN() - Esto se puede usar para encontrar el valor mínimo
MAX() - Esto se puede usar para encontrar el valor máximo.
Vinculación de variables de Apex
Puede utilizar la variable Apex en la consulta SOQL para obtener los resultados deseados. Se puede hacer referencia a las variables de Apex mediante la notación de dos puntos (:).
Ejemplo
// Apex Variable Reference
String CustomerName = 'ABC Customer';
List<apex_customer__c> ListCustomer = [SELECT Id, Name FROM APEX_Customer__c
WHERE Name = :CustomerName];
// Query Using Apex variable
System.debug('ListCustomer Name'+ListCustomer); // Customer Name
La seguridad de Apex se refiere al proceso de aplicar la configuración de seguridad y hacer cumplir las reglas de uso compartido en el código en ejecución. Las clases de Apex tienen una configuración de seguridad que se puede controlar mediante dos palabras clave.
Reglas de seguridad y uso compartido de datos
Apex generalmente se ejecuta en el contexto del sistema, es decir, los permisos del usuario actual. La seguridad a nivel de campo y las reglas de uso compartido no se tienen en cuenta durante la ejecución del código. Solo el código de bloque anónimo se ejecuta con el permiso del usuario que está ejecutando el código.
Nuestro código Apex no debe exponer los datos confidenciales al usuario que están ocultos a través de la configuración de seguridad y uso compartido. Por lo tanto, la seguridad de Apex y el cumplimiento de la regla de uso compartido es lo más importante.
Con compartir palabra clave
Si utiliza esta palabra clave, el código Apex aplicará la configuración de uso compartido del usuario actual al código Apex. Esto no aplica el permiso del perfil, solo la configuración de uso compartido del nivel de datos.
Consideremos un ejemplo en el que nuestro usuario tiene acceso a 5 registros, pero el número total de registros es 10. Por lo tanto, cuando la clase Apex se declare con la palabra clave "With Sharing", devolverá solo 5 registros en los que el usuario tiene acceso a.
Example
Primero, asegúrese de haber creado al menos 10 registros en el objeto Cliente con 'Nombre' de 5 registros como 'Cliente ABC' y el resto de 5 registros como 'Cliente XYZ'. Luego, cree una regla para compartir que compartirá el 'Cliente ABC' con todos los usuarios. También debemos asegurarnos de haber configurado el objeto OWD del cliente como Privado.
Pegue el código que se proporciona a continuación en el bloque Anónimo en la Consola del desarrollador.
// Class With Sharing
public with sharing class MyClassWithSharing {
// Query To fetch 10 records
List<apex_customer__c> CustomerList = [SELECT id, Name FROM APEX_Customer__c LIMIT 10];
public Integer executeQuery () {
System.debug('List will have only 5 records and the actual records are'
+ CustomerList.size()+' as user has access to'+CustomerList);
Integer ListSize = CustomerList.size();
return ListSize;
}
}
// Save the above class and then execute as below
// Execute class using the object of class
MyClassWithSharing obj = new MyClassWithSharing();
Integer ListSize = obj.executeQuery();
Sin compartir palabra clave
Como sugiere el nombre, la clase declarada con esta palabra clave se ejecuta en modo Sistema, es decir, independientemente del acceso del usuario al registro, la consulta buscará todos los registros.
// Class Without Sharing
public without sharing class MyClassWithoutSharing {
List<apex_customer__c> CustomerList = [SELECT id, Name FROM APEX_Customer__c LIMIT 10];
// Query To fetch 10 records, this will return all the records
public Integer executeQuery () {
System.debug('List will have only 5 records and the actula records are'
+ CustomerList.size()+' as user has access to'+CustomerList);
Integer ListSize = CustomerList.size();
return ListSize;
}
}
// Output will be 10 records.
Configuración de seguridad para la clase Apex
Puede habilitar o deshabilitar una clase de Apex para un perfil en particular. Los pasos para el mismo se dan a continuación. Puede determinar qué perfil debe tener acceso a qué clase.
Configuración de la seguridad de la clase Apex desde la página de lista de clases
Step 1 - Desde Configuración, haga clic en Desarrollar → Clases de Apex.
Step 2- Haga clic en el nombre de la clase que desea restringir. Hemos hecho clic en CustomerOperationClass.
Step 3 - Haga clic en Seguridad.
Step 4 - Seleccione los perfiles que desea habilitar de la lista Perfiles disponibles y haga clic en Agregar, o seleccione los perfiles que desea deshabilitar de la lista Perfiles habilitados y haga clic en Eliminar.
Step 5 - Haga clic en Guardar.
Configuración de la seguridad de Apex desde el conjunto de permisos
Step 1 - Desde Configuración, haga clic en Administrar usuarios → Conjuntos de permisos.
Step 2 - Seleccione un conjunto de permisos.
Step 3 - Haga clic en Apex Class Access.
Step 4 - Haga clic en Editar.
Step 5 - Seleccione las clases de Apex que desea habilitar de la lista de Clases de Apex disponibles y haga clic en Agregar, o seleccione las clases de Apex que desea deshabilitar de la lista de Clases de Apex habilitadas y haga clic en eliminar.
Step 6 - Haga clic en el botón Guardar.
La invocación de Apex se refiere al proceso de ejecución de la clase Apex. La clase Apex solo se puede ejecutar cuando se invoca a través de una de las formas que se enumeran a continuación:
Desencadenadores y bloqueo anónimo
Un disparador invocado para eventos específicos
Apex asincrónico
Programar una clase de Apex para que se ejecute a intervalos específicos o ejecutar un trabajo por lotes
Clase de servicios web
Clase de servicio de correo electrónico de Apex
Servicios web Apex, que permiten exponer sus métodos a través de servicios web SOAP y REST
Controladores de Visualforce
Servicio de correo electrónico Apex para procesar el correo electrónico entrante
Invocar Apex mediante JavaScript
El kit de herramientas Ajax para invocar métodos de servicios web implementados en Apex
Ahora entenderemos algunas formas comunes de invocar Apex.
Desde Ejecutar bloque anónimo
Puede invocar la clase Apex mediante la ejecución anónima en la Consola del desarrollador como se muestra a continuación:
Step 1 - Abra la Consola de desarrollador.
Step 2 - Haga clic en Depurar.
Step 3- Se abrirá la ventana Ejecutar anónimo como se muestra a continuación. Ahora, haga clic en el botón Ejecutar -
Step 4 - Abra el registro de depuración cuando aparezca en el panel Registros.
Desde Trigger
También puede llamar a una clase de Apex desde Trigger. Los disparadores se llaman cuando ocurre un evento específico y los disparadores pueden llamar a la clase Apex cuando se ejecuta.
A continuación se muestra el código de muestra que muestra cómo se ejecuta una clase cuando se llama a un Trigger.
Ejemplo
// Class which will gets called from trigger
public without sharing class MyClassWithSharingTrigger {
public static Integer executeQuery (List<apex_customer__c> CustomerList) {
// perform some logic and operations here
Integer ListSize = CustomerList.size();
return ListSize;
}
}
// Trigger Code
trigger Customer_After_Insert_Example on APEX_Customer__c (after insert) {
System.debug('Trigger is Called and it will call Apex Class');
MyClassWithSharingTrigger.executeQuery(Trigger.new); // Calling Apex class and
// method of an Apex class
}
// This example is for reference, no need to execute and will have detail look on
// triggers later chapters.
Desde el código del controlador de página de Visualforce
La clase Apex también se puede llamar desde la página de Visualforce. Podemos especificar el controlador o la extensión del controlador y se llama a la clase de Apex especificada.
Ejemplo
VF Page Code
Apex Class Code (Controller Extension)
Los disparadores de Apex son como procedimientos almacenados que se ejecutan cuando ocurre un evento en particular. Un disparador se ejecuta antes y después de que ocurra un evento registrado.
Sintaxis
trigger triggerName on ObjectName (trigger_events) { Trigger_code_block }
Ejecutando el gatillo
Los siguientes son los eventos en los que podemos disparar el gatillo:
- insert
- update
- delete
- merge
- upsert
- undelete
Ejemplo de activador 1
Supongamos que recibimos un requisito comercial de que debemos crear un registro de factura cuando el campo 'Estado del cliente' del cliente cambia a Activo de Inactivo. Para esto, crearemos un disparador en el objeto APEX_Customer__c siguiendo estos pasos:
Step 1 - Ir a sObject
Step 2 - Haga clic en Cliente
Step 3 - Haga clic en el botón 'Nuevo' en la lista relacionada de Activador y agregue el código de activación como se indica a continuación.
// Trigger Code
trigger Customer_After_Insert on APEX_Customer__c (after update) {
List InvoiceList = new List();
for (APEX_Customer__c objCustomer: Trigger.new) {
if (objCustomer.APEX_Customer_Status__c == 'Active') {
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
// DML to insert the Invoice List in SFDC
insert InvoiceList;
}
Explicación
Trigger.new- Esta es la variable de contexto que almacena los registros que se encuentran actualmente en el contexto de activación, ya sea que se estén insertando o actualizando. En este caso, esta variable tiene los registros del objeto Cliente que se han actualizado.
Hay otras variables de contexto que están disponibles en el contexto: trigger.old, trigger.newMap, trigger.OldMap.
Ejemplo de activador 2
El activador anterior se ejecutará cuando haya una operación de actualización en los registros del Cliente. Supongamos que el registro de la factura debe insertarse solo cuando el Estado del cliente cambia de Inactivo a Activo y no siempre; para esto, podemos usar otra variable de contextotrigger.oldMap que almacenará la clave como ID de registro y el valor como valores de registro antiguos.
// Modified Trigger Code
trigger Customer_After_Insert on APEX_Customer__c (after update) {
List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
for (APEX_Customer__c objCustomer: Trigger.new) {
// condition to check the old value and new value
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
// DML to insert the Invoice List in SFDC
insert InvoiceList;
}
Explicación
Hemos utilizado la variable Trigger.oldMap que, como se explicó anteriormente, es una variable de contexto que almacena el Id y el valor antiguo de los registros que se están actualizando.
Los patrones de diseño se utilizan para hacer que nuestro código sea más eficiente y evitar alcanzar los límites del regulador. A menudo, los desarrolladores pueden escribir código ineficiente que puede provocar la creación de instancias repetidas de objetos. Esto puede resultar en un código ineficiente, de bajo rendimiento y potencialmente en el incumplimiento de los límites del regulador. Esto ocurre con mayor frecuencia en los desencadenantes, ya que pueden operar contra un conjunto de registros.
Veremos algunas estrategias de patrones de diseño importantes en este capítulo.
Patrones de diseño de disparadores a granel
En un caso comercial real, es posible que necesite procesar miles de registros de una sola vez. Si su disparador no está diseñado para manejar tales situaciones, entonces puede fallar al procesar los registros. Existen algunas prácticas recomendadas que debe seguir al implementar los activadores. Todos los disparadores son disparadores masivos de forma predeterminada y pueden procesar varios registros a la vez. Siempre debe planificar procesar más de un registro a la vez.
Considere un caso comercial, en el que necesita procesar una gran cantidad de registros y ha escrito el activador como se indica a continuación. Este es el mismo ejemplo que habíamos tomado para insertar el registro de factura cuando el estado del cliente cambia de inactivo a activo.
// Bad Trigger Example
trigger Customer_After_Insert on APEX_Customer__c (after update) {
for (APEX_Customer__c objCustomer: Trigger.new) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
insert objInvoice; //DML to insert the Invoice List in SFDC
}
}
}
Ahora puede ver que la Declaración DML se ha escrito para el bloque de bucle que funcionará al procesar solo unos pocos registros, pero cuando esté procesando algunos cientos de registros, alcanzará el límite de Declaración DML por transacción, que es el governor limit. Veremos en detalle los límites del gobernador en un capítulo posterior.
Para evitar esto, tenemos que hacer que el disparador sea eficiente para procesar varios registros a la vez.
El siguiente ejemplo le ayudará a entender lo mismo:
// Modified Trigger Code-Bulk Trigger
trigger Customer_After_Insert on APEX_Customer__c (after update) {
List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
for (APEX_Customer__c objCustomer: Trigger.new) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
//condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);//Adding records to List
}
}
insert InvoiceList;
// DML to insert the Invoice List in SFDC, this list contains the all records
// which need to be modified and will fire only one DML
}
Este disparador solo disparará 1 declaración DML ya que estará operando sobre una Lista y la Lista tiene todos los registros que necesitan ser modificados.
De esta manera, puede evitar los límites del regulador de la declaración DML.
Activador de clase auxiliar
Escribir todo el código en el disparador tampoco es una buena práctica. Por lo tanto, debe llamar a la clase Apex y delegar el procesamiento de Trigger a la clase Apex como se muestra a continuación. La clase Trigger Helper es la clase que realiza todo el procesamiento del disparador.
Consideremos nuevamente nuestro ejemplo de creación de registros de facturas.
// Below is the Trigger without Helper class
trigger Customer_After_Insert on APEX_Customer__c (after update) {
List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
for (APEX_Customer__c objCustomer: Trigger.new) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
insert InvoiceList; // DML to insert the Invoice List in SFDC
}
// Below is the trigger with helper class
// Trigger with Helper Class
trigger Customer_After_Insert on APEX_Customer__c (after update) {
CustomerTriggerHelper.createInvoiceRecords(Trigger.new, trigger.oldMap);
// Trigger calls the helper class and does not have any code in Trigger
}
Clase de ayudante
public class CustomerTriggerHelper {
public static void createInvoiceRecords (List<apex_customer__c>
customerList, Map<id, apex_customer__c> oldMapCustomer) {
List<apex_invoice__c> InvoiceList = new Listvapex_invoice__c>();
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
oldMapCustomer.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
// objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
insert InvoiceList; // DML to insert the Invoice List in SFDC
}
}
En esto, todo el procesamiento se ha delegado a la clase de ayuda y cuando necesitamos una nueva funcionalidad simplemente podemos agregar el código a la clase de ayuda sin modificar el disparador.
Disparador único en cada sObject
Cree siempre un único disparador en cada objeto. Varios disparadores en el mismo objeto pueden causar conflictos y errores si alcanza los límites del regulador.
Puede usar la variable de contexto para llamar a los diferentes métodos de la clase auxiliar según el requisito. Considere nuestro ejemplo anterior. Supongamos que se debe llamar a nuestro método createInvoice solo cuando el registro se actualiza y en varios eventos. Entonces podemos controlar la ejecución como se muestra a continuación:
// Trigger with Context variable for controlling the calling flow
trigger Customer_After_Insert on APEX_Customer__c (after update, after insert) {
if (trigger.isAfter && trigger.isUpdate) {
// This condition will check for trigger events using isAfter and isUpdate
// context variable
CustomerTriggerHelper.createInvoiceRecords(Trigger.new);
// Trigger calls the helper class and does not have any code in Trigger
// and this will be called only when trigger ids after update
}
}
// Helper Class
public class CustomerTriggerHelper {
//Method To Create Invoice Records
public static void createInvoiceRecords (List<apex_customer__c> customerList) {
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
insert InvoiceList; // DML to insert the Invoice List in SFDC
}
}
Los límites de ejecución del gobernador garantizan el uso eficiente de los recursos en la plataforma multiusuario de Force.com. Es el límite especificado por Salesforce.com sobre la ejecución del código para un procesamiento eficiente.
¿Qué son los límites del gobernador?
Como sabemos, Apex se ejecuta en un entorno multiinquilino, es decir, todos los clientes y organizaciones comparten un único recurso. Por lo tanto, es necesario asegurarse de que nadie monopolice los recursos y, por lo tanto, Salesforce.com ha creado el conjunto de límites que rige y limita la ejecución del código. Siempre que se cruce alguno de los límites del gobernador, arrojará un error y detendrá la ejecución del programa.
Desde la perspectiva de un desarrollador, es importante asegurarse de que nuestro código sea escalable y no supere los límites.
Todos estos límites se aplican por transacción. La ejecución de un solo disparador es una transacción.
Como hemos visto, el patrón de diseño del disparador ayuda a evitar el error de límite. Ahora veremos otros límites importantes.
Evitar el límite de consultas SOQL
Puede emitir solo 100 consultas por transacción, es decir, cuando su código emita más de 100 consultas SOQL, arrojará un error.
Ejemplo
Este ejemplo muestra cómo se puede alcanzar el límite de consultas SOQL:
El siguiente desencadenador itera sobre una lista de clientes y actualiza la descripción del registro secundario (Factura) con la cadena 'Aceptar para pagar'.
// Helper class:Below code needs o be checked.
public class CustomerTriggerHelper {
public static void isAfterUpdateCall(Trigger.new) {
createInvoiceRecords(trigger.new);//Method call
updateCustomerDescription(trigger.new);
}
// Method To Create Invoice Records
public static void createInvoiceRecords (List<apex_customer__c> customerList) {
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
insert InvoiceList; // DML to insert the Invoice List in SFDC
}
// Method to update the invoice records
public static updateCustomerDescription (List<apex_customer__c> customerList) {
for (APEX_Customer__c objCust: customerList) {
List<apex_customer__c> invList = [SELECT Id, Name,
APEX_Description__c FROM APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id];
// This query will fire for the number of records customer list has and will
// hit the governor limit when records are more than 100
for (APEX_Invoice__c objInv: invList) {
objInv.APEX_Description__c = 'OK To Pay';
update objInv;
// Update invoice, this will also hit the governor limit for DML if large
// number(150) of records are there
}
}
}
}
Cuando se llama al método 'updateCustomerDescription' y el número de registros de clientes es superior a 100, alcanzará el límite de SOQL. Para evitar esto, nunca escriba la consulta SOQL en For Loop. En este caso, la consulta SOQL se ha escrito en el bucle For.
A continuación se muestra un ejemplo que mostrará cómo evitar el DML y el límite SOQL. Hemos utilizado la consulta de relación anidada para recuperar los registros de facturas y hemos utilizado la variable de contextotrigger.newMap para obtener el mapa de id y registros de clientes.
// SOQL-Good Way to Write Query and avoid limit exception
// Helper Class
public class CustomerTriggerHelper {
public static void isAfterUpdateCall(Trigger.new) {
createInvoiceRecords(trigger.new); //Method call
updateCustomerDescription(trigger.new, trigger.newMap);
}
// Method To Create Invoice Records
public static void createInvoiceRecords (List<apex_customer__c> customerList) {
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
trigger.oldMap.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
InvoiceList.add(objInvoice);
}
}
insert InvoiceList; // DML to insert the Invoice List in SFDC
}
// Method to update the invoice records
public static updateCustomerDescription (List<apex_customer__c>
customerList, Map<id, apex_customer__c> newMapVariable) {
List<apex_customer__c> customerListWithInvoice = [SELECT id,
Name,(SELECT Id, Name, APEX_Description__c FROM APEX_Invoice__r) FROM
APEX_Customer__c WHERE Id IN :newMapVariable.keySet()];
// Query will be for only one time and fetches all the records
List<apex_invoice__c> invoiceToUpdate = new
List<apex_invoice__c>();
for (APEX_Customer__c objCust: customerList) {
for (APEX_Invoice__c objInv: invList) {
objInv.APEX_Description__c = 'OK To Pay';
invoiceToUpdate.add(objInv);
// Add the modified records to List
}
}
update invoiceToUpdate;
}
}
Llamadas masivas DML
Este ejemplo muestra el desencadenador masivo junto con el patrón de clase auxiliar de desencadenante. Primero debe guardar la clase auxiliar y luego guardar el disparador.
Note - Pegue el siguiente código en la clase 'CustomerTriggerHelper' que hemos creado anteriormente.
// Helper Class
public class CustomerTriggerHelper {
public static void isAfterUpdateCall(List<apex_customer__c> customerList,
Map<id, apex_customer__c> mapIdToCustomers, Map<id, apex_customer__c>
mapOldItToCustomers) {
createInvoiceRecords(customerList, mapOldItToCustomers); //Method call
updateCustomerDescription(customerList,mapIdToCustomers,
mapOldItToCustomers);
}
// Method To Create Invoice Records
public static void createInvoiceRecords (List<apex_customer__c>
customerList, Map<id, apex_customer__c> mapOldItToCustomers) {
List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
List<apex_customer__c> customerToInvoice = [SELECT id, Name FROM
APEX_Customer__c LIMIT 1];
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
mapOldItToCustomers.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
//condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
objInvoice.APEX_Customer__c = objCustomer.id;
InvoiceList.add(objInvoice);
}
}
system.debug('InvoiceList&&&'+InvoiceList);
insert InvoiceList;
// DML to insert the Invoice List in SFDC. This also follows the Bulk pattern
}
// Method to update the invoice records
public static void updateCustomerDescription (List<apex_customer__c>
customerList, Map<id, apex_customer__c> newMapVariable, Map<id,
apex_customer__c> oldCustomerMap) {
List<apex_customer__c> customerListWithInvoice = [SELECT id,
Name,(SELECT Id, Name, APEX_Description__c FROM Invoices__r) FROM
APEX_Customer__c WHERE Id IN :newMapVariable.keySet()];
// Query will be for only one time and fetches all the records
List<apex_invoice__c> invoiceToUpdate = new List<apex_invoice__c>();
List<apex_invoice__c> invoiceFetched = new List<apex_invoice__c>();
invoiceFetched = customerListWithInvoice[0].Invoices__r;
system.debug('invoiceFetched'+invoiceFetched);
system.debug('customerListWithInvoice****'+customerListWithInvoice);
for (APEX_Customer__c objCust: customerList) {
system.debug('objCust.Invoices__r'+objCust.Invoices__r);
if (objCust.APEX_Active__c == true &&
oldCustomerMap.get(objCust.id).APEX_Active__c == false) {
for (APEX_Invoice__c objInv: invoiceFetched) {
system.debug('I am in For Loop'+objInv);
objInv.APEX_Description__c = 'OK To Pay';
invoiceToUpdate.add(objInv);
// Add the modified records to List
}
}
}
system.debug('Value of List ***'+invoiceToUpdate);
update invoiceToUpdate;
// This statement is Bulk DML which performs the DML on List and avoids
// the DML Governor limit
}
}
// Trigger Code for this class: Paste this code in 'Customer_After_Insert'
// trigger on Customer Object
trigger Customer_After_Insert on APEX_Customer__c (after update) {
CustomerTriggerHelper.isAfterUpdateCall(Trigger.new, trigger.newMap,
trigger.oldMap);
// Trigger calls the helper class and does not have any code in Trigger
}
Otros límites del gobernador de Salesforce
La siguiente tabla enumera los límites importantes del regulador.
Descripción | Límite |
---|---|
Tamaño total del montón | 6 MB / 12 MB |
Número total de extractos de DML emitidos | 150 |
Número total de registros recuperados por una sola consulta SOSL | 2000 |
Número total de consultas SOSL emitidas | 20 |
Número total de registros recuperados por Database.getQueryLocator | 10000 |
Número total de registros recuperados por consultas SOQL | 50000 |
En este capítulo, comprenderemos el procesamiento por lotes en Apex. Considere un escenario en el que procesaremos una gran cantidad de registros a diario, probablemente la limpieza de datos o tal vez eliminando algunos datos no utilizados.
¿Qué es Batch Apex?
Batch Apex es una ejecución asincrónica de código Apex, especialmente diseñado para procesar una gran cantidad de registros y tiene mayor flexibilidad en los límites del regulador que el código síncrono.
¿Cuándo usar Batch Apex?
Cuando desee procesar una gran cantidad de registros a diario o incluso en un intervalo de tiempo específico, puede optar por Batch Apex.
Además, cuando desee que una operación sea asincrónica, puede implementar Batch Apex. Batch Apex se expone como una interfaz que debe implementar el desarrollador. Los trabajos por lotes se pueden invocar mediante programación en tiempo de ejecución mediante Apex. Batch Apex opera sobre pequeños lotes de registros, cubriendo todo su conjunto de registros y dividiendo el procesamiento en fragmentos de datos manejables.
Uso de Batch Apex
Cuando usamos Batch Apex, debemos implementar la interfaz Database.Batchable proporcionada por Salesforce y luego invocar la clase mediante programación.
Puede monitorear la clase siguiendo estos pasos:
Para monitorear o detener la ejecución del trabajo por lotes Apex Batch, vaya a Configuración → Monitoreo → Trabajos Apex o Trabajos → Trabajos Apex.
Database.Batchable interfaz tiene los siguientes tres métodos que deben implementarse:
- Start
- Execute
- Finish
Entendamos ahora cada método en detalle.
comienzo
El método Start es uno de los tres métodos de la interfaz Database.Batchable.
Syntax
global void execute(Database.BatchableContext BC, list<sobject<) {}
Este método se llamará al inicio del trabajo por lotes y recopila los datos en los que funcionará el trabajo por lotes.
Considere los siguientes puntos para comprender el método:
Utilizar el Database.QueryLocatorobjeto cuando está utilizando una consulta simple para generar el alcance de los objetos utilizados en el trabajo por lotes. En este caso, se omitirá el límite de filas de datos SOQL.
Utilice el objeto iterable cuando tenga criterios complejos para procesar los registros. Database.QueryLocator determina el alcance de los registros que deben procesarse.
Ejecutar
Entendamos ahora el método Execute de la interfaz Database.Batchable.
Syntax
global void execute(Database.BatchableContext BC, list<sobject<) {}
donde, list <sObject <es devuelto por el método Database.QueryLocator.
Este método se llama después del método Start y realiza todo el procesamiento necesario para el trabajo por lotes.
Terminar
Ahora discutiremos el método Finish de la interfaz Database.Batchable.
Syntax
global void finish(Database.BatchableContext BC) {}
Este método se llama al final y puede realizar algunas actividades de acabado, como enviar un correo electrónico con información sobre los registros de trabajo por lotes procesados y el estado.
Ejemplo de lote de Apex
Consideremos un ejemplo de nuestra Compañía Química existente y supongamos que tenemos el requisito de actualizar el campo Estado del cliente y Descripción del cliente de los Registros del cliente que se han marcado como Activos y que se han creado como Fecha como hoy. Esto debe hacerse a diario y se debe enviar un correo electrónico a un usuario sobre el estado del procesamiento por lotes. Actualice el estado del cliente como 'Procesado' y la descripción del cliente como 'Actualizado mediante trabajo por lotes'.
// Batch Job for Processing the Records
global class CustomerProessingBatch implements Database.Batchable<sobject> {
global String [] email = new String[] {'[email protected]'};
// Add here your email address here
// Start Method
global Database.Querylocator start (Database.BatchableContext BC) {
return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c,
APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today
AND APEX_Active__c = true');
// Query which will be determine the scope of Records fetching the same
}
// Execute method
global void execute (Database.BatchableContext BC, List<sobject> scope) {
List<apex_customer__c> customerList = new List<apex_customer__c>();
List<apex_customer__c> updtaedCustomerList = new List<apex_customer__c>();
// List to hold updated customer
for (sObject objScope: scope) {
APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ;
// type casting from generic sOject to APEX_Customer__c
newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job';
newObjScope.APEX_Customer_Status__c = 'Processed';
updtaedCustomerList.add(newObjScope); // Add records to the List
System.debug('Value of UpdatedCustomerList '+updtaedCustomerList);
}
if (updtaedCustomerList != null && updtaedCustomerList.size()>0) {
// Check if List is empty or not
Database.update(updtaedCustomerList); System.debug('List Size '
+ updtaedCustomerList.size());
// Update the Records
}
}
// Finish Method
global void finish(Database.BatchableContext BC) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
// Below code will fetch the job Id
AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors,
a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById,
a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()];
// get the job Id
System.debug('$$$ Jobid is'+BC.getJobId());
// below code will send an email to User about the status
mail.setToAddresses(email);
mail.setReplyTo('[email protected]'); // Add here your email address
mail.setSenderDisplayName('Apex Batch Processing Module');
mail.setSubject('Batch Processing '+a.Status);
mail.setPlainTextBody('The Batch Apex job processed'
+ a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item
processed are'+a.JobItemsProcessed);
Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail});
}
}
Para ejecutar este código, primero guárdelo y luego pegue el siguiente código en Ejecutar anónimo. Esto creará el objeto de la clase y el método Database.execute ejecutará el trabajo por lotes. Una vez que se complete el trabajo, se enviará un correo electrónico a la dirección de correo electrónico especificada. Asegúrese de tener un registro de cliente que tengaActive como se marcó.
// Paste in Developer Console
CustomerProessingBatch objClass = new CustomerProessingBatch();
Database.executeBatch (objClass);
Una vez que se ejecute esta clase, verifique la dirección de correo electrónico que proporcionó donde recibirá el correo electrónico con la información. Además, puede verificar el estado del trabajo por lotes a través de la página de Monitoreo y los pasos indicados anteriormente.
Si comprueba los registros de depuración, puede encontrar el tamaño de la lista que indica cuántos registros se han procesado.
Limitations
Solo podemos procesar 5 trabajos por lotes a la vez. Esta es una de las limitaciones de Batch Apex.
Programación del trabajo por lotes de Apex mediante la página de detalles de Apex
Puede programar la clase de Apex a través de la página de detalles de Apex como se indica a continuación:
Step 1 - Vaya a Configuración ⇒ Clases Apex, haga clic en Clases Apex.
Step 2 - Haga clic en el botón Schedule Apex.
Step 3 - Proporcione detalles.
Programación del trabajo por lotes de Apex mediante la interfaz programable
Puede programar el trabajo por lotes de Apex utilizando la interfaz programable como se indica a continuación:
// Batch Job for Processing the Records
global class CustomerProessingBatch implements Database.Batchable<sobject> {
global String [] email = new String[] {'[email protected]'};
// Add here your email address here
// Start Method
global Database.Querylocator start (Database.BatchableContext BC) {
return Database.getQueryLocator('Select id, Name, APEX_Customer_Status__c,
APEX_Customer_Decscription__c From APEX_Customer__c WHERE createdDate = today
AND APEX_Active__c = true');
// Query which will be determine the scope of Records fetching the same
}
// Execute method
global void execute (Database.BatchableContext BC, List<sobject> scope) {
List<apex_customer__c> customerList = new List<apex_customer__c>();
List<apex_customer__c> updtaedCustomerList = new
List<apex_customer__c>();//List to hold updated customer
for (sObject objScope: scope) {
APEX_Customer__c newObjScope = (APEX_Customer__c)objScope ;//type
casting from generic sOject to APEX_Customer__c
newObjScope.APEX_Customer_Decscription__c = 'Updated Via Batch Job';
newObjScope.APEX_Customer_Status__c = 'Processed';
updtaedCustomerList.add(newObjScope);//Add records to the List
System.debug('Value of UpdatedCustomerList '+updtaedCustomerList);
}
if (updtaedCustomerList != null && updtaedCustomerList.size()>0) {
// Check if List is empty or not
Database.update(updtaedCustomerList); System.debug('List Size'
+ updtaedCustomerList.size());
// Update the Records
}
}
// Finish Method
global void finish(Database.BatchableContext BC) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
// Below code will fetch the job Id
AsyncApexJob a = [Select a.TotalJobItems, a.Status, a.NumberOfErrors,
a.JobType, a.JobItemsProcessed, a.ExtendedStatus, a.CreatedById,
a.CompletedDate From AsyncApexJob a WHERE id = :BC.getJobId()];//get the job Id
System.debug('$$$ Jobid is'+BC.getJobId());
// below code will send an email to User about the status
mail.setToAddresses(email);
mail.setReplyTo('[email protected]');//Add here your email address
mail.setSenderDisplayName('Apex Batch Processing Module');
mail.setSubject('Batch Processing '+a.Status);
mail.setPlainTextBody('The Batch Apex job processed'
+ a.TotalJobItems+'batches with '+a.NumberOfErrors+'failures'+'Job Item
processed are'+a.JobItemsProcessed);
Messaging.sendEmail(new Messaging.Singleemailmessage [] {mail});
}
// Scheduler Method to scedule the class
global void execute(SchedulableContext sc) {
CustomerProessingBatch conInstance = new CustomerProessingBatch();
database.executebatch(conInstance,100);
}
}
// Paste in Developer Console
CustomerProessingBatch objClass = new CustomerProcessingBatch();
Database.executeBatch (objClass);
La depuración es una parte importante en cualquier desarrollo de programación. En Apex, tenemos ciertas herramientas que se pueden usar para depurar. Uno de ellos es el método system.debug () que imprime el valor y la salida de la variable en los registros de depuración.
Podemos usar las siguientes dos herramientas para depurar:
- Consola de desarrollador
- Registros de depuración
Depuración a través de la consola de desarrollo
Puede usar la consola del desarrollador y ejecutar la funcionalidad anónima para depurar el Apex como se muestra a continuación:
Example
Considere nuestro ejemplo actual de obtención de registros de clientes que se han creado hoy. Solo queremos saber si la consulta está devolviendo los resultados o no y, en caso afirmativo, verificaremos el valor de List.
Pegue el código que se proporciona a continuación en ejecutar la ventana anónima y siga los pasos que hemos realizado para abrir la ventana de ejecución anónima.
Step 1 - Abra la consola de desarrollador
Step 2 - Abra Ejecutar anónimo desde 'Depurar' como se muestra a continuación.
Step 3 - Abra la ventana Ejecutar anónimo y pegue el siguiente código y haga clic en ejecutar.
// Debugging The Apex
List<apex_customer__c> customerList = new List<apex_customer__c>();
customerList = [SELECT Id, Name FROM APEX_Customer__c WHERE CreatedDate =
today];
// Our Query
System.debug('Records on List are '+customerList+' And Records are '+customerList);
// Debug statement to check the value of List and Size
Step 4 - Abra los registros como se muestra a continuación.
Step 5 - Introduzca 'USUARIO' en condición de filtro como se muestra a continuación.
Step 6 - Abra la declaración DEBUG DEL USUARIO como se muestra a continuación.
Depuración mediante registros de depuración
También puede depurar la misma clase a través de registros de depuración. Supongamos que tiene un disparador en el objeto Cliente y debe depurarse para algunos valores de variable, luego puede hacerlo a través de los registros de depuración como se muestra a continuación:
Este es el código de activación que actualiza el campo Descripción si el cliente modificado está activo y desea verificar los valores de las variables y registros actualmente en el alcance -
trigger CustomerTrigger on APEX_Customer__c (before update) {
List<apex_customer__c> customerList = new List<apex_customer__c>();
for (APEX_Customer__c objCust: Trigger.new) {
System.debug('objCust current value is'+objCust);
if (objCust.APEX_Active__c == true) {
objCust.APEX_Customer_Description__c = 'updated';
System.debug('The record which has satisfied the condition '+objCust);
}
}
}
Siga los pasos que se indican a continuación para generar los registros de depuración.
Step 1- Configure los registros de depuración para su usuario. Vaya a Configuración y escriba 'Debug Log' en la ventana de configuración de búsqueda y luego haga clic en Link.
Step 2 - Configure los registros de depuración de la siguiente manera.
Step 3- Ingrese el nombre del usuario que requiere configuración. Introduzca su nombre aquí.
Step 4 - Modifique los registros del cliente a medida que ocurra el evento para generar el registro de depuración.
Step 5- Ahora ve de nuevo a la sección de registros de depuración. Abra los registros de depuración y haga clic en Restablecer.
Step 6 - Haga clic en el enlace de visualización del primer registro de depuración.
Step 7 - Busque la cadena 'USUARIO' utilizando la búsqueda del navegador como se muestra a continuación.
La declaración de depuración mostrará el valor del campo en el que hemos establecido el punto.
Las pruebas son la parte integrada de Apex o cualquier otro desarrollo de aplicaciones. En Apex, tenemos clases de prueba separadas para desarrollar para todas las pruebas unitarias.
Clases de prueba
En SFDC, el código debe tener una cobertura de código del 75% para poder implementarse en Producción. Esta cobertura de código la realizan las clases de prueba. Las clases de prueba son los fragmentos de código que prueban la funcionalidad de otras clases de Apex.
Escribamos una clase de prueba para uno de nuestros códigos que hemos escrito previamente. Escribiremos la clase de prueba para cubrir nuestro código de clase Trigger y Helper. A continuación se muestra la clase de activación y ayuda que debe cubrirse.
// Trigger with Helper Class
trigger Customer_After_Insert on APEX_Customer__c (after update) {
CustomerTriggerHelper.createInvoiceRecords(Trigger.new, trigger.oldMap);
//Trigger calls the helper class and does not have any code in Trigger
}
// Helper Class:
public class CustomerTriggerHelper {
public static void createInvoiceRecords (List<apex_customer__c>
customerList, Map<id, apex_customer__c> oldMapCustomer) {
List<apex_invoice__c> InvoiceList = new List<apex_invoice__c>();
for (APEX_Customer__c objCustomer: customerList) {
if (objCustomer.APEX_Customer_Status__c == 'Active' &&
oldMapCustomer.get(objCustomer.id).APEX_Customer_Status__c == 'Inactive') {
// condition to check the old value and new value
APEX_Invoice__c objInvoice = new APEX_Invoice__c();
objInvoice.APEX_Status__c = 'Pending';
objInvoice.APEX_Customer__c = objCustomer.id;
InvoiceList.add(objInvoice);
}
}
insert InvoiceList; // DML to insert the Invoice List in SFDC
}
}
Crear clase de prueba
En esta sección, entenderemos cómo crear una clase de prueba.
Creación de datos
Necesitamos crear datos para la clase de prueba en nuestra propia clase de prueba. La clase de prueba de forma predeterminada no tiene acceso a los datos de la organización, pero si configura @isTest (seeAllData = true), entonces también tendrá acceso a los datos de la organización.
@isTest anotación
Al usar esta anotación, declaró que se trata de una clase de prueba y no se contará en el límite de código total de la organización.
testMethod palabra clave
Los métodos de prueba unitaria son los métodos que no toman argumentos, no envían datos a la base de datos, no envían correos electrónicos y se declaran con la palabra clave testMethod o la anotación isTest en la definición del método. Además, los métodos de prueba deben definirse en clases de prueba, es decir, clases anotadas con isTest.
Hemos utilizado el método de prueba 'myUnitTest' en nuestros ejemplos.
Test.startTest () y Test.stopTest ()
Estos son los métodos de prueba estándar que están disponibles para las clases de prueba. Estos métodos contienen el evento o la acción para la cual estaremos simulando nuestra prueba. Como en este ejemplo, probaremos nuestra clase de disparador y ayudante para simular el disparador de fuego actualizando los registros como lo hemos hecho para iniciar y detener el bloque. Esto también proporciona un límite de gobernador separado para el código que está en el bloque de inicio y parada.
System.assert ()
Este método verifica la salida deseada con la real. En este caso, esperamos que se inserte un registro de factura, por lo que agregamos aserción para verificar lo mismo.
Example
/**
* This class contains unit tests for validating the behavior of Apex classes
* and triggers.
*
* Unit tests are class methods that verify whether a particular piece
* of code is working properly. Unit test methods take no arguments,
* commit no data to the database, and are flagged with the testMethod
* keyword in the method definition.
*
* All test methods in an organization are executed whenever Apex code is deployed
* to a production organization to confirm correctness, ensure code
* coverage, and prevent regressions. All Apex classes are
* required to have at least 75% code coverage in order to be deployed
* to a production organization. In addition, all triggers must have some code coverage.
*
* The @isTest class annotation indicates this class only contains test
* methods. Classes defined with the @isTest annotation do not count against
* the organization size limit for all Apex scripts.
*
* See the Apex Language Reference for more information about Testing and Code Coverage.
*/
@isTest
private class CustomerTriggerTestClass {
static testMethod void myUnitTest() {
//Create Data for Customer Objet
APEX_Customer__c objCust = new APEX_Customer__c();
objCust.Name = 'Test Customer';
objCust.APEX_Customer_Status__c = 'Inactive';
insert objCust;
// Now, our trigger will fire on After update event so update the Records
Test.startTest(); // Starts the scope of test
objCust.APEX_Customer_Status__c = 'Active';
update objCust;
Test.stopTest(); // Ends the scope of test
// Now check if it is giving desired results using system.assert
// Statement.New invoice should be created
List<apex_invoice__c> invList = [SELECT Id, APEX_Customer__c FROM
APEX_Invoice__c WHERE APEX_Customer__c = :objCust.id];
system.assertEquals(1,invList.size());
// Check if one record is created in Invoivce sObject
}
}
Ejecutando la clase de prueba
Siga los pasos que se indican a continuación para ejecutar la clase de prueba:
Step 1 - Vaya a las clases de Apex ⇒ haga clic en el nombre de la clase 'CustomerTriggerTestClass'.
Step 2 - Haga clic en el botón Ejecutar prueba como se muestra.
Step 3 - Verificar estado
Step 4 - Ahora verifique la clase y el disparador para el que hemos escrito la prueba.
Clase
Desencadenar
Nuestras pruebas son exitosas y completadas.
¿Qué es la implementación en SFDC?
Hasta ahora hemos desarrollado código en Developer Edition, pero en el escenario de la vida real, debe hacer este desarrollo en Sandbox y luego es posible que deba implementarlo en otro entorno de producción o sandbox y esto se llama implementación. En resumen, este es el movimiento de metadatos de una organización a otra. La razón detrás de esto es que no puede desarrollar Apex en su organización de producción de Salesforce. Los usuarios en vivo que acceden al sistema mientras está desarrollando pueden desestabilizar sus datos o corromper su aplicación.
Herramientas disponibles para implementación -
- IDE de Force.com
- Cambiar conjuntos
- API SOAP
- Herramienta de migración Force.com
Como usamos Developer Edition para nuestro desarrollo y propósito de aprendizaje, no podemos usar Change Set u otras herramientas que necesiten SFDC Enterprise u otra edición paga. Por lo tanto, elaboraremos el método de implementación IDE de Force.com en este tutorial.
Force.com Eclipse IDE
Step 1 - Abra Eclipse y abra el disparador de clase que necesita implementarse.
Step 2 - Una vez que haga clic en 'Implementar en el servidor', ingrese el nombre de usuario y la contraseña de la organización en la que se debe implementar el componente.
Al realizar los pasos mencionados anteriormente, sus componentes de Apex se implementarán en la organización de destino.
Implementación mediante conjunto de cambios
Puede implementar reglas de validación, reglas de flujo de trabajo, clases de Apex y Trigger de una organización a otra conectándolos a través de la configuración de implementación. En este caso, las organizaciones deben estar conectadas.
Para abrir la configuración de implementación, siga los pasos que se indican a continuación. Recuerde que esta función no está disponible en Developer Edition -
Step 1 - Vaya a Configuración y busque 'Implementar'.
Step 2 - Haga clic en 'Conjunto de cambios salientes' para crear un conjunto de cambios para implementar.
Step 3 - Agregue componentes para cambiar el conjunto usando el botón 'Agregar' y luego Guardar y haga clic en Cargar.
Step 4 - Vaya a la organización de destino y haga clic en el conjunto de cambios entrantes y finalmente haga clic en implementar.
Llamadas a la API de SOAP para implementar
Solo tendremos una pequeña descripción general de este método, ya que no es un método de uso común.
Puede utilizar las llamadas al método que se indican a continuación para implementar sus metadatos.
- compileAndTest()
- compileClasses()
- compileTriggers()
Herramienta de migración Force.com
Esta herramienta se utiliza para la implementación con script. Debe descargar la herramienta de migración Force.com y luego puede realizar la implementación basada en archivos. Puede descargar la herramienta de migración Force.com y luego realizar la implementación con script.