addError en triggers
En un trigger no lanzas excepciones para rechazar un registro: marcas ese registro con addError. Solo falla él, el usuario ve tu mensaje como el de una regla de validación, y el resto del lote sigue su camino.
✓ En esta sub-lección
- 01Rechazar un registro en un trigger con addError, a nivel de registro y de campo.
- 02Explicar qué pasa con el lote al usar throw o addError, con insert o con Database.insert(list, false).
- 03Detectar duplicados dentro del mismo lote, algo que ni una regla de validación ni un flow resuelven bien.
La nutria: ¿Te acuerdas? · Repaso de la lección 4
¿Por qué el bucle de la importación captura solo RenewalImportException y no Exception?
Northwind quiere una norma: una cuenta no puede tener dos renovaciones abiertas a la vez. La primera versión del guardián la escribió alguien del equipo con un throw, y la primera noche que el ERP cargó 200 renovaciones, una sola repetida tumbó las 200. Hoy aprenderás la forma correcta de decir «no» dentro de un trigger.
addError: rechazar un registro, no la transacción
Todo registro de Trigger.new tiene un método addError('mensaje'). Llamarlo no lanza nada: tu código sigue ejecutándose con normalidad, pero ese registro queda marcado como fallido y Salesforce no lo guardará. Si lo pides sobre un campo, o.Amount.addError('…'), el mensaje aparece junto a ese campo en el formulario, igual que una regla de validación con «Error Location: Field».
for (Opportunity o : newOpps) {
if (o.Amount == null || o.Amount <= 0) {
o.Amount.addError('El importe tiene que ser mayor que 0.'); // junto al campo
} else if (accountsWithRenewal.contains(o.AccountId)) {
o.addError('Esta cuenta ya tiene una renovación abierta.'); // arriba del registro
}
}
// El bucle sigue: ningún addError para la ejecuciónLa nutria: Tu regla de validación de siempre… con vista al resto del lote
throw o addError: qué pasa con el lote
Lo que le pase al resto del lote depende de dos cosas: cómo rechaza el trigger y cómo se hizo el guardado. Una excepción sin capturar dentro de un trigger hace fallar el guardado entero, se haya pedido como se haya pedido. addError, en cambio, marca solo ese registro: con un insert normal (todo o nada, Módulo 4) el guardado lanza una DmlException y no se guarda nada; con Database.insert(list, false), fallan solo los marcados y el resto se guarda. Data Loader y la mayoría de integraciones guardan en modo parcial.
EL TRIGGER RECHAZA CON…
EL ERP GUARDA CON…
- Acme · Renovación
- Globex · Renovación
- Acme · Renovación (2ª)
- Initech · Renovación
La tercera es una segunda renovación abierta de Acme. Elige las dos cosas y guarda.
Duplicados dentro del mismo lote
La consulta solo ve lo que ya está guardado. Si el ERP manda en el mismo lote dos renovaciones para la misma cuenta, ninguna de las dos está en la base de datos todavía, así que la consulta dice «no hay ninguna abierta» para ambas. El truco: cada vez que aceptas una renovación, añades su cuenta al Set. La siguiente del mismo lote ya la encontrará.
La nutria: ¿Y por qué no un Flow… ni una regla de validación? Porque no ven el lote