Elle laisse les novices dubitatifs et fait pleurer les plus expérimentés... Il s'agit de l'exception : Too many SOQL queries !
Qu'est ce c'est ?
Tout développeur Force.com qui a quelques heures de travail derrière lui, a déjà dû être confronté à ce fléau cette erreur au moins une fois.
Elle fait référence à la limite "Total number of SOQL queries issued" fixée à 100 par Salesforce (voir Apex Governor Limits) qui empêche l'exécution d'un trop grand nombre de requêtes SOQL.
Comptent pour une requête SOQL :
- Chaque appel via l'instruction SELECT et ce peu importe sa complexité (champs enfants ou parents). Exemple :
Account myAccount = [SELECT Name FROM Account LIMIT 1];
- Chaque appel dynamique via la méthode Database.query(). Exemple :
Account myAccount = (Account) Database.query('SELECT Name FROM Account LIMIT 1');
L'enjeu est donc de limiter ces appels dans le code. C'est d'autant plus vrai pour les triggers que pour les classes APEX car les requêtes contenues dans un trigger seront appelées autant de fois que celui-ci est déclenché.
Comment résoudre le problème ?
Il n'y a pas de solution miracle. Seul un code plus propre et plus respectueux des bonnes pratiques prônées par Salesforce permettra d'éviter d'atteindre la limite.
Parmi les bonnes pratiques, on peut retenir celle-ci (qui dépannera dans 99% des cas). Cette « Best Practice » conseille de ne pas envoyer de requêtes SOQL à l'intérieur d'une boucle (for ou while) mais plutôt de « bulker » (grouper) les requêtes en une seule.
Exemple :
Nous voulons lister les noms des contacts qui sont rattachés à un compte.
List<String> contactNames = new List<String>();
for (Account a : [SELECT Id FROM Account]) {
for (Contact c : [SELECT Name FROM Contact WHERE AccountId=:a.Id]) {
contactNames.add(c.Name);
}
}
Le code ci-dessus soulèvera une exception SOQL si nous avons plus de 100 comptes dans le CRM.
Ceci peut être évité si nous utilisons plutôt le code qui suit.
Set<Id> accountIds = new Set<Id>();
for (Account a : [SELECT Id FROM Account]) {
accountIds.add(a.Id);
}
List<String> contactNames = new List<String>();
for (Contact c : [SELECT Name FROM Contact WHERE AccountId IN :accountIds]) {
contactNames.add(c.Name);
}
Si on gagne en lignes de codes, on gagne surtout en requêtes SOQL car on comptabilise maintenant 2 requêtes seulement et ce, indépendamment du nombre de comptes récupérés par la première requête.
Le code peut être encore amélioré en exploitant entièrement la puissance des requêtes SOQL, cela n'est pas le but de cet article mais fera sûrement l'objet d'un nouveau.
Aucun commentaire:
Enregistrer un commentaire