Database.insert y resultados parciales
Todo o nada frente a «guarda lo que puedas y dime qué falló»: la misma decisión que tomas cada vez que cargas un CSV con Data Loader.
✓ En esta sub-lección
- 01Explicar qué hace insert cuando falla un solo registro de la lista.
- 02Usar Database.insert(lista, false) y leer cada SaveResult.
- 03Decidir cuándo conviene todo o nada y cuándo resultados parciales.
La nutria: ¿Te acuerdas? · Repaso de la lección 1
Insertas una cuenta con insert acc;. ¿Cuándo tiene Id la variable acc?
Insertas 200 leads y uno tiene un correo mal formado, que el campo Email rechaza por sí solo. ¿Qué debería pasar con los otros 199? Depende del negocio, y Apex te deja elegir. La instrucción insert de la lección anterior elige por ti; los métodos de la clase Database te dejan decidir.
La nutria: El paralelo de Admin
LA CARGA DE ESTA NOCHE
- Ruiz · Acme
- Kim · Globex
- Silva · Initech
Paso 1 de 4
Tres leads del formulario web. Kim trae el correo mal escrito. Pulsa Reproducir.
insert: todo o nada
Con la instrucción insert (y update, delete, upsert), si un solo registro de la lista falla, no se guarda ninguno y se lanza una DmlException que detiene tu código. Es lo que quieres cuando los registros solo tienen sentido juntos: un pedido y sus líneas, una cuenta y su contacto principal.
Database.insert(lista, false): lo que se pueda
List<Lead> leads = new List<Lead>{
new Lead(LastName = 'Ruiz', Company = 'Acme', Email = 'ruiz@acme.com'),
new Lead(LastName = 'Kim', Company = 'Globex', Email = 'no-es-un-email'),
new Lead(LastName = 'Silva', Company = 'Initech', Email = 'silva@initech.com')
};
List<Database.SaveResult> results = Database.insert(leads, false);
for (Integer i = 0; i < results.size(); i++) {
Database.SaveResult sr = results[i];
if (sr.isSuccess()) {
System.debug('Guardado: ' + sr.getId());
} else {
for (Database.Error err : sr.getErrors()) {
System.debug(leads[i].LastName + ' falló: ' + err.getMessage());
}
}
}- El segundo parámetro se llama allOrNone. true (o no ponerlo) se comporta como insert; false permite resultados parciales.
- Devuelve una lista de Database.SaveResult en el mismo orden que la lista de entrada. results[1] es el resultado de leads[1]: por eso el for con índice, del Módulo 2, y no el for-each.
- isSuccess() dice si se guardó; getId(), el Id nuevo; getErrors(), una lista de Database.Error con getMessage(), getStatusCode() y getFields(). Es tu error.csv, fila a fila.
- Existen igual Database.update, Database.upsert (con UpsertResult e isCreated()) y Database.delete (con DeleteResult).
¿Cuál uso?
| Situación | Elige |
|---|---|
| Una cuenta y su contacto principal: sin uno, el otro sobra | insert (todo o nada) |
| Carga nocturna de leads de un formulario web | Database.insert(lista, false) y registrar los fallos |
| Actualizar la valoración de 500 cuentas independientes | Database.update(lista, false) |
| Una factura y sus líneas | Todo o nada (y en la lección 5, savepoints) |
¿Todo o nada, o lo que se pueda?
La elección no es técnica, es de negocio, y se decide con una pregunta: ¿los registros de la lista dependen unos de otros? Si son independientes (leads de un formulario, casos de un correo), guardar los buenos y apuntar los malos es lo sensato: un lead sin empresa no tiene por qué impedir que entren los otros 199. Si forman una unidad (una cuenta con sus contactos, un pedido con sus líneas), una parte guardada sin la otra es un dato roto, y entonces quieres todo o nada. Esa segunda situación es la de la lección 5.
La nutria: El motivo del error lo escribiste tú
La nutria: ¿Y por qué no un Flow? Porque Marketing quiere la lista