Guide du développeur de code Apex Force.com

Transcription

Guide du développeur de code Apex Force.com
salesforce: Spring ’13
Guide du développeur de code Apex Force.com
© Copyright 2000–2013 salesforce.com, inc. Tous droits réservés. Salesforce.com, le logo "no software" et Team Edition sont des marques
déposées, et AppExchange, "Success On Demand" et "The Business Web" sont des marques de commerce de salesforce.com, inc. Toutes
les autres marques mentionnées dans ce document sont la propriété de leur détenteur respectif.
salesforce | Table des matières | i
Table des matières
Chapitre 1: Introduction au langage Apex..............................................................................................1
Qu'est-ce que le langage Apex ?................................................................................................................................................2
Comment fonctionne le code Apex ?.............................................................................................................................4
Qu'est-ce que le processus de développement Apex ?....................................................................................................4
Utilisation d'une organisation Developer ou Sandbox.......................................................................................5
Apprentissage du langage Apex.........................................................................................................................7
Écriture de code Apex........................................................................................................................................9
Écriture de tests...............................................................................................................................................10
Déploiement de code Apex dans une organisation Sandbox............................................................................10
Déploiement de code Apex dans une organisation de production Salesforce..................................................11
Ajout de code Apex à une application Force.com AppExchange....................................................................11
Quand dois-je utiliser un code Apex ?.........................................................................................................................12
Quelles sont les limitations du langage Apex ?............................................................................................................12
Nouveautés..............................................................................................................................................................................13
Démarrage rapide avec le langage Apex..................................................................................................................................13
Conventions typographiques de la documentation......................................................................................................13
Compréhension des concepts de base du langage Apex...............................................................................................15
Écriture de votre première classe et de votre premier déclencheur Apex.....................................................................20
Création d'un objet personnalisé......................................................................................................................20
Ajout d'une classe Apex...................................................................................................................................21
Ajout d'un déclencheur Apex...........................................................................................................................22
Ajout d'une classe de test.................................................................................................................................24
Déploiement de composants en production.....................................................................................................26
Chapitre 2: Constructions du langage..................................................................................................28
Types de données....................................................................................................................................................................29
Type de données Primitive..........................................................................................................................................29
Types sObject..............................................................................................................................................................32
Accès aux champs sObject...............................................................................................................................34
Accès aux champs sObject via des relations.....................................................................................................36
Validation de sObjects et de champs ..............................................................................................................37
Collections...................................................................................................................................................................38
Listes................................................................................................................................................................38
Sets..................................................................................................................................................................46
Maps................................................................................................................................................................47
Type paramétré................................................................................................................................................49
Utilisation de types personnalisés dans des clés et ensembles de mappages.....................................................49
Itération de collections.....................................................................................................................................53
Enumérations..............................................................................................................................................................53
Compréhension des règles de conversion....................................................................................................................55
Variables..................................................................................................................................................................................56
salesforce | Table des matières | ii
Sensibilité à la casse.....................................................................................................................................................57
Constantes...................................................................................................................................................................58
Expressions..............................................................................................................................................................................59
Compréhension des expressions..................................................................................................................................59
Compréhension des opérateurs d'expression................................................................................................................60
Compréhension des précédences d'opérateur..............................................................................................................66
Extension d'expressions sObject et List.......................................................................................................................67
Utilisation de commentaires........................................................................................................................................67
Instructions d'attribution.........................................................................................................................................................68
Instructions conditionnelles (If-Else)......................................................................................................................................69
Boucles....................................................................................................................................................................................70
Boucles Do-While.......................................................................................................................................................71
Boucles While..............................................................................................................................................................71
Boucles For..................................................................................................................................................................72
Boucles For traditionnelles..............................................................................................................................73
Boucles For d'itération de List ou de Set.........................................................................................................73
Boucles For SOQL..........................................................................................................................................74
Requêtes SOQL et SOSL.......................................................................................................................................................77
Utilisation des résultats de requêtes SOQL et SOSL..................................................................................................78
Utilisation de fonctions Aggregate SOQL..................................................................................................................79
Utilisation de très grandes requêtes SOQL.................................................................................................................80
Utilisation de requêtes SOQL renvoyant un enregistrement.......................................................................................83
Amélioration des performances en annulant la recherche des valeurs nulles................................................................83
Compréhension des requêtes SOQL de clé étrangère et de relations parent-enfant...................................................84
Utilisation de relations polymorphiques dans des requêtes SOQL..............................................................................85
Utilisation de variables Apex dans des requêtes SOQL et SOSL................................................................................87
Demande de tous les enregistrements avec une instruction SOQL.............................................................................90
Instructions de verrouillage......................................................................................................................................................90
Verrouillage d'une boucle For SOQL..........................................................................................................................90
Éviter les impasses.......................................................................................................................................................91
Contrôle des transactions........................................................................................................................................................91
Instructions d'exception...........................................................................................................................................................92
Instructions Throw......................................................................................................................................................92
Instructions Try-Catch-Finally...................................................................................................................................93
Chapitre 3: Invocation de code Apex...................................................................................................95
Déclencheurs...........................................................................................................................................................................96
Déclencheurs en masse................................................................................................................................................97
Syntaxe de déclencheur................................................................................................................................................97
Variables de contexte de déclencheur...........................................................................................................................98
Considérations sur les variables de contexte..............................................................................................................101
Idiomes de déclencheur en masse courants................................................................................................................102
Utilisation de mappages et d'ensembles dans des déclencheurs en masse......................................................102
Corrélation d'enregistrements avec des résultats de requête dans des déclencheurs en masse........................103
Utilisation de déclencheurs pour insérer ou mettre à jour des enregistrements avec des champs uniques......103
salesforce | Table des matières | iii
Définition de déclencheurs........................................................................................................................................104
Déclencheurs et instructions Merge..........................................................................................................................106
Déclencheurs et enregistrements restaurés.................................................................................................................107
Déclencheurs et séquence d'exécution.......................................................................................................................107
Opérations n'invoquant pas de déclencheurs.............................................................................................................109
Considérations sur les entités et les champs dans les déclencheurs............................................................................110
Exceptions de déclencheur.........................................................................................................................................112
Meilleures pratiques pour les déclencheurs et les requêtes en masse..........................................................................112
Planificateur Apex.................................................................................................................................................................113
Blocs anonymes.....................................................................................................................................................................120
Apex dans AJAX...................................................................................................................................................................121
Chapitre 4: Classes, objets et interfaces..............................................................................................124
Compréhension des classes....................................................................................................................................................125
Définition de classes Apex.........................................................................................................................................125
Exemple de classe étendue.........................................................................................................................................127
Déclaration de variables de classe..............................................................................................................................132
Définition de méthodes de classe...............................................................................................................................133
Utilisation de constructeurs.......................................................................................................................................136
Modificateurs d'accès.................................................................................................................................................138
Statique et instance....................................................................................................................................................139
Utilisation de méthodes et de variables statiques...........................................................................................140
Utilisation de méthodes et de variables d'instance.........................................................................................141
Utilisation d'un code d'initialisation..............................................................................................................142
Propriétés Apex.........................................................................................................................................................144
Interfaces et extension de classes...........................................................................................................................................147
Itérateurs personnalisés..............................................................................................................................................149
Mots clés...............................................................................................................................................................................152
Utilisation du mot clé final........................................................................................................................................152
Utilisation du mot clé instanceof...............................................................................................................................152
Utilisation du mot clé super.......................................................................................................................................153
Utilisation du mot clé this.........................................................................................................................................154
Utilisation du mot clé transient.................................................................................................................................155
Utilisation des mots clés with sharing ou without sharing.........................................................................................156
Annotations...........................................................................................................................................................................159
Annotation Deprecated.............................................................................................................................................160
Annotation Future.....................................................................................................................................................161
Annotations IsTest....................................................................................................................................................162
Annotation ReadOnly...............................................................................................................................................167
Annotation RemoteAction........................................................................................................................................167
Annotations REST Apex..........................................................................................................................................168
Annotation RestResource..............................................................................................................................169
Annotation HttpDelete.................................................................................................................................169
Annotation HttpGet......................................................................................................................................169
Annotation HttpPatch...................................................................................................................................170
salesforce | Table des matières | iv
Annotation HttpPost.....................................................................................................................................170
Annotation HttpPut......................................................................................................................................170
Classes et conversion.............................................................................................................................................................170
Classes et collections..................................................................................................................................................172
Conversion de collection............................................................................................................................................172
Différences entre les classes Apex et les classes Java..............................................................................................................173
Création d'une définition de classe........................................................................................................................................174
Conventions de nommage.........................................................................................................................................176
Occultation de noms..................................................................................................................................................176
Sécurité des classes.................................................................................................................................................................177
Application des autorisations d'objet et de champ.................................................................................................................178
Préfixe d'espace de noms.......................................................................................................................................................179
Utilisation d'espace de noms lors de l'invocation de méthodes..................................................................................179
Précédence des noms d'espace de noms, de classe et de variable................................................................................180
Résolution du type et espace de noms système pour les types....................................................................................181
Paramètres de version............................................................................................................................................................181
Définition de la version de l'API Salesforce pour des classes et des déclencheurs.....................................................181
Définition de versions de package pour des classes des déclencheurs Apex...............................................................183
Chapitre 5: Test du code Apex...........................................................................................................184
Compréhension du test dans Apex........................................................................................................................................185
Pourquoi tester le code Apex ?...................................................................................................................................185
Éléments à tester dans un code Apex.........................................................................................................................185
Test unitaire Apex.................................................................................................................................................................186
Isolation des données test de celles de l'organisation dans les tests unitaires.............................................................187
Utilisation de la méthode runAs................................................................................................................................189
Utilisation de limitations, startTest, et stopTest........................................................................................................191
Ajout de requêtes SOSL à des tests unitaires............................................................................................................191
Exécution de méthodes de test unitaire.................................................................................................................................192
Meilleures pratiques de test...................................................................................................................................................194
Exemple de test.....................................................................................................................................................................195
Chapitre 6: Apex dynamique.............................................................................................................203
Compréhension de l'information Describe Apex..................................................................................................................204
Requête SOQL dynamique...................................................................................................................................................217
Requête SOSL dynamique....................................................................................................................................................218
Requêtes DML dynamiques..................................................................................................................................................219
Chapitre 7: Apex par lot....................................................................................................................223
Utilisation d'une tâche Apex par lot......................................................................................................................................224
Compréhension du partage géré Apex...................................................................................................................................237
Compréhension du partage........................................................................................................................................237
Partage d'un enregistrement en utilisant Apex..........................................................................................................240
Recalcul du partage géré Apex...................................................................................................................................247
Chapitre 8: Débogage du langage Apex..............................................................................................255
salesforce | Table des matières | v
Compréhension du journal de débogage...............................................................................................................................256
Utilisation de journaux dans la Console du développeur...........................................................................................261
Débogage des appels d'API Apex..............................................................................................................................271
Gestion des exceptions non détectées....................................................................................................................................273
Compréhension des limitations et des gouverneurs d'exécution............................................................................................273
Utilisation d'avertissements par e-mail pour les limitations du gouverneur...........................................................................279
Chapitre 9: Développement de code Apex dans des packages gérés......................................................280
Versions de package...............................................................................................................................................................281
Dépréciation du code Apex...................................................................................................................................................282
Comportement dans les versions de package.........................................................................................................................282
Gestion des versions de comportement dans un code Apex......................................................................................282
Éléments de code Apex invariables dans les différentes versions...............................................................................283
Test du comportement dans les versions de package.................................................................................................284
Chapitre 10: Exposition de méthodes Apex en tant que services Web SOAP........................................288
Méthodes WebService...........................................................................................................................................................289
Exposition des données avec des méthodes WebService...........................................................................................289
Considérations sur l'utilisation du mot clé WebService.............................................................................................289
Surcharge des méthodes WebService........................................................................................................................292
Chapitre 11: Exposition de classes Apex en tant que services Web REST.............................................293
Introduction à REST Apex...................................................................................................................................................294
Annotations REST Apex......................................................................................................................................................294
Méthodes REST Apex..........................................................................................................................................................294
Exposition de données avec des méthodes de services Web REST Apex.............................................................................301
Exemples de code REST Apex.............................................................................................................................................301
Exemple de code de base REST Apex.......................................................................................................................301
Exemple de code REST Apex utilisant RestRequest................................................................................................304
Chapitre 12: Invocation d'appels en utilisant le langage Apex..............................................................306
Ajout des paramètres de site distant......................................................................................................................................307
Services SOAP : Définition d'une classe à partir d'un document WSDL.............................................................................307
Invocation d'un service externe..................................................................................................................................308
Prise en charge d'en-tête HTTP...............................................................................................................................309
Fonctionnalités WSDL prises en charge...................................................................................................................310
Compréhension du code généré.................................................................................................................................313
Test des appels de service Web..................................................................................................................................318
Considérations sur l'utilisation de WSDL.................................................................................................................321
Mappage d'en-têtes........................................................................................................................................321
Compréhension des événements à l'exécution...............................................................................................321
Compréhension des caractères non pris en charge dans les noms de variables...............................................321
Débogage de classes générées à partir de fichiers WSDL..............................................................................321
Invocation d'appels HTTP....................................................................................................................................................322
Utilisation de certificats.........................................................................................................................................................322
Génération de certificats............................................................................................................................................322
salesforce | Table des matières | vi
Utilisation de certificats avec des services SOAP.......................................................................................................323
Utilisation de certificats avec des requêtes HTTP.....................................................................................................324
Limitations des appels...........................................................................................................................................................325
Chapitre 13: Référence.....................................................................................................................326
Opérations DML (langage de manipulation de données) Apex............................................................................................327
Opération ConvertLead............................................................................................................................................328
Opération Delete.......................................................................................................................................................332
Opération Insert........................................................................................................................................................334
Instruction Merge......................................................................................................................................................338
Opération Undelete...................................................................................................................................................339
Opération Update......................................................................................................................................................342
Opération Upsert.......................................................................................................................................................345
sObjects qui ne prennent pas en charge les opérations DML....................................................................................351
sObjects non utilisables dans des opérations DML...................................................................................................351
Gestion des exceptions DML en masse.....................................................................................................................353
Méthodes et classes standard Apex........................................................................................................................................354
Méthodes Primitives Apex........................................................................................................................................355
Méthodes Blob..............................................................................................................................................355
Méthodes Boolean.........................................................................................................................................356
Méthodes Date..............................................................................................................................................357
Méthodes Datetime.......................................................................................................................................360
Méthodes Decimal.........................................................................................................................................367
Méthodes Double..........................................................................................................................................373
Méthodes ID.................................................................................................................................................375
Méthodes Integer...........................................................................................................................................377
Méthodes Long.............................................................................................................................................378
Méthodes String............................................................................................................................................379
Méthodes Time.............................................................................................................................................409
Méthodes Collection Apex........................................................................................................................................410
Méthodes List................................................................................................................................................411
Méthodes Map..............................................................................................................................................420
Méthodes Set.................................................................................................................................................427
Méthodes Enum........................................................................................................................................................431
Méthodes sObject Apex............................................................................................................................................432
Méthodes Schéma..........................................................................................................................................432
Méthodes sObject..........................................................................................................................................437
Méthodes de résultat de description de sObject.............................................................................................442
Méthodes Describe Field Result....................................................................................................................446
Méthodes Schema.FieldSet...........................................................................................................................455
Méthodes Custom Settings...........................................................................................................................459
Méthodes Système Apex...........................................................................................................................................470
Méthodes ApexPages.....................................................................................................................................471
Méthodes Approval.......................................................................................................................................471
Méthodes Database.......................................................................................................................................472
salesforce | Table des matières | vii
Prise en charge JSON....................................................................................................................................490
Méthodes Limits...........................................................................................................................................513
Méthodes Math.............................................................................................................................................516
Méthodes MultiStaticResourceCalloutMock................................................................................................521
REST Apex...................................................................................................................................................522
Méthodes Search...........................................................................................................................................528
Méthodes StaticResourceCalloutMock.........................................................................................................528
Méthodes System...........................................................................................................................................529
Méthodes Test...............................................................................................................................................542
Méthodes TimeZone.....................................................................................................................................548
Méthodes Type..............................................................................................................................................550
Méthodes URL..............................................................................................................................................554
Méthodes UserInfo........................................................................................................................................557
Méthodes Version..........................................................................................................................................560
Utilisation de méthodes d'exception..........................................................................................................................562
Classes Apex..........................................................................................................................................................................565
Classes E-mail Apex..................................................................................................................................................566
E-mail sortant................................................................................................................................................566
E-mail entant.................................................................................................................................................579
Classe d'exception......................................................................................................................................................585
Construction d'une exception........................................................................................................................586
Utilisation de variables d'exception................................................................................................................587
Classes Visualforce.....................................................................................................................................................588
Classe Action.................................................................................................................................................588
Méthodes et propriétés de composants dynamiques......................................................................................590
Classe IdeaStandardController......................................................................................................................591
Classe IdeaStandardSetController.................................................................................................................594
Classe KnowledgeArticleVersionStandardController....................................................................................600
Classe Message..............................................................................................................................................604
Classe PageReference....................................................................................................................................605
Classe SelectOption.......................................................................................................................................611
Classe StandardController.............................................................................................................................614
Classe StandardSetController........................................................................................................................617
Classe Flow.Interview................................................................................................................................................620
Classes Pattern et Matcher........................................................................................................................................621
Utilisation de classes Pattern et Matcher.......................................................................................................621
Utilisation de classes Region..........................................................................................................................622
Utilisation d'opérations Match......................................................................................................................622
Utilisation de limites......................................................................................................................................623
Compréhension des groupes de capture.........................................................................................................623
Exemple de classe Pattern et Matcher...........................................................................................................624
Méthodes Pattern..........................................................................................................................................626
Méthodes Matcher........................................................................................................................................627
Classes de services (RESTful) HTTP.......................................................................................................................634
Classes HTTP...............................................................................................................................................634
salesforce | Table des matières | viii
Classe Crypto.................................................................................................................................................648
Classe EncodingUtil......................................................................................................................................656
Classes XML.............................................................................................................................................................657
Classes XmlStream........................................................................................................................................657
Classes DOM................................................................................................................................................667
Classes de gestion des approbations Apex.................................................................................................................674
Exemple de gestion des approbations Apex...................................................................................................675
Classe ProcessRequest...................................................................................................................................676
Classe ProcessResult......................................................................................................................................677
Classe ProcessSubmitRequest........................................................................................................................678
Classe ProcessWorkitemRequest...................................................................................................................679
Classes de support Apex............................................................................................................................................680
Classe BusinessHours....................................................................................................................................680
Classe Cases...................................................................................................................................................682
Classes de communauté Apex....................................................................................................................................683
Classe Answers..............................................................................................................................................683
Classe Ideas....................................................................................................................................................684
Classe Publishing Service pour la gestion de Knowledge..........................................................................................688
Classe Site..................................................................................................................................................................693
Classe Cookie............................................................................................................................................................700
Classe Network..........................................................................................................................................................703
Connect in Apex - Aperçu du développeur...............................................................................................................704
Interfaces Apex......................................................................................................................................................................704
Interface Auth.RegistrationHandler..........................................................................................................................705
Interface Comparable................................................................................................................................................710
Interface HttpCalloutMock.......................................................................................................................................712
Interface InstallHandler.............................................................................................................................................713
Interface Support.EmailTemplateSelector................................................................................................................716
Interface Site.UrlRewriter..........................................................................................................................................718
Utilisation de l'interface Process.Plugin.....................................................................................................................727
Interface Process.Plugin.................................................................................................................................727
Classe Process.PluginRequest........................................................................................................................729
Classe Process.PluginResult...........................................................................................................................730
Classe Process.PluginDescribeResult.............................................................................................................731
Conversions de type de donnéesProcess.Plugin.............................................................................................734
Exemple de mise en oeuvre Process.Plugin pour la conversion de piste.........................................................735
Interface UninstallHandler........................................................................................................................................746
Interface WebServiceMock.......................................................................................................................................748
Chapitre 14: Déploiement de code Apex............................................................................................750
Utilisation d'ensembles de modifications pour déployer un code Apex.................................................................................751
Utilisation de l'IDE Force.com pour déployer un code Apex................................................................................................751
Utilisation de l'Outil de migration Force.com.......................................................................................................................752
Compréhension de deploy.........................................................................................................................................753
Compréhension de retrieveCode...............................................................................................................................755
salesforce | Table des matières | ix
Compréhension de runTests()...................................................................................................................................757
Utilisation de l'API SOAP pour déployer un code Apex......................................................................................................757
Annexes...........................................................................................................................................758
Annexe A: Exemple de bordereau d'expédition..........................................................................758
Présentation d'un exemple de bordereau d'expédition...............................................................................................758
Code de l'exemple de bordereau d'expédition............................................................................................................761
Annexe B: Mots clés réservés....................................................................................................776
Annexe C: Conseils relatifs à la sécurité pour le développement de code Apex et de pages
Visualforce..........................................................................................................................778
Cross Site Scripting (XSS)........................................................................................................................................778
Sortie et formules non échappées dans des pages Visualforce....................................................................................780
Cross-Site Request Forgery (CSRF).........................................................................................................................782
Injection SOQL........................................................................................................................................................783
Contrôle de l'accès aux données.................................................................................................................................785
Annexe D: API SOAP et en-têtes SOAP pour Apex..................................................................788
compileAndTest()......................................................................................................................................................788
CompileAndTestRequest..............................................................................................................................790
CompileAndTestResult.................................................................................................................................791
compileClasses()........................................................................................................................................................793
compileTriggers()......................................................................................................................................................795
executeanonymous()..................................................................................................................................................795
ExecuteAnonymousResult.............................................................................................................................796
runTests()..................................................................................................................................................................797
RunTestsRequest...........................................................................................................................................799
RunTestsResult..............................................................................................................................................800
DebuggingHeader.....................................................................................................................................................803
PackageVersionHeader..............................................................................................................................................804
Glossaire..........................................................................................................................................806
salesforce | Table des matières | x
Chapitre 1
Introduction au langage Apex
Sujets :
•
•
•
Qu'est-ce que le langage Apex ?
Nouveautés
Démarrage rapide avec le langage
Apex
Salesforce.com a transformé la façon dont les entreprises exercent leur activité
en déplaçant les applications professionnelles, qui étaient traditionnellement
basées sur une relation client-serveur, vers un environnement Web à la demande
et mutualisé, la plate-forme Force.com. Cet environnement permet aux entreprises
d'exécuter et de personnaliser des applications, telles que Automatisation et
Service et Support Salesforce, et d'élaborer des applications personnalisées basées
sur des besoins métier spécifiques.
Bien que de nombreuses options de personnalisation soient disponibles à travers
l'interface utilisateur de Salesforce, notamment la possibilité de définir de
nouveaux champs, des objets, un workflow et des processus d'approbation, les
développeurs peuvent également utiliser l'API SOAP pour émettre des
commandes de manipulation de données, telles que delete(), update() ou
upsert(), à partir de programmes côté client.
Ces programmes côté client, généralement écrits en Java, JavaScript et .NET,
ou d'autres langages de programmation, offrent aux organisations davantage de
flexibilité dans leurs personnalisations. Cependant, comme la logique de contrôle
de ces programmes côté client ne réside dans les serveurs de la plate-forme
Force.com, ils sont restreints par les éléments suivants :
•
•
Les coûts en performance des multiples allers-retours vers le site salesforce.com
pour accomplir des transactions commerciales courantes
Le coût et la complexité de l'hébergement du code serveur, tel que Java ou
.NET, dans un environnement sécurisé et robuste
Pour apporter une réponse à ces problèmes et révolutionner la façon dont les
développeurs créent des applications à la demande, salesforce.com présente le
code Apex Force.com, le premier langage de programmation à la demande et
mutualisé destiné aux développeurs qui élaborent la prochaine génération
d'applications professionnelles.
•
•
•
Qu'est-ce que le code Apex ? Pour en savoir plus sur l'utilisation du code
Apex, le processus de développement et ses limitations
Nouveautés dans cette version Apex ?
Démarrage rapide avec Apex. Explorez directement ce code, et écrivez votre
première classe et votre premier déclencheur Apex
Introduction au langage Apex
salesforce | Qu'est-ce que le langage Apex ? | 2
Qu'est-ce que le langage Apex ?
Apex est un langage de programmation orienté objet, fortement typé, qui permet aux développeurs d'exécuter des instructions
de contrôle de flux et de transactions sur le serveur de la plate-forme Force.com, en conjonction avec des appels à l'API
Force.com. Avec une syntaxe semblable à Java et qui se comporte comme les procédures stockées dans une base de données,
le langage Apex permet aux développeurs d'ajouter une logique applicative à la plupart des événements système, y compris aux
clics de bouton, aux mises à jour d'enregistrements associés et aux pages Visualforce. Le code Apex peut être initialisé par des
demandes émanant de services Web et de déclencheurs d'objets.
Figure 1: Vous pouvez ajouter un code Apex à la plupart des événements système.
En tant que langage, Apex est :
Intégré
Apex fournit une prise en charge intégrée pour des idiomes communs de la plate-forme Force.com qui comprennent :
• Les appels DML (langage de manipulation de données), tels que INSERT, UPDATE et DELETE, qui inclut le traitement
DmlException intégré
• Des requêtes SOQL (langage de requête d'objets) Salesforce et SOSL (langage de recherche d'objets) Salesforce qui
renvoient des listes d'enregistrements sObject
• Des boucles qui permettent de traiter en masse plusieurs enregistrements même temps
• Une syntaxe de verrouillage qui empêche les conflits de mise à jour d'enregistrements
Introduction au langage Apex
•
•
salesforce | Qu'est-ce que le langage Apex ? | 3
Des appels API Force.com publics personnalisés qui peuvent être créés à partir de méthodes Apex stockées
Des avertissements et des erreurs émis lorsqu'un utilisateur tente de modifier ou de supprimer un objet personnalisé
ou un champ qui est référencé par un code Apex
Facilité d'utilisation
Le langage Apex est basé sur des idiomes Java familiers, tels qu'une syntaxe de variables et d'expressions, une syntaxe de
déclaration de bloc et conditionnelle, une syntaxe de boucle, une notation d'objet et de tableau, etc. Lorsque le langage
Apex introduit de nouveaux éléments, il utilise une syntaxe et une sémantique faciles à comprendre et favorise une
utilisation efficace de la plate-forme Force.com. Par conséquent, le langage Apex produit un code à la fois succinct et
facile à écrire.
Orienté vers les données
Le langage Apex est conçu pour relier entre elles plusieurs requêtes et déclarations DML dans une seule unité de travail
sur le serveur de la plate-forme Force.com, de la même façon que les développeurs utilisent des procédures stockées dans
une base de données pour relier entre elles plusieurs déclarations de transaction sur un serveur de base de données. Notez
que comme d'autres procédures stockées dans une base de données, le langage Apex n'essaie pas de fournir un support
général pour le rendu des éléments dans l'interface utilisateur.
Rigoureux
L'Apex est un langage fortement typé qui utilise des références directes à des objets de schéma, tels que des noms d'objet
et de champ. Il échoue rapidement lors de la compilation si des références ne sont pas valides, et stocke toutes les
dépendances de champ, d'objet et de classe personnalisés dans des métadonnées afin de les protéger contre la suppression
lorsqu'elles sont demandées par un code Apex actif.
Hébergé
Le langage Apex est entièrement interprété, exécuté et contrôlé par la plate-forme Force.com.
Mutualisé
Comme le reste de la plate-forme Force.com, le langage Apex est exécuté dans un environnement mutualisé (multitenant).
Par conséquent, le moteur d'exécution du langage Apex est conçu pour empêcher qu'un emballement de code ne
monopolise des ressources partagées. Tout code qui viole ces limites échoue avec des messages d'erreur faciles à comprendre.
Automatiquement mis à niveau
Il n'est jamais nécessaire de réécrire le code Apex lorsque d'autres parties de la plate-forme Force.com sont mises à niveau.
Le code étant compilé et stocké sous forme de métadonnées sur la plate-forme, il est toujours automatiquement mis à
niveau avec le reste du système.
Facile à tester
Le langage Apex fournit une prise en charge intégrée de la création et de l'exécution de tests unitaires, qui comprennent
des résultats de tests indiquant la quantité de code couverte et les parties de votre code qui peuvent être améliorées.
Salesforce.com garantit la fiabilité du fonctionnement du code Apex, en exécutant des tests unitaires stockés dans des
métadonnées avant toute mise à niveau de la plate-forme.
Versions multiples
Vous pouvez enregistrer votre code Apex dans plusieurs versions API Force.com. Vous pouvez ainsi préserver des
comportements.
Le langage Apex est inclus dans les versions Unlimited Edition, Developer Edition, Enterprise Edition et Database.com.
Introduction au langage Apex
salesforce | Comment fonctionne le code Apex ? | 4
Comment fonctionne le code Apex ?
Tout le code Apex est exécuté entièrement à la demande sur la plate-forme Force.com, comme indiqué dans le diagramme
d'architecture suivant :
Figure 2: Le code Apex est entièrement compilé, stocké et exécuté sur la plate-forme Force.com.
Lorsqu'un développeur écrit et enregistre un code Apex sur la plate-forme, le serveur d'applications de la plate-forme commence
par compiler le code dans un ensemble d'instructions abstraites compréhensibles par l'interpréteur d'exécution Apex, puis il
enregistre ces instructions sous forme de métadonnées.
Lorsqu'un utilisateur final déclenche l'exécution du code Apex, par exemple en cliquant sur un bouton ou en accédant à une
page Visualforce, le serveur d'applications de la plate-forme récupère les instructions compilées à partir des métadonnées, et
les envoie via l'interpréteur d'exécution, avant de renvoyer le résultat. L'utilisateur final ne remarque aucune différence en
termes de délais d'exécution par rapport aux requêtes standard de la plate-forme.
Qu'est-ce que le processus de développement Apex ?
Nous recommandons le processus suivant pour le développement de code Apex :
1.
2.
3.
4.
5.
6.
Obtenir un compte Developer Edition.
Apprendre le langage Apex.
Écrire votre code Apex.
En écrivant un code Apex, vous devez également écrire des tests.
(Facultatif) Déployer votre code Apex dans une organisation sandbox et effectuer des tests unitaires finaux.
Déployer votre code Apex dans votre organisation de production Salesforce.
En plus de du déploiement de votre code Apex, une fois écrit et testé, vous pouvez également ajouter vos classes et déclencheurs
à un package d'applications Force.com AppExchange.
Introduction au langage Apex
salesforce | Qu'est-ce que le processus de développement Apex
?|5
Utilisation d'une organisation Developer ou Sandbox
Il existe trois types d'organisation dans lesquels vous pouvez exécuter votre code Apex :
•
•
•
Une organisation de développeur : organisation créée avec un compte Developer Edition.
Une organisation de production : organisation comprenant des utilisateurs actifs qui accèdent vos données.
Une organisation sandbox : organisation créée dans votre organisation de production, mais qui est une copie de cette
organisation.
Remarque: Des déclencheurs Apex sont disponibles dans la version d'évaluation (Trial Edition) de Salesforce. Ils
sont toutefois désactivés lorsque vous passez à une autre version. Si votre nouvelle organisation inscrite inclut le langage
Apex, vous devez déployer votre code vers votre organisation en utilisant l'une des méthodes de déploiement.
Vous ne pouvez pas développer un code Apex dans votre organisation de production Salesforce. Les utilisateurs actifs qui
accèdent au système pendant que vous développez risquent de déstabiliser vos données ou de corrompre votre application. À
la place, nous recommandons de réaliser tout le travail de développement dans un environnement sandbox ou dans une
organisation Developer Edition.
Si vous n'êtes pas déjà membre d'une communauté de développeurs, accédez à http://developer.force.com/join et
suivez les instructions pour vous inscrire à un compte Developer Edition. Un compte Developer Edition vous donne accès à
une organisation Developer Edition gratuite. Même si vous avez déjà une organisation Enterprise Edition ou Unlimited
Edition et un environnement sandbox pour créer un code Apex, nous recommandons vivement de bénéficier des ressources
disponibles dans la communauté de développeurs.
Remarque: Vous ne pouvez pas modifier un code Apex en utilisant l'interface utilisateur de Salesforce dans une
organisation de production Salesforce.
Création d'une organisation Sandbox
Pour créer ou actualiser une sandbox :
1. Cliquez sur Votre nom > Configuration > Gestion des données > Sandbox.
2. Effectuez l'une des opérations suivantes :
•
•
Cliquez sur Nouvelle version test. Pour plus d'informations sur les différents types de sandbox, reportez-vous à
Présentation de sandbox.
Salesforce désactive le bouton Nouvelle version test Sandbox lorsqu'une entreprise atteint le nombre maximal
d'environnements Sandbox. Si nécessaire, contactez salesforce.com pour commander davantage d'environnements
sandbox pour votre organisation.
Notez que Salesforce désactive tous les liens d'actualisation lorsque vous atteignez votre limite en environnements
sandbox.
Cliquez sur Actualiser pour remplacer un environnement Sandbox existant par une nouvelle copie. Salesforce affiche
le lien Actualiser uniquement pour les environnements sandbox éligibles pour l'actualisation. Pour des sandbox complets,
la valeur correspond toute période après 29 jours à compter de la création ou de l'actualisation précédente des sandbox.
Pour des sandbox de type configuration-uniquement (y compris les sandbox de développeur), vous pouvez actualiser
une fois par jour. Votre copie existante de cet environnement sandbox reste disponible en attendant la fin de l'actualisation.
La copie actualisée reste inactive jusqu'à son activation.
3. Saisissez un nom et une description pour le sandbox. Vous pouvez modifier le nom uniquement lors de la création ou de
l'actualisation d'un sandbox.
Introduction au langage Apex
salesforce | Qu'est-ce que le processus de développement Apex
?|6
Conseil: Nous vous recommandons de choisir un nom qui :
•
•
Reflète l'objectif de ce sandbox, tel que « QA ».
Contient peu de caractères, car Salesforce ajoute automatiquement le nom du sandbox au nom d'utilisateur et
à l'adresse e-mail dans les enregistrements utilisateur de l'environnement sandbox. Les noms contenant peu
de caractères facilitent la saisie des informations de connexion sandbox.
4. Sélectionnez le type de sandbox :
•
•
•
Configuration uniquement : Les sandbox de type configuration-uniquement copient tous les rapports, tableaux de bord,
catalogues de prix, produits, applications et personnalisations de votre organisation de production sous Votre nom >
Configuration, mais excluent tous les enregistrements d'objet personnalisé et standard, les documents et pièces jointes
de votre organisation. La création d'un sandbox de type configuration-uniquement peut diminuer le délai de création
ou d'actualisation d'un sandbox de quelques heures à seulement quelques minutes, mais peut inclure uniquement 500 Mo
de données. Vous pouvez actualiser un sandbox de type configuration-uniquement une fois par jour.
Développeur : Les sandbox Developer sont des versions test spéciales de configuration-uniquement qui permettent à
un seul développeur de coder et de tester des programmes. Plusieurs utilisateurs peuvent se connecter à un seul sandbox
de développeur, mais leur objet principal consiste à offrir un environnement permettant d'isoler les modifications en
cours de développement tant qu'elles ne sont pas prêtes à être partagées. Semblables aux sandbox de
configuration-uniquement, les sandbox Developer copient toutes les informations d'application et de configuration
dans l'environnement sandbox. Les sandbox Developer sont limités à 10 Mo de données test ou d'essai, valeur suffisante
pour de nombreuses tâches de développement et de test. Vous pouvez actualiser un sandbox de développeur une fois
par jour.
Intégral : Les environnements sandbox complets copient l'ensemble de votre organisation de production et de ses
données, notamment les enregistrements d'objet personnalisé et standard, les documents et les pièces jointes. Vous
pouvez actualiser un environnement sandbox complet tous les 29 jours.
Si vous avez diminué le nombre de sandbox achetés et que vous possédez toujours un nombre de sandbox d'un type donné
supérieur à celui autorisé, vous devez ajuster le nombre de sandbox utilisés au nombre de sandbox achetés. Par exemple, si
vous disposez de deux environnements sandbox complets, alors que vous en avez acheté qu'un seul, vous ne pouvez pas
actualiser l'environnement sandbox en tant que sandbox complet. Vous devez choisir un sandbox complet pour le convertir
en environnement sandbox réduit, tel qu'un sandbox de configuration-uniquement ou de développeur, selon le type de
sandbox disponible.
Remarque: Les sandbox de type configuration-uniquement et développeur copient tous les rapports, tableaux de
bord, catalogues de prix, produits, applications et personnalisations de votre organisation de production sous
Votre nom > Configuration, mais excluent tous les enregistrements d'objet personnalisé et standard, les documents
et pièces jointes de votre organisation. Puisque ces types de sandbox copient un volume inférieur de données, leur
création peut fortement diminuer le délai de création ou d'actualisation d'un environnement sandbox.
Si vous actualisez un sandbox existant, la case présélectionne généralement le type de sandbox correspondant au sandbox
que vous actualisez. Par exemple, si vous actualisez un Sandbox de type configuration-uniquement, la case présélectionne
Configuration Uniquement.
Si vous actualisez un sandbox existant ou créez un sandbox, certaines cases peuvent être désactivées si vous avez déjà atteint
le nombre de sandbox de ce type autorisé pour votre organisation.
5. Pour un sandbox complet, sélectionnez la quantité d'historique d'objet, d'historique de requête et d'historique d'opportunité
à copier, et s'il est nécessaire ou non de copier les données Chatter. L'historique d'objet est le suivi de l'historique des
champs des objets personnalisés et de la plupart des objets standard. L'historique de requête et l'historique d'opportunité
jouent le même rôle pour les requêtes et les opportunités. Vous pouvez copier de 0 à 180 jours d'historique, par incréments
de 30 jours. La valeur par défaut est 0 jour. Les données Chatter comprennent des fils, des messages et des rubriques de
découverte. La diminution de la quantité de données copiée peut accélérer de façon significative le délai de copie de votre
sandbox.
Introduction au langage Apex
salesforce | Qu'est-ce que le processus de développement Apex
?|7
6. Cliquez sur Lancer la copie.
Le processus peut durer plusieurs minutes, heures ou mêmes plusieurs jours, en fonction de la taille de votre organisation
et du type de copie que vous créez, à savoir une copie complète ou une copie de type configuration-uniquement.
Conseil: Essayez de limiter les modifications de votre organisation de production pendant la copie d'une sandbox.
7. Vous recevez une notification par e-mail une fois la copie de votre sandbox créée ou actualisée. Si vous créez un sandbox,
l'environnement est maintenant prêt à l'emploi.
Si vous actualisez un sandbox existant, vous devez exécuter une étape supplémentaire pour terminer le processus de copie
de l'environnement sandbox. Le nouveau sandbox doit être activé. Pour supprimer votre sandbox existant et en activer un
nouveau :
a. Revenez à la liste de sandbox en vous connectant à votre organisation de production et en accédant à Votre nom >
Configuration > Gestion des données > Sandbox.
b. Cliquez sur le lien Activer en regard du sandbox à activer.
Vous êtes dirigé vers une page qui vous informe de la suppression de votre sandbox existant.
c. Lisez attentivement cet avertissement. Si vous acceptez la suppression, saisissez le texte demandé à l'invite, puis cliquez
sur le bouton Activer.
Une fois le processus d'activation terminé, vous recevez une notification par e-mail.
ATTENTION: L'activation d'un sandbox de remplacement créé en utilisant le lien Actualiser entraîne la
suppression complète du sandbox actualisé. Toutes les configurations et les données de la copie du sandbox
précédent sont perdues, y compris les modifications d'applications ou de données effectuées. Lisez attentivement
les avertissements, puis cliquez sur le lien Activer uniquement si vous ne souhaitez pas conserver le contenu de la
copie de l'environnement sandbox actuellement utilisé. Votre organisation de production et ses données ne sont
pas affectées.
8. Une fois votre nouveau sandbox terminé, ou votre sandbox actualisé activé, cliquez sur le lien de la notification par e-mail
pour accéder à votre environnement sandbox.
Vous pouvez vous connecter au sandbox à l'adresse test.salesforce.com/login.jsp en ajoutant .nom_sandbox
à votre nom d'utilisateur Salesforce. Par exemple, si votre nom d'utilisateur pour votre organisation de production est
[email protected], votre nom d'utilisateur pour un sandbox appelé « test » est
[email protected].
Remarque: Salesforce modifie automatiquement les noms d'utilisateur de sandbox, mais pas les mots de passe.
Les nouveaux environnements sandbox créés incluent le paramètre de livraison d'e-mail par défaut E-mail
système uniquement. Le paramètre E-mail système uniquement est particulièrement utile pour contrôler
les e-mails envoyés à partir d'environnements sandbox, afin d'empêcher les opérations de test et de développement
d'envoyer des e-mails tests à vos utilisateurs.
Apprentissage du langage Apex
Avec un compte Developer, vous disposez de nombreuses ressources pour apprendre le langage Apex :
Guides Force.com Workbook : Get Started Building Your First App in the Cloud (Premiers pas d'élaboration de
votre première application dans le Cloud)
Programmeurs débutants
Introduction au langage Apex
salesforce | Qu'est-ce que le processus de développement Apex
?|8
Une série de dix tutoriels de 30 minutes qui présentent diverses fonctionnalités de la plate-forme Force.com. Les tutoriels
Force.com Workbook présentent l'élaboration d'un système de gestion des stocks extrêmement simple. Vous apprenez
à développer entièrement une application, c.-à-d. vous commencez par élaborer un modèle de base de données pour
assurer le suivi des marchandises. Vous ajoutez ensuite une logique métier : des règles de validation qui vérifient si le
stock est suffisant, un workflow pour mettre à jour l'inventaire suite à la vente de marchandises, des approbations afin
d'envoyer des notifications par e-mail pour des montants de facture importants, enfin une logique de déclenchement
pour mettre à jour les prix dans les factures ouvertes. Une fois la base de données et la logique métier terminées, vous
créez une interface utilisateur pour présenter l'inventaire produit au personnel, un site Web public pour présenter un
catalogue de produits, puis vous commencez à réaliser une simple vitrine. Si vous souhaitez développer hors ligne, puis
intégrer à l'application, nous avons ajouté un dernier tutoriel consacré à l'utilisation d'Adobe Flash Builder pour Force.com.
Guides Force.com Workbook : HTML | PDF
Guide Apex Workbook
Programmeurs débutants
Le guide Apex Workbook présente le langage de programmation Apex dans une série de tutoriels. Vous apprenez les
concepts de base de Apex, et comment les utiliser sur la plate-forme Force.com pour ajouter une logique métier
personnalisée via des déclencheurs, des tests unitaires, un code Apex planifié, un code Apex par lot, des services Web
REST et des contrôleurs Visualforce.
Guide Apex Workbook : HTML | PDF
Page Apex Developer Force
Programmeurs débutants et avancés
La page Apex sur Developer Force inclut des liens vers diverses ressources qui comprennent des articles sur le langage
de programmation Apex. Ces ressources présentent une vue d'ensemble du langage Apex, ainsi que les meilleures pratiques
de développement Apex.
Guide Force.com Cookbook
Programmeurs débutants et avancés
Ce site collaboratif offre plusieurs recettes d'utilisation des services Web API, de développement de code Apex et de
création de pages Visualforce. Le guide Force.com Cookbook aide les développeurs à se familiariser avec les techniques et
les meilleures pratiques de programmation Force.com courantes. Vous pouvez consulter et commenter les recettes
existantes ou soumettre vos propres recettes à l'adresse developer.force.com/cookbook.
Development Life Cycle: Enterprise Development on the Force.com Platform (Cycle de vie du développement Développement d'entreprise sur la plate-forme Force.com)
Programmeurs architectes et avancés
Que vous soyez architecte, administrateur, développeur ou dirigeant, le guide Development Life Cycle Guide vous prépare
au développement et à la livraison d'applications complexes sur la plate-forme Force.com.
Cours de formation
Des cours de formation sont également disponibles dans la rubrique Formation et certification de salesforce.com. Pour
consulter la liste complète des cours, accédez au site Formation et Certification.
Dans ce manuel (Guide du développeur Apex)
Nous invitons les programmeurs débutants à consulter les rubriques suivantes :
• Introduction au langage Apex, et en particulier :
Introduction au langage Apex
salesforce | Qu'est-ce que le processus de développement Apex
?|9
◊ Conventions de documentation
◊ Concepts de base
◊ Tutoriel de démarrage rapide
•
•
•
Classes, objets et interfaces
Test du code Apex
Compréhension des limitations et des gouverneurs d'exécution
En plus des documents ci-dessus, nous invitons les programmeurs avancés à consulter les rubriques suivantes :
• Meilleures pratiques pour les déclencheurs et les requêtes en masse
• Exemple de programmation Apex avancée
• Compréhension de l'information Describe Apex
• Exécution asynchrone (Annotation @future)
• Apex par lot et Planificateur Apex
Écriture de code Apex
Vous pouvez écrire un code Apex et le tester dans les environnements d'édition suivants :
•
L'IDE Force.com, un complément de l'IDE Eclipse. L'IDE Force.com offre une interface unifiée pour l'élaboration et le
déploiement d'applications Force.com. Conçu pour les développeurs et les équipes de développement, l'IDE fournit des
outils qui permettent d'accélérer le développement d'applications Force.com, notamment des éditeurs de code source, des
outils d'exécution de tests, des assistants et une aide intégrée. Ces outils incluent un code couleur de base, une vue de la
structure hiérarchique, des tests unitaires intégrés et une compilation automatique lors de l'enregistrement avec un affichage
des messages d'erreur. Pour plus d'informations sur son installation et son utilisation, reportez-vous au site Web.
Remarque: L'IDE Force.com est une ressource gratuite offerte par salesforce.com pour aider ses utilisateurs et
ses partenaires, mais qui n'est pas considérée comme faisant partie de nos services dans le cadre du Contrat
d'abonnement principal salesforce.com.
•
L'interface utilisateur de Salesforce Toutes les classes et tous les déclencheurs sont compilés lors de leur enregistrement,
et les erreurs de syntaxe sont signalées. Vous ne pouvez pas enregistrer votre code tant qu'il contient des erreurs. L'interface
utilisateur de Salesforce numérote également les lignes de code et utilise un code couleur pour distinguer les différents
éléments, notamment les commentaires, les mots clés, les chaînes littérales etc.
◊ Pour un déclencheur dans un objet standard, cliquez sur Votre nom > Configuration > Personnaliser, cliquez sur le
nom de l'objet, puis sur Déclencheurs. Dans la page de détails Déclencheurs, cliquez sur Nouveau, puis saisissez votre
code dans la zone de texte Corps.
◊ Pour un déclencheur dans un objet personnalisé, cliquez sur Votre nom > Configuration > Développer > Objets,
puis cliquez sur le nom de l'objet. Dans la liste associée Déclencheurs, cliquez sur Nouveau, puis saisissez votre code
dans la zone de texte Corps.
◊ Pour une classe, cliquez sur Votre nom > Configuration > Développer > Classes Apex. Cliquez sur Nouveau, puis
saisissez votre code dans la zone de texte Corps.
Remarque: Vous ne pouvez pas modifier un code Apex en utilisant l'interface utilisateur de Salesforce dans une
organisation de production Salesforce.
Introduction au langage Apex
•
salesforce | Qu'est-ce que le processus de développement Apex
? | 10
N'importe quel éditeur de texte, tel que le Bloc-notes. Vous pouvez écrire votre code Apex, puis le copier et le coller dans
votre application, ou utiliser l'un des appels API pour le déployer.
Conseil: Si vous souhaitez étendre le plug-in Eclipse ou développer votre propre IDE Apex, l'API SOAP inclut des
méthodes de compilation de déclencheurs et de classes, et d'exécution de méthodes de test, tandis que l'API de
métadonnées inclut des méthodes de déploiement de code dans des environnements de production. Pour plus
d'informations, reportez-vous à Déploiement de code Apex à la page 750 et API SOAP et en-têtes SOAP pour Apex
à la page 788.
Écriture de tests
Le test est la clé de la réussite du développement à long terme et forme un composant essentiel du processus de développement.
Nous recommandons vivement d'utiliser un processus de développement piloté par des tests, c.-à-d. des tests effectués parallèlement
au développement du code.
Pour faciliter le développement d'un code robuste et sans erreur, Apex prend en charge la création et l'exécution de tests unitaires.
Les test unitaires sont des méthodes de classe qui vérifient le fonctionnement normal d'une portion de code. Les méthodes de
test unitaires ne prennent aucun argument, ne soumettent aucune donnée à la base de données, n'envoient aucun e-mail et
sont marquées avec le mot clé testMethod dans la définition de la méthode.
De plus, avant de pouvoir déployer votre code Apex ou de l'empaqueter pour Force.com AppExchange, le point suivant doit
être vrai.
•
Au moins 75 % de votre code Apex doit être couvert par des tests unitaires, et tous ces tests doivent être réussis.
Notez les points suivants :
◊ Lors du déploiement d'une organisation de production, chaque test unitaire dans l'espace de noms de votre organisation
est exécuté.
◊ Les appels de System.debug ne sont pas pris en compte dans la couverture du code Apex.
◊ Les méthodes de test et les classes de test ne sont pas prises en compte dans la couverture du code Apex.
◊ Alors que seulement 75 % de votre code Apex doit être couvert par des tests, votre attention ne doit pas se porter sur
le pourcentage du code couvert. Assurez-vous plutôt que chaque cas d'utilisation de votre application est couvert, y
compris les cas positifs et négatifs, ainsi que les enregistrements en masse et uniques. Ils doivent représenter 75 % ou
plus de couverture de votre code par des tests unitaires.
•
•
Chaque déclencheur doit avoir une couverture de test.
Toutes les classes et tous les déclencheurs doivent être compilés avec succès.
Pour plus d'informations sur l'écriture de tests, reportez-vous à Tests Apex à la page 184.
Déploiement de code Apex dans une organisation Sandbox
Salesforce permet de créer plusieurs copies de votre organisation dans des environnements distincts avec le test et la formation
comme objectifs principaux, sans altérer les données et les applications de votre organisation de production Salesforce. Ces
copies, appelées sandbox, sont presque identiques à votre organisation de production Salesforce. Les sandbox sont totalement
isolées de votre organisation de production Salesforce. Par conséquent, les opérations que vous effectuez dans vos sandbox
n'affectent pas votre organisation de production Salesforce, et inversement.
Pour déployer un code Apex d'un projet local dans Force.com IDE vers une organisation Salesforce, utilisez l'Assistant de
déploiement de composants Force.com. Pour plus d'informations sur Force.com IDE, reportez-vous à
http://wiki.developerforce.com/index.php/Force.com_IDE.
Introduction au langage Apex
salesforce | Qu'est-ce que le processus de développement Apex
? | 11
Vous pouvez utiliser l'appel API de métadonnées deploy() pour déployer votre code Apex depuis une organisation de
développeur vers une organisation sandbox.
Un appel API utile est runTests(). Dans une organisation de développement ou sandbox, vous pouvez exécuter des tests
unitaires pour une classe spécifique, une liste de classes ou un espace de noms.
Salesforce inclut un Outil de migration Force.com qui permet d'émettre ces commandes dans une fenêtre de console. Vous
pouvez également mettre en oeuvre votre propre code de déploiement.
Remarque: Force.com IDE et l'Outil de migration Force.com sont des ressources fournies gratuitement par
salesforce.com pour aider ses utilisateurs et partenaires, mais qui ne sont pas considérées comme faisant partie de nos
services dans le cadre du Contrat d'abonnement principal salesforce.com.
Pour plus d'informations, reportez-vous à Utilisation de l'outil de migration Force.com et Déploiement de code Apex.
Déploiement de code Apex dans une organisation de production Salesforce
Lorsque vous avez terminé tous vos tests unitaires et vérifié que votre code Apex est exécuté correctement, l'étape finale consiste
à déployer le code Apex vers votre organisation de production Salesforce.
Pour déployer un code Apex d'un projet local dans Force.com IDE vers une organisation Salesforce, utilisez l'Assistant de
déploiement de composants Force.com. Pour plus d'informations sur Force.com IDE, reportez-vous à
http://wiki.developerforce.com/index.php/Force.com_IDE.
Vous pouvez également déployer Apex via des ensembles de modifications dans l'interface utilisateur de Salesforce.
Pour plus d'informations et des options de déploiement supplémentaires, reportez-vous à Déploiement de code Apex à la page
750.
Ajout de code Apex à une application Force.com AppExchange
Vous pouvez également inclure une classe ou un déclencheur Apex à une application que vous avez créée pour AppExchange.
Tout code Apex inclus dans un package doit avoir au moins 75 % de couverture de test cumulée. Chaque déclencheur doit
avoir une couverture de test. Lorsque vous chargez votre package sur AppExchange, tous les tests sont exécutés pour vérifier
l'absence d'erreur. De plus, des tests avec l'annotation @isTest(OnInstall=true) sont exécutés lors de l'installation du
package dans l'organisation de l'installateur. Vous pouvez spécifier les tests à exécuter durant l'installation du package en les
annotant avec @isTest(OnInstall=true). Ce sous-ensemble de tests doit être exécuté avec succès pour que l'installation
du package réussisse.
De plus, salesforce.com recommande que tout package AppExchange contenant un code Apex soit un package géré.
Pour plus d'informations, reportez-vous au document Force.com Quick Reference for Developing Packages. Pour plus d'informations
sur le code Apex dans des packages gérés, reportez-vous à Développement de code Apex dans des packages gérés à la page
280.
Remarque: Empaquetage de classes Apex contenant des références à des étiquettes personnalisées qui ont des
traductions : Pour inclure les traductions dans le package, activez le Système de traduction, puis empaquetez
explicitement les langues individuelles à utiliser dans les étiquettes personnalisées traduites. Reportez-vous à Présentation
des étiquettes personnalisées.
Introduction au langage Apex
salesforce | Quand dois-je utiliser un code Apex ? | 12
Quand dois-je utiliser un code Apex ?
Les applications Salesforce pré-construites offrent des fonctionnalités CRM puissantes. Salesforce offre en outre la possibilité
de personnaliser les applications pré-construites en fonction de votre organisation. Cependant, votre organisation peut avoir
des processus métier complexes non pris en charge par les fonctionnalités existantes. Dans ce cas, la plate-forme Force.com
comprend plusieurs méthodes qui permettent aux administrateurs et aux développeurs de mettre en oeuvre des fonctionnalités
personnalisées. Elles comprennent Apex, Visualforce et l'API SOAP.
Apex
Utilisez Apex si vous souhaitez :
•
•
•
•
•
•
Créer des services Web.
Créer des services de messagerie.
Effectuer une validation complexe sur des objets multiples.
Créer des processus métier complexes qui ne sont pas pris en charge par le workflow.
Créer une logique transactionnelle personnalisée (qui se produit sur la transaction complète, pas seulement sur un
enregistrement ou un objet unique).
Joindre une logique personnalisée à une autre opération, par exemple la sauvegarde d'un enregistrement, qui se produit
ainsi lorsque l'opération est exécutée, qu'elle soit issue ou non de l'interface utilisateur, d'une page Visualforce ou de l'API
SOAP.
Visualforce
Visualforce est formé d'un langage de balisage qui offre aux développeurs un moyen plus puissant pour concevoir des applications
et personnaliser l'interface utilisateur de Salesforce. Avec Visualforce, vous pouvez :
•
•
•
Élaborer des assistants et d'autres processus à plusieurs étapes.
Créer votre propre contrôle de flux personnalisé via une application.
Définir des modèles de navigation et des règles spécifiques aux données pour une interaction d'application optimale et
efficace.
Pour plus d'informations, reportez-vous au guide Visualforce Developer's Guide.
API SOAP
Utilisez des appels API SOAP standard si vous souhaitez ajouter à une application composite une fonctionnalité qui traite un
seul type d'enregistrement à la fois et ne nécessite aucun contrôle transactionnel (telle que la définition d'un enregistrement
ou l'annulation de modifications).
Pour plus d'informations, reportez-vous au guide SOAP API Developer's Guide.
Quelles sont les limitations du langage Apex ?
Le langage Apex change radicalement la façon dont les développeurs créent des applications professionnelles à la demande,
mais il n'a pas actuellement pour objectif de devenir un langage de programmation général. La version actuelle du langage
Apex ne peut pas être utilisée pour :
•
•
•
Rendre des éléments autres que des messages d'erreur dans l'interface utilisateur.
Modifier une fonctionnalité standard : le langage Apex peut uniquement empêcher l'exécution d'une fonctionnalité ou
ajouter une fonctionnalité supplémentaire
Créer des fichiers temporaires
Introduction au langage Apex
•
salesforce | Nouveautés | 13
Engendrer des fils
Conseil:
Tout le code Apex est exécuté sur la plate-forme Force.com, qui est une ressource partagée, utilisée par toutes les
autres organisations. Pour garantir une cohérence en termes de performances et d'évolutivité, l'exécution de code
Apex est encadrée par des limitations du gouverneur qui empêchent une exécution Apex unique d'affecter le service
global de Salesforce. Cela signifie que tout le code Apex est limité en nombre d'opérations (telles que DML ou SOQL)
qu'il peut effectuer dans un seul processus.
Toutes les requêtes Apex renvoient une collection qui contient de 1 à 50 000 enregistrements. Vous ne pouvez pas
supposer que votre code fonctionne uniquement sur un seul enregistrement à la fois. Par conséquent, vous devez
mettre en oeuvre des modèles de programmation qui tiennent compte du traitement global. Sans cette protection,
vous risquez de dépasser les limitations du gouverneur.
Voir aussi :
Compréhension des limitations et des gouverneurs d'exécution
Meilleures pratiques pour les déclencheurs et les requêtes en masse
Nouveautés
Reportez-vous aux Notes de publications de Winter ’13 pour prendre connaissance des fonctionnalités Apex nouvelles et
modifiées dans la version Winter ’13.
Démarrage rapide avec le langage Apex
Lorsque vous avez une organisation Developer Edition ou sandbox, vous pouvez apprendre quelques concepts de base du
langage Apex. Comme le langage Apex est très similaire au langage Java, vous pouvez reconnaître la plupart de ses fonctionnalités.
Une fois les concepts de base révisés, vous pouvez écrire votre premier programme Apex : une classe, un déclencheur et un test
unitaire extrêmement simples.
Vous pouvez également parcourir un exemple de bordereau d'expédition plus complexe. Cet exemples illustre de nombreuses
autres fonctionnalités du langage.
Remarque: Les exemples Hello World et du bordereau d'expédition nécessitent des champs et des objets personnalisés.
Vous pouvez créer les vôtres, ou télécharger les objets, les champs et le code Apex dans package géré sur Force.com
AppExchange. Pour plus d'informations, reportez-vous à
wiki.developerforce.com/index.php/Documentation.
Conventions typographiques de la documentation
La documentation Apex et Visualforce utilise les conventions typographiques ci-dessous.
Introduction au langage Apex
salesforce | Conventions typographiques de la
documentation | 14
Convention
Description
Police Courier
Dans les descriptions de syntaxe, les polices monospace indiquent des éléments que vous
devez saisir tels quels, sans les parenthèses. Par exemple :
Public class HelloWorld
Italique
Dans les descriptions de syntaxe, les caractères en italique représentent des variables.
Vous renseignez la valeur. Dans l'exemple suivant, trois valeurs doivent être saisies :
datatype variable_name [ = value];
Si la syntaxe est en gras et en italique, le texte représente un élément de code pour lequel
vous devez saisir une valeur, par exemple un nom de classe ou une valeur de variable :
public static class YourClassHere { ... }
Police Courier gras
Dans les exemples de code et les descriptions de syntaxe, la police Courier gras souligne
une portion du code ou de la syntaxe.
<>
Dans les descriptions de syntaxe, les symboles inférieur à et supérieur à (< >) sont saisis
tels quels.
<apex:pageBlockTable value="{!account.Contacts}" var="contact">
<apex:column value="{!contact.Name}"/>
<apex:column value="{!contact.MailingCity}"/>
<apex:column value="{!contact.Phone}"/>
</apex:pageBlockTable>
{}
Dans les descriptions de syntaxe, les accolades ({ }) sont saisies telles quelles.
<apex:page>
Hello {!$User.FirstName}!
</apex:page>
[]
Dans les descriptions de syntaxe, tout élément entre parenthèses est facultatif. Dans
l'exemple suivant, la spécification value est facultative :
data_type variable_name [ = value];
Introduction au langage Apex
salesforce | Compréhension des concepts de base du langage
Apex | 15
Convention
Description
|
Dans les descriptions de syntaxe, le caractère pipe signifie « ou », c.-à-d. que vous pouvez
effectuer l'une des actions (pas toutes). Dans l'exemple suivant, vous pouvez créer un
nouvel ensemble non renseigné de deux façons différentes, ou renseigner l'ensemble :
Set<data_type> set_name
[= new Set<data_type>();] |
[= new Set<data_type{value [, value2. . .] };] |
;
Compréhension des concepts de base du langage Apex
Le code Apex contient généralement de nombreux éléments courants dans d'autres langages de programmation :
Figure 3: Éléments de programmation dans le langage Apex
La section présente les principales fonctionnalités du langage Apex, ainsi que quelques concepts de base.
Utilisation des paramètres de version
Dans l'interface utilisateur de Salesforce, vous pouvez spécifier une version de l'API Salesforce.com pour laquelle vous enregistrez
votre classe ou déclencheur Apex. Ce paramètre indique la version de l'API SOAP à utiliser, mais également la version Apex.
Vous pouvez changer la version après l'enregistrement. Chaque nom de classe ou de déclencheur doit être unique. Vous ne
pouvez pas enregistrer la même classe ou le même déclencheur pour différentes versions.
Vous pouvez également utiliser des paramètres de version afin d'associer une classe ou un déclencheur à une version particulière
d'un package géré installé dans votre organisation à partir d'AppExchange. La classe ou le déclencheur continue d'utiliser cette
Introduction au langage Apex
salesforce | Compréhension des concepts de base du langage
Apex | 16
version du package géré si des versions ultérieures du package sont installées, sauf si vous mettez à jour manuellement le
paramètre de version. Pour ajouter un package géré installé à la liste des paramètres, sélectionnez un package dans la liste des
packages disponibles. Cette liste s'affiche uniquement si un package géré installé n'est pas déjà associé à la classe ou au
déclencheur.
Pour plus d'informations sur l'utilisation de paramètres de version avec des packages gérés, reportez-vous à « À propos des
versions de package » dans l'aide en ligne de Salesforce.
Nommage de variables, de méthodes et de classes
Vous ne pouvez utiliser aucun mot clé Apex réservé pour nommer des variables, des méthodes ou des classes. Sont inclus les
termes faisant partie du code Apex et de la plate-forme Force.com, tels que list, test ou account, ainsi que les mots clés
réservés.
Utilisation de variables et d'expressions
Apex est un langage fortement typé, c.-à-d. que vous devez déclarer le type de données d'une variable en la référençant pour la
première fois. Le types de données Apex incluent des types de base, tels que Nombre entier, Date et Booléen, ainsi que les
types plus avancés, tels que lists, maps, objects et sObjects.
Les variables sont déclarées avec un nom et un type de données. Vous pouvez attribuer une valeur à une variable lorsque vous
la déclarez. Vous pouvez également attribuer des valeurs ultérieurement. Lors de la déclaration de variables, utilisez la syntaxe
suivante :
datatype variable_name [ = value];
Conseil: Notez que le point-virgule final ci-dessus n'est pas facultatif. Vous devez terminer toutes les instructions
par un point-virgule.
Les exemples ci-dessous sont des instructions de variables :
// The following variable has the data type of Integer with the name Count,
// and has the value of 0.
Integer Count = 0;
// The following variable has the data type of Decimal with the name Total. Note
// that no value has been assigned to it.
Decimal Total;
// The following variable is an account, which is also referred to as an sObject.
Account MyAcct = new Account();
Introduction au langage Apex
salesforce | Compréhension des concepts de base du langage
Apex | 17
Dans le langage Apex, tous les arguments de type de données primitifs, tels que Nombre entier ou Chaîne, sont transmis en
méthodes par valeur. Cela signifie que toute modification apportée aux arguments existe uniquement dans la portée de la
méthode. Lorsque la méthode retourne, les modifications de l'argument sont perdues.
Les arguments de type de données non primitifs, tels que sObjects, sont également transmis en méthodes par valeur. Cela
signifie que lorsque la méthode retourne, l'argument passé référence toujours le même objet qu'avant l'appel de la méthode et
ne peut pas être modifié pour pointer vers un autre objet. Cependant, les valeurs des champs de l'objet peuvent être modifiées
dans la méthode.
Utilisation d'instructions
Une instruction correspond à toute instruction codée pour exécuter une action.
Dans le langage Apex, les instructions doivent se terminer par un point-virgule et peuvent correspondre à l'un des types suivants
:
Attribution, par exemple attribution d'une valeur à une variable
Conditionnel (if-else)
Boucles :
•
•
•
◊ Do-while
◊ While
◊ For
Verrouillage
Langage de manipulation des données (DML)
Contrôle des transactions
Invocation de méthode
Gestion des exceptions
•
•
•
•
•
Un block est une série d'instructions regroupées par des accolades, qui peut être utilisé partout où une instruction unique est
autorisée. Par exemple :
if (true) {
System.debug(1);
System.debug(2);
} else {
System.debug(3);
System.debug(4);
}
Lorsqu'un bloc contient une seule instruction, les accolades peuvent être abandonnées. Par exemple :
if (true)
System.debug(1);
else
System.debug(2);
Introduction au langage Apex
salesforce | Compréhension des concepts de base du langage
Apex | 18
Utilisation de collections
Le langage Apex inclut les types de collection suivants :
•
•
•
Lists (tableaux)
Maps
Sets
Une list (liste) est une collection d'éléments, telle que des Nombres entiers, des Chaînes, des objets ou d'autres collections.
Utilisez une liste lorsque la séquence d'élément est importante. Une liste peut inclure des éléments dupliqués.
La première position d'index dans une liste est toujours 0.
Pour créer une liste :
•
•
Utilisez le mot clé new
Utilisez le mot clé List suivi du type d'élément entre crochets <>.
Utilisez la syntaxe suivante pour créer une liste :
List <datatype> list_name
[= new List<datatype>();] |
[=new List<datatype>{value [, value2. . .]};] |
;
L'exemple suivant crée une liste de Nombres entiers et l'attribue à la variable My_List. Notez que comme le langage Apex
est fortement typé, vous devez déclarer le type de données My_List en tant que liste de Nombres entiers.
List<Integer> My_List = new List<Integer>();
Pour plus informations, reportez-vous à Lists à la page 38.
Un set (ensemble) est une collection d'éléments uniques non organisés. Il contient des types de données primitifs, tels que
Chaîne, Nombre entier, Date, etc. Il inclut également des types de données plus complexes tels que des sObjects.
Pour créer un ensemble :
•
•
Utilisez le mot clé new
Utilisez le mot clé Set suivi du type de données primitif entre crochets <>.
Utilisez la syntaxe suivante pour créer un ensemble :
Set<datatype> set_name
[= new Set<datatype>();] |
[= new Set<datatype>{value [, value2. . .] };] |
;
L'exemple suivant crée un ensemble de Chaînes. Les valeurs de l'ensemble sont transmises en utilisant des accolades {}.
Set<String> My_String = new Set<String>{'a', 'b', 'c'};
Introduction au langage Apex
salesforce | Compréhension des concepts de base du langage
Apex | 19
Pour plus informations, reportez-vous à Sets à la page 46.
Un map (mappage) est une collection de paires clé-valeur. Les clés peuvent avoir n'importe quel type de données primitif. Les
valeurs peuvent inclure des types de données primitifs, ainsi que des objets et d'autres collections. Utilisez un mappage lorsque
la recherche par clé est importante. Un mappage peut inclure des valeurs dupliquées, mais chaque clé doit être unique.
Pour créer un mappage :
Utilisez le mot clé new
Utilisez le mot clé Map suivi d'une paire clé-valeur, séparée par une virgule et placée entre crochets <>.
•
•
Utilisez la syntaxe suivante pour créer un mappage :
Map<key_datatype, value_datatype> map_name
[=new map<key_datatype, value_datatype>();] |
[=new map<key_datatype, value_datatype>
{key1_value => value1_value
[, key2_value => value2_value. . .]};] |
;
L'exemple suivant crée un mappage qui a un type de données Integer pour clé et String pour valeur. Dans cet exemple, les
valeurs du mappage sont transmises entre accolades {} lors de la création du mappage.
Map<Integer, String> My_Map = new Map<Integer, String>{1 => 'a', 2 => 'b', 3 => 'c'};
Pour plus informations, reportez-vous à Maps à la page 47.
Utilisation de branchements
Une instruction if est un test vrai-faux qui permet à votre application d'exécuter plusieurs opérations en fonction d'une
condition. La syntaxe de base est la suivante :
if (Condition){
// Do this if the condition is true
} else {
// Do this if the condition is not true
}
Pour plus d'informations, reportez-vous à Instructions conditionnelles (If-Else) à la page 69.
Utilisation de boucles
Tandis que l'instruction if permet à votre organisation d'exécuter des opérations basées sur une condition, les boucles indiquent
à votre application d'exécuter la même opération en boucle en fonction d'une condition. Le langage Apex prend en charge les
types de boucle suivants :
•
•
•
Do-while
While
For
Introduction au langage Apex
salesforce | Écriture de votre première classe et de votre premier
déclencheur Apex | 20
Une boucle Do-while vérifie la condition après l'exécution du code.
Une boucle While vérifie la condition au début, avant l'exécution du code.
Une boucle For permet d'affiner le contrôle de la condition utilisée par la boucle. De plus, le langage Apex prend charge les
boucles traditionnelles For dans lesquels vous définissez les conditions, ainsi que les boucles For qui utilisent des listes et des
requêtes SOQL dans la condition.
Pour plus informations, reportez-vous à Boucles à la page 70.
Écriture de votre première classe et de votre premier déclencheur Apex
Ce tutoriel pas à pas présente la création d'une simple classe et d'un simple déclencheur Apex. Il montre également comment
déployer ces composants dans une organisation de production.
Ce tutoriel est basé sur un objet personnalisé appelé Book qui est créé à la première étape. Cet objet personnalisé est mis à
jour via un déclencheur.
Voir aussi :
Création d'un objet personnalisé
Ajout d'une classe Apex
Ajout d'un déclencheur Apex
Ajout d'une classe de test
Déploiement de composants en production
Création d'un objet personnalisé
Prérequis :
Un compte Salesforce dans une organisation sandbox Unlimited Edition ou Enterprise Edition, ou un compte dans une
organisation Developer.
Pour plus d'informations sur la création d'une organisation sandbox, reportez-vous à « Présentation de Sandbox » dans l'aide
en ligne de Salesforce. Pour vous inscrire à une organisation Developer gratuite, reportez-vous à Page d'inscription à un
environnement Developer Edition.
Dans cette étape, vous créez un objet personnalisé appelé Book avec un champ personnalisé appelé Price.
1.
2.
3.
4.
5.
Connectez-vous à votre organisation sandbox ou Developer.
Cliquez sur Votre nom > Configuration > Créer > Objets, puis cliquez sur Nouvel objet personnalisé.
Saisissez l'étiquette Book.
Saisissez l'étiquette au pluriel Books.
Cliquez sur Enregistrer.
Terminé ! Nous avons créé notre premier objet personnalisé. Créons maintenant un champ personnalisé.
6. Dans la section Champs personnalisés et relations de la page de détail Book, cliquez sur Nouveau.
7. Sélectionnez le type de données Numéro, puis cliquez sur Suivant.
8. Saisissez l'étiquette de champ Price.
9. Saisissez 16 dans la zone de texte de la longueur.
10. Saisissez 2 dans la zone de texte des décimales, puis cliquez sur Suivant.
11. Cliquez sur Suivant pour accepter les valeurs par défaut de sécurité au niveau du champ.
12. Cliquez sur Enregistrer.
Introduction au langage Apex
salesforce | Écriture de votre première classe et de votre premier
déclencheur Apex | 21
Vous venez de créer un objet personnalisé appelé Book et ajouté un champ personnalisé à cet objet. Les objets personnalisés
contiennent déjà des champs standard, tels que Nom et Créé par. Ils permettent d'ajouter d'autres champs plus spécifiques à
votre mise en oeuvre. Dans ce tutoriel, le champ Price fait partie de votre objet Book, et il est accessible via la classe Apex que
vous allez écrire à la prochaine étape.
Voir aussi :
Écriture de votre première classe et de votre premier déclencheur Apex
Ajout d'une classe Apex
Ajout d'une classe Apex
Prérequis :
•
•
Un compte Salesforce dans une organisation sandbox Unlimited Edition ou Enterprise Edition, ou un compte dans une
organisation Developer.
L'objet personnalisé Book
Dans cette étape, vous allez ajouter une classe Apex qui inclut une méthode de mise à jour du prix du livre. Cette méthode est
appelée par le déclencheur que vous allez ajouter à la prochaine étape.
1. Cliquez sur Votre nom > Configuration > Développer > Classes Apex, puis cliquez sur Nouveau.
2. Dans l'éditeur de classe, saisissez la définition de classe suivante :
public class MyHelloWorld {
}
Le code précédent correspond à la définition de classe à laquelle vous allez ajouter une méthode supplémentaire à la
prochaine étape. Le code Apex est généralement contenu dans une classe. Cette classe est définie comme public, ce qui
signifie qu'elle est disponible pour d'autres classes et déclencheurs Apex. Pour plus d'informations, reportez-vous à Classes,
objets et interfaces à la page 124.
3. Ajoutez cette définition de méthode entre les parenthèses ouvrante et fermante de la classe.
public static void applyDiscount(Book__c[] books) {
for (Book__c b :books){
b.Price__c *= 0.9;
}
}
Cette méthode est appelée applyDiscount, et elle est à la fois publique et statique. Puisque cette méthode est statique,
il n'est pas nécessaire de créer une instance de la classe pour accéder à la méthode, il suffit d'utiliser le nom de la classe
suivie d'un point (.) et du nom de la méthode. Pour plus informations, reportez-vous à Statique et instance à la page 139.
Cette méthode prend un paramètre, une liste d'enregistrements Book, qui est attribué à la variable books. Notez le __c
dans le nom de l'objet Book__c. Il indique que vous avez créé un objet personnalisé. Les objets standard fournis dans
l'application Salesforce, tels que Account, ne se terminent pas par ce suffixe.
Introduction au langage Apex
salesforce | Écriture de votre première classe et de votre premier
déclencheur Apex | 22
La section suivante du code contient le reste de la définition de la méthode :
for (Book__c b :books){
b.Price__c *= 0.9;
}
Notez le __c après le nom de champ Price__c. Il indique que vous avez créé un champ personnalisé. Les champs standard
fournis par défaut dans Salesforce sont accessibles en utilisant le même type de notation pointée, mais sans le __c, par
exemple Name ne se termine pas par __c dans Book__c.Name. L'instruction b.Price__c *= 0.9; prend l'ancienne
valeur de b.Price__c, la multiplie par 0,9, ce qui signifie qu'elle est diminuée de 10 %, puis stocke la nouvelle valeur
dans le champ b.Price__c. L'opérateur *= est un raccourci. Une autre façon d'écrire cette instruction est b.Price__c
= b.Price__c * 0.9;. Reportez-vous à Compréhension des opérateurs d'expression à la page 60.
4. Cliquez sur Enregistrer pour enregistrer la nouvelle classe. Vous devez maintenant obtenir cette définition de classe
complète.
public class MyHelloWorld {
public static void applyDiscount(Book__c[] books) {
for (Book__c b :books){
b.Price__c *= 0.9;
}
}
}
Vous avez désormais une classe contenant un code qui itère dans une liste de livres et met à jour le champ Price pour chaque
livre. Ce code fait partie de la méthode statique applyDiscount qui est appelé par le déclencheur que vous allez créer à la
prochaine étape.
Voir aussi :
Écriture de votre première classe et de votre premier déclencheur Apex
Création d'un objet personnalisé
Ajout d'un déclencheur Apex
Ajout d'un déclencheur Apex
Prérequis :
•
•
Un compte Salesforce dans une organisation sandbox Unlimited Edition ou Enterprise Edition, ou un compte dans une
organisation Developer.
La classe Apex MyHelloWorld.
Dans cette étape, vous créez un déclencheur pour l'objet personnalisé Book__c qui appelle la méthode applyDiscount de
la classe MyHelloWorld que vous avez créée à l'étape précédente.
Un déclencheur est une partie de code qui s'exécute avant ou après l'insertion, la mise à jour ou la suppression d'enregistrements
d'un type spécifique à partir de la base de données de la plate-forme Force.com. Chaque déclencheur est exécuté avec un
Introduction au langage Apex
salesforce | Écriture de votre première classe et de votre premier
déclencheur Apex | 23
ensemble de variables contextuelles qui fournissent l'accès aux enregistrements ayant activé le déclencheur. Tous les déclencheurs
sont activés en masse, c.-à-d. qu'ils traitent plusieurs enregistrements à la fois.
1. Cliquez sur Votre nom > Configuration > Créer > Objets, puis sur le nom de l'objet que vous venez de créer, Book.
2. Dans la section des déclencheurs, cliquez sur Nouveau.
3. Dans l'éditeur de déclencheurs, supprimez le code du modèle par défaut, puis saisissez la définition de déclencheur suivante
:
trigger HelloWorldTrigger on Book__c (before insert) {
Book__c[] books = Trigger.new;
MyHelloWorld.applyDiscount(books);
}
La première ligne du code définit le déclencheur :
trigger HelloWorldTrigger on Book__c (before insert) {
Elle attribue un nom au déclencheur, spécifie l'objet sur lequel il opère et définit les événements qui l'activent. Par exemple,
ce déclencheur est appelé HelloWorldTrigger, il opère sur l'objet Book__c et est exécuté avant l'insertion de nouveaux
livres dans la base de données.
La ligne suivante du déclencheur crée une liste d'enregistrements de livres nommée books et attribue le contenu d'une
variable de contexte de déclencheur appelée Trigger.new. Les variables de contexte de déclencheur, telles que
Trigger.new, sont définies implicitement dans tous les déclencheurs et fournissent l'accès aux enregistrements qui activent
le déclencheur. Dans ce cas, Trigger.new contient les nouveaux livres qui vont être insérés.
Book__c[] books = Trigger.new;
La ligne suivante du code appelle la méthode applyDiscount dans la classe MyHelloWorld. Il transmet le tableau des
nouveaux livres.
MyHelloWorld.applyDiscount(books);
Vous disposez maintenant de tout le code nécessaire pour mettre à jour le prix de tous les livres qui sont insérés. Cependant,
une pièce du puzzle est manquante. Les tests unitaires sont une partie importante de l'écriture de code et sont obligatoires.
Dans la prochaine étape, vous allez en découvrir les raisons et vous pourrez ajouter une classe de test.
Voir aussi :
Écriture de votre première classe et de votre premier déclencheur Apex
Ajout d'une classe Apex
Ajout d'une classe de test
Introduction au langage Apex
salesforce | Écriture de votre première classe et de votre premier
déclencheur Apex | 24
Ajout d'une classe de test
Prérequis :
•
•
Un compte Salesforce dans une organisation sandbox Unlimited Edition ou Enterprise Edition, ou un compte dans une
organisation Developer.
Le déclencheur Apex HelloWorldTrigger.
Dans cette étape, vous ajoutez une classe de test avec une méthode de test. Vous exécutez également le test et vérifiez la
couverture de code. La méthode de test exerce et valide le code dans le déclencheur et la classe. Il permet également d'atteindre
100 % de couverture de code pour le déclencheur et la classe.
Remarque: Le test est une partie importante du processus de développement. Avant de pouvoir déployer votre code
Apex ou de l'empaqueter pour Force.com AppExchange, les conditions suivantes doivent être remplies.
•
Au moins 75 % de votre code Apex doit être couvert par des tests unitaires, et tous ces tests doivent être réussis.
Notez les points suivants :
◊ Lors du déploiement d'une organisation de production, chaque test unitaire dans l'espace de noms de votre
organisation est exécuté.
◊ Les appels de System.debug ne sont pas pris en compte dans la couverture du code Apex.
◊ Les méthodes de test et les classes de test ne sont pas prises en compte dans la couverture du code Apex.
◊ Alors que seulement 75 % de votre code Apex doit être couvert par des tests, votre attention ne doit pas se
porter sur le pourcentage du code couvert. Assurez-vous plutôt que chaque cas d'utilisation de votre application
est couvert, y compris les cas positifs et négatifs, ainsi que les enregistrements en masse et uniques. Ils doivent
représenter 75 % ou plus de couverture de votre code par des tests unitaires.
•
•
Chaque déclencheur doit avoir une couverture de test.
Toutes les classes et tous les déclencheurs doivent être compilés avec succès.
1. Cliquez sur Votre nom > Configuration > Développer > Classes Apex, puis cliquez sur Nouveau.
2. Dans l'éditeur de classe, ajoutez cette définition de classe de test, puis cliquez sur Enregistrer.
@isTest
private class HelloWorldTestClass {
static testMethod void validateHelloWorld() {
Book__c b = new Book__c(Name='Behind the Cloud', Price__c=100);
System.debug('Price before inserting new book: ' + b.Price__c);
// Insert book
insert b;
// Retrieve the new book
b = [SELECT Price__c FROM Book__c WHERE Id =:b.Id];
System.debug('Price after trigger fired: ' + b.Price__c);
Introduction au langage Apex
salesforce | Écriture de votre première classe et de votre premier
déclencheur Apex | 25
// Test that the trigger correctly updated the price
System.assertEquals(90, b.Price__c);
}
}
Cette classe est définie en utilisant l'annotation @isTest. Les classes définies ainsi ne peuvent contenir que des méthodes
de test. L'un des avantages de la création d'une classe séparée pour le test par rapport à l'ajout de méthodes de test à une
classe existante, est que les classes définies avec isTest ne sont pas prises en compte dans la limite de votre organisation
de 3 Mo pour tout le code Apex. Vous pouvez également ajouter l'annotation @isTest à des méthodes individuelles. Pour
plus d'informations, reportez-vous à Annotation IsTest à la page 162 et Compréhension des limitations et des gouverneurs
d'exécution à la page 273.
La méthode validateHelloWorld est définie comme testMethod. Cela signifie que si des modifications sont apportées
à la base de données, elles sont automatiquement annulées une fois l'exécution terminée, ce qui vous évite de supprimer
les données de test créées dans la méthode de test.
La méthode de test commence par créer un livre, puis l'insère temporairement dans la base de données. L'instruction
System.debug écrit la valeur du livre dans le journal de débogage.
Book__c b = new Book__c(Name='Behind the Cloud', Price__c=100);
System.debug('Price before inserting new book: ' + b.Price__c);
// Insert book
insert b;
Une fois le livre inséré, le code récupère le nouveau livre inséré à l'aide de l'ID initialement attribué au livre lors de son
insertion, puis consigne le nouveau prix que le déclencheur à modifié :
// Retrieve the new book
b = [SELECT Price__c FROM Book__c WHERE Id =:b.Id];
System.debug('Price after trigger fired: ' + b.Price__c);
Lors de l'exécution de la classe MyHelloWorld, il met à jour le champ Price__c et réduit sa valeur de 10 %. La ligne
suivante correspond au test, qui vérifie si la méthode applyDiscount a été exécutée et a produit le résultat attendu :
// Test that the trigger correctly updated the price
System.assertEquals(90, b.Price__c);
3. Cliquez sur Exécuter le test dans la page de la classe pour exécuter toutes les méthodes de test de cette classe. Dans le cas
présent, nous savons une seule méthode de test.
Introduction au langage Apex
salesforce | Écriture de votre première classe et de votre premier
déclencheur Apex | 26
La page Résultat de test Apex s'affiche une fois l'exécution du test terminée. Elle contient les détails des résultats du test,
notamment le nombre d'échecs au test, les informations sur la couverture de code et un lien vers le fichier journal à
télécharger.
4. Cliquez sur Télécharger, puis sélectionnez l'ouverture du fichier journal. Vous pouvez consulter les informations consignées
sur l'événement déclencheur, l'appel de la méthode de classe applyDiscount et la sortie de débogage du prix avant et
après le déclencheur.
Vous pouvez également utiliser la Console du développeur pour le débogage du code Apex. Reportez-vous à « Console du
développeur » dans l'aide en ligne de Salesforce.
5. Vous pouvez également exécuter le test via la page Exécution de test Apex, qui exécute le test de façon asynchrone. Cela
signifie qu'il n'est pas nécessaire d'attendre la fin de l'exécution du reste du code pour obtenir les résultats, vous pouvez
effectuer d'autres tâches dans l'interface utilisateur pendant l'exécution du test, et visiter la page ultérieurement pour
consulter le statut du test.
a. Cliquez sur Votre nom > Configuration > Développer > Exécution de test Apex.
b. Cliquez sur Exécuter le test.
c. Sélectionnez la classe HelloWorldTestClass, puis cliquez sur Exécuter.
Une fois l'exécution terminée, vous pouvez :
•
•
Cliquer sur le test pour afficher les détails du résultat ; si un test échoue, le premier message d'erreur et la trace de pile
s'affichent.
Cliquez sur Afficher pour visualiser la source du code Apex.
6. Une fois l'exécution du test terminée, vérifiez la quantité de couverture de code.
a. Cliquez sur Votre nom > Configuration > Développer > Classes Apex.
b. Cliquez sur Calculer la couverture du code de votre organisation afin d'examiner la quantité de code de votre
organisation qui est couverte par des tests unitaires.
c. Dans la colonne Couverture de code, cliquez sur 100 % pour afficher les lignes de code couvertes par des tests unitaires.
Examinez la liste des déclencheurs en cliquant sur Votre nom > Configuration > Développer > Déclencheurs Apex. Le
déclencheur que vous avez écrit a également 100 % de son code couvert.
Vous avez maintenant effectué toutes les étapes requises pour obtenir un code Apex testé qui est exécuté dans votre
environnement de développement. Dans la réalité, lorsque vous avez suffisamment testé votre code et que vous êtes satisfait(e)
des résultats, vous pouvez le déployer avec d'autres composants prérequis dans une organisation de production. La prochaine
étape montre comment procéder pour le code et l'objet personnalisé que vous venez de créer.
Voir aussi :
Écriture de votre première classe et de votre premier déclencheur Apex
Ajout d'un déclencheur Apex
Déploiement de composants en production
Déploiement de composants en production
Prérequis :
•
•
Un compte Salesforce dans l'une organisation sandbox Unlimited Edition ou Enterprise Edition.
La classe de test Apex HelloWorldTestClass.
Introduction au langage Apex
•
•
salesforce | Écriture de votre première classe et de votre premier
déclencheur Apex | 27
Une connexion de déploiement entre les organisations sandbox et de production qui permet à l'organisation de production
de recevoir des ensembles de modifications entrants. Reportez-vous à « Présentation des ensembles de modifications » dans
l'aide en ligne de Salesforce.
Des autorisations utilisateur Créer et charger des ensembles d'autorisations pour créer, modifier ou charger des ensembles
d'autorisations entrants.
Dans cette étape, vous déployez le code Apex et l'objet personnalisé, que vous avez créés précédemment dans votre organisation
de production, en utilisant des ensembles de modifications.
Cette procédure ne s'applique pas aux organisations Developer, car les ensembles de modifications sont disponibles uniquement
dans les organisations Unlimited Edition, Enterprise Edition ou Database.com Edition. Si vous avez un compte Developer
Edition, vous pouvez utiliser d'autres méthodes de déploiement. Reportez-vous à Déploiement de code Apex.
1.
2.
3.
4.
Cliquez sur Votre nom > Configuration > Déployer > Ensembles de modifications sortants.
Si une page d'introduction s'affiche, cliquez sur Continuer.
Dans la liste Ensembles d'autorisations, cliquez sur Nouveau.
Saisissez un nom pour votre ensemble de modifications, par exemple HelloWorldChangeSet, puis description
(facultative). Cliquez sur Enregistrer.
5. Dans la section des composants d'ensembles de modifications, cliquez sur Ajouter.
6. Sélectionnez Classe Apex dans la liste déroulante du type de composant, sélectionnez les classes MyHelloWorld et
HelloWorldTestClass dans la liste, puis cliquez sur Ajouter à l'ensemble de modifications.
7. Cliquez sur Afficher / ajouter des dépendances pour ajouter des composants dépendants.
8. Cochez la case supérieure pour sélectionner tous les composants. Cliquez sur Ajouter à l'ensemble de modifications.
9. Dans la section de détails de la page de l'ensemble de modifications, cliquez sur Charger.
10. Sélectionnez l'organisation cible, dans le cas présent production, puis cliquez sur Charger.
11. Une fois le chargement de l'ensemble de modifications terminé, déployez-le dans votre organisation de production.
a.
b.
c.
d.
Connectez-vous à votre organisation de production.
Cliquez sur Votre nom > Configuration > Déployer > Ensembles de modifications entrants.
Si une page d'introduction s'affiche, cliquez sur Continuer.
Dans la liste des ensembles de modifications en attente de déploiement, cliquez sur le nom de votre ensemble de
modifications.
e. Cliquez sur Déployer.
Dans ce tutoriel, vous avez appris comment créer un objet personnalisé, comment ajouter un déclencheur, une classe et une
classe de test Apex, et comment tester votre code. Pour terminer, vous avez également appris comment charger le code et
l'objet personnalisé en utilisant des ensembles de modifications.
Voir aussi :
Écriture de votre première classe et de votre premier déclencheur Apex
Ajout d'une classe de test
Chapitre 2
Constructions du langage
Sujets :
•
•
•
•
•
•
•
•
•
•
Types de données
Variables
Expressions
Instructions d'attribution
Instructions conditionnelles (If-Else)
Boucles
Requêtes SOQL et SOSL
Instructions de verrouillage
Contrôle des transactions
Instructions d'exception
Le langage de programmation Apex est fortement typé, orienté objet et insensible
à la casse. Le langage Apex est formé de blocs de construction qui permettent
d'écrire des programmes dans du code Apex. En utilisant ces constructions du
langage, vous pouvez déclarer des variables et des constantes de types de données
intégrés (primitifs et sObjects) énumérations, et des types de données
personnalisées basées sur le système et des types Apex fournis par l'utilisateur.
Le langage Apex fournit des expressions, des instructions d'attribution et
conditionnelles. Comme d'autres langages de programmation, le langage Apex
fournit un traitement des exceptions et différents types de boucle. Contrairement
à d'autres, le langage Apex a un type de boucle spécial appelé SOQL for loop,
qui permet de traiter les résultats de requêtes par lot. Le langage Apex est intégré
à la base de données. Il permet d'écrire des requêtes en ligne, d'effectuer un
verrouillage d'enregistrement et de contrôler les transactions.
Les constructions de langage suivantes forment les éléments de base du langage
Apex :
•
•
•
•
•
•
•
•
•
•
Types de données
Variables
Expressions
Instructions d'attribution
Instructions conditionnelles (If-Else)
Boucles
Requêtes SOQL et SOSL
Instructions de verrouillage
Contrôle des transactions
Instructions d'exception
Le code Apex est contenu dans un déclencheur ou dans une classe. Pour plus
d'informations, reportez-vous à Déclencheurs à la page 96 et Classes, objets et
interfaces à la page 124.
Constructions du langage
salesforce | Types de données | 29
Types de données
Dans le langage Apex, toutes les variables et expressions ont l'un des types de données suivants :
•
•
•
Un primitif, qui comprend Integer, Double, Long, Date, Datetime, String, ID ou Boolean (reportez-vous à Types de
données Primitive à la page 29)
Un sObject, générique ou spécifique, qui comprend Account, Contact ou MyCustomObject__c (reportez-vous à Types
sObject à la page 32)
Une collection, qui comprend :
◊ Une liste (ou un tableau) de primitifs, sObjects, objets définis par l'utilisateur ou créés à partir de classes Apex, ou des
collections (reportez-vous à Lists à la page 38)
◊ Un ensemble de primitifs (reportez-vous à Sets à la page 46)
◊ Un mappage d'un primitif avec un primitif, un sObject ou une collection (reportez-vous à Maps à la page 47)
•
•
•
•
Une liste de valeurs typée, également appelée enum (reportez-vous à Enumérations à la page 53)
Des objets créés à partir de classes Apex définies par l'utilisateur (reportez-vous à Classes, objets et interfaces à la page 124)
Des objets créés à partir de classes Apex fournies par le système (reportez-vous à Classes Apex à la page 565)
Type null (pour la constante null, qui peut être attribué à n'importe quelle variable)
Les méthodes peuvent renvoyer n'importe quel type de valeur ci-dessus, ou ne renvoyer aucune valeur et être de type Void.
La vérification du type s'applique uniquement lors de la compilation. Par exemple, l'analyseur génère une erreur si un champ
objet de type Nombre entier est attribué à une valeur de type Chaîne. Cependant, toutes les exceptions de compilation sont
renvoyées en tant que code d'erreur spécifique, avec le numéro de ligne et la colonne de l'erreur. Pour plus d'informations,
reportez-vous à Débogage Apex à la page 255.
Type de données Primitive
Le langage Apex utilise les mêmes types de données primitifs que l'API SOAP. Tous les types de données primitifs sont
transmis par valeur.
Toutes les variables Apex, qu'elles soient des variables membres de classe ou des variables de méthode, sont initialisées sur
null. Assurez-vous d'initialiser vos variables sur les valeurs appropriées avant de les utiliser. Par exemple, initialisez une variable
Boolean sur false.
Les types de données primitifs Apex comprennent :
Type de données
Description
Blob
Une collection de données binaires stockées en tant qu'objet unique. Vous pouvez convertir
ce type de données en String ou à partir de String utilisant les méthodes toString et
valueOf, respectivement. Les Blobs peuvent être acceptés en tant qu'arguments de services
Web, stockés dans un document (le corps d'un document est un Blob), ou envoyés en tant
que pièces jointes. Pour plus d'informations, reportez-vous à Classe Crypto à la page 648.
Boolean
Une valeur qui peut être attribuée uniquement à true, false ou null. Par exemple :
Boolean isWinner = true;
Constructions du langage
salesforce | Type de données Primitive | 30
Type de données
Description
Date
Une valeur qui indique un jour spécifique. Contrairement aux valeurs Datetime, les valeurs
Date ne contiennent aucune information horaire. Les valeurs Date doivent toujours être créées
avec une méthode statique système.
Vous ne pouvez pas manipuler une valeur Date, par exemple ajouter des jours, en ajoutant
simplement un chiffre à une variable Date. Vous devez utiliser à la place des méthodes Date.
Datetime
Une valeur qui indique un jour et une heure spécifiques, telle qu'un horodatage. Les valeurs
Datetime doivent toujours être créées avec une méthode statique système.
Vous ne pouvez pas manipuler une valeur Datetime, par exemple ajouter des minutes, en
ajoutant simplement un chiffre à une variable Datetime. Vous devez utiliser à la place des
méthodes Datetime.
Decimal
Un chiffre qui indique un point décimal. Le type Decimal est une valeur de précision arbitraire.
Les champs de devise sont automatiquement attribués au type Decimal.
Si vous ne définissez pas explicitement l'échelle, c.-à-d. le nombre de décimales pour un type
Decimal qui utilise la méthode setScale, l'échelle est déterminée par l'élément à partir
duquel le type Decimal a été créé.
•
•
•
Double
Si le Decimal est créé dans le cadre d'une requête, l'échelle est basée sur l'échelle du champ
renvoyé à partir de la requête.
Si le Decimal est créé à partir d'une String, l'échelle correspond au nombre de caractères
après le point décimal de la chaîne.
Si le Decimal est créé à partir d'un chiffre non décimal, l'échelle est déterminée en
convertissant le nombre en String, puis en utilisant le nombre de caractères après le point
décimal.
Un chiffre 64 bits qui indique un point décimal. Les types Double ont une valeur minimale
de -263 et une valeur maximale de 263-1. Par exemple :
Double d=3.14159;
Notez la notation scientifique (e) pour les Doubles n'est pas prise en charge.
ID
N'importe quel identifiant d'enregistrement Force.com de 18 caractères valide. Par exemple
:
ID id='00300000003T2PGAA0';
Notez si vous définissez ID sur une valeur de 15 caractères, Apex convertit automatiquement
la valeur en représentation de 18 caractères. Toutes les valeurs ID non valides sont rejetées
avec une exception d'exécution.
Integer
Un chiffre 32 bits qui n'inclut pas de point décimal. Les types Integer ont une valeur minimale
de -2 147 483 648 est une valeur maximale de 2 147 483 647. Par exemple :
Integer i = 1;
Constructions du langage
salesforce | Type de données Primitive | 31
Type de données
Description
Long
Un chiffre 64 bits qui n'inclut pas de point décimal. Les types Long ont une valeur minimale
de -263 et une valeur maximale de 263-1. Utilisez ce type de données lorsque vous avez besoin
d'une plage de valeurs plus large que celle fournie par le type Integer. Par exemple :
Long l = 2147483648L;
String
N'importe quel jeu de caractères entre guillemets. Par exemple :
String s = 'The quick brown fox jumped over the lazy dog.';
Taille de chaîne : Le nombre de caractères que les types String peuvent inclure est limité. À
la place, la limite du segment mémoire est utilisée pour éviter que vos programmes Apex ne
soient trop volumineux.
Chaînes vides et espaces de fin : Les valeurs de champ sObject String appliquent les mêmes
règles que l'API SOAP : elles ne peuvent jamais être vides (uniquement null), et ne peuvent
jamais inclure d'espaces de début et de fin. Ces conventions sont nécessaires pour le stockage
de la base de données.
Inversement, les types String dans le langage Apex peuvent être null ou vides, et peuvent
inclure des espaces de début et de fin (par exemple pour construire un message).
Le champ sObject de solution, SolutionNote, fonctionne en tant que type String spécial. Si
vous avez des solutions HTML activées, toutes les balises HTML utilisées dans ce champ
sont vérifiées avant la création ou la mise à jour de l'objet. Si des balises HTML non valides
sont saisies, une erreur est générée. Tout JavaScript utilisé dans ce champ est supprimé avant
la création ou la mise à jour de l'objet. Dans l'exemple suivant, lorsque la Solution s'affiche
dans une page de détail, une mise en forme HTML H1 est appliquée au champ SolutionNote
:
trigger t on Solution (before insert) {
Trigger.new[0].SolutionNote ='<h1>hello</h1>';
}
Dans l'exemple suivant, lorsque la Solution s'affiche dans une page de détail, le champ
SolutionNote contient uniquement HelloGoodbye :
trigger t2 on Solution (before insert) {
Trigger.new[0].SolutionNote =
'<javascript>Hello</javascript>Goodbye';
}
Pour plus d'informations, reportez-vous à « Présentation des solutions HTML ».
Séquences d'échappement : Tous les types String dans le langage Apex utilisent les mêmes
séquences d'échappement que les chaînes SOQL : \b (retour arrière), \t (tabulation), \n
Constructions du langage
Type de données
salesforce | Types sObject | 32
Description
(saut de ligne), \f (saut de page), \r (retour chariot), \" (guillemets), \' (apostrophe) et \\
(barre oblique inverse).
Opérateurs de comparaison : Contrairement à Java, le type String Apex prend en charge
l'utilisation des opérateurs de comparaison ==, !=, <, <=, > et >=. Comme le langage Apex
utilise des sémantiques de comparaison SOQL, les résultats des types String sont comparés
en fonction des paramètres régionaux de l'utilisateur contextuel, et ne sont pas sensibles à la
casse. Pour plus informations, reportez-vous à Opérateurs à la page 60.
Méthodes de chaîne : Comme dans le langage Java, les types String peuvent être manipulés
par plusieurs méthodes standard. Pour plus d'informations, reportez-vous à Méthodes String.
Les classes et les déclencheurs Apex sauvegardés (compilés) en utilisant l'API versions 15.0
et supérieures, génèrent une erreur d'exécution si vous attribuez une valeur String trop longue
pour le champ.
Time
Une valeur qui indique une heure spécifique. Les valeurs Time doivent toujours être créées
avec une méthode statique système. Reportez-vous à Méthodes Time à la page 409.
De plus, deux types de données primitifs non standard ne peuvent pas être utilisés en tant que type de variable ou de méthode,
mais figurent dans des méthodes statiques système :
•
•
AnyType. La méthode statique valueOf convertit un champ sObject de type AnyType en primitif standard. AnyType
est utilisé dans la base de données de la plate-forme Force.com exclusivement pour des champs sObject dans des tableaux
de suivi d'historique des champs.
Currency. La méthode statique Currency.newInstance crée un type Currency littéral. Cette méthode est utilisée
exclusivement dans des clauses SOQL et SOSL WHERE pour filtrer par des champs de devise sObject. Vous ne pouvez pas
instancier Currency dans un autre type Apex.
Pour plus d'informations sur le type de données AnyType, reportez-vous à Field Types dans le guide Object Reference for
Salesforce and Force.com.
Types sObject
Dans le guide du développeur, le terme sObject fait référence à un objet qui peut être stocké dans la base de données de la
plate-forme Force.com. Une variable sObject représente une ligne de données et peut être déclarée dans Apex uniquement en
utilisant le nom d'API SOAP de l'objet. Par exemple :
Account a = new Account();
MyCustomObject__c co = new MyCustomObject__c();
Semblable à l'API SOAP, le langage Apex permet d'utiliser le type sObject abstrait générique pour représenter n'importe quel
objet. Le type de données sObject peut être utilisé dans du code qui traite différents types de sObject.
L'opérateur new requiert toutefois un type sObject concret. Par conséquent, toutes les instances sont des sObjects spécifiques.
Par exemple :
sObject s = new Account();
Constructions du langage
salesforce | Types sObject | 33
Vous pouvez également utiliser une conversion (casting) entre le type sObject générique et le type sObject spécifique. Par
exemple :
// Cast the generic variable s from the example above
// into a specific account and account variable a
Account a = (Account)s;
// The following generates a runtime error
Contact c = (Contact)s;
Puisque les sObjects fonctionnent comme des objects, vous pouvez également avoir :
Object obj = s;
// and
a = (Account)obj;
Les opérations DML fonctionnent dans des variables déclarées en tant que type de données sObject générique ainsi que dans
des sObjects réguliers.
Les variables sObject sont initialisées sur null, mais une référence d'objet valide peut leur être attribuée avec l'opérateur new.
Par exemple :
Account a = new Account();
Les développeurs peuvent également spécifier des valeurs de champs initiales avec des paires nom = valeur, séparées par
des virgules, en instanciant un nouveau sObject. Par exemple :
Account a = new Account(name = 'Acme', billingcity = 'San Francisco');
Pour plus d'informations sur l'accès à des sObjects existants à partir de la base de données de la plate-forme Force.com,
reportez-vous à Requêtes SOQL et SOSL à la page 77.
Remarque: L'ID d'un sObject est une valeur en lecture seule qui ne peut jamais être modifiée explicitement dans
Apex, sauf si elle est effacée pendant une opération de clonage ou attribuée avec un constructeur. La plate-forme
Force.com attribue des valeurs ID automatiquement lors de l'insertion initiale d'un enregistrement d'objet dans la
base de données. Pour plus informations, reportez-vous à Listes à la page 38.
Étiquettes personnalisées
Les étiquettes personnalisées ne sont pas des sObjects standard. Vous ne pouvez pas créer une instance d'une étiquette
personnalisée. Vous pouvez accéder à la valeur d'une étiquette personnalisée uniquement en utilisant
system.label.label_name. Par exemple :
String errorMsg = System.Label.generic_error;
Pour plus d'informations sur les étiquettes personnalisées, reportez-vous à Présentation des étiquettes personnalisées.
Constructions du langage
salesforce | Types sObject | 34
Accès aux champs sObject
Comme dans Java, les champs sObject peuvent être accédés ou modifiés avec une simple notation pointée. Par exemple :
Account a = new Account();
a.Name = 'Acme';
// Access the account name field and assign it 'Acme'
Les champs générés par le système, tels que Created By (Créé par) ou Last Modified Date (Date de dernière
modification), ne sont pas modifiables. Si vous essayez de les modifier, le moteur d'exécution Apex génère une erreur. En
outre, les valeurs de champs de formule et les valeurs d'autres champs en lecture seule pour l'utilisateur contextuel, ne sont pas
modifiables.
Si vous utilisez un type sObject générique à la place d'un objet spécifique, tel que Compte, vous pouvez récupérer uniquement
le champ Id en utilisant une notation pointée. Vous pouvez définir le champ Id pour le code Apex enregistré en utilisant
l'API Salesforce.com (versions 27.0 et supérieures). Vous pouvez également utiliser les méthodes sObject génériques put et
get. Reportez-vous à Méthodes sObject.
Cet exemple montre comment accéder au champ Id et présente les opérations qui ne sont pas autorisées dans des sObjects
génériques.
Account a = new Account(Name = 'Acme', BillingCity = 'San Francisco');
insert a;
sObject s = [SELECT Id, Name FROM Account WHERE Name = 'Acme' LIMIT 1];
// This is allowed
ID id = s.Id;
// The following line results in an error when you try to save
String x = s.Name;
// This line results in an error when you try to save using API version 26.0 or earlier
s.Id = [SELECT Id FROM Account WHERE Name = 'Acme' LIMIT 1].Id;
Remarque: Si votre organisation a des comptes personnels activés, vous disposez de deux types de compte : comptes
professionnels et comptes personnels. Si votre code crée un compte en utilisant name, un compte professionnel est
créé. Si votre code utilise LastName, un compte personnel est créé.
Si vous souhaitez effectuer des opérations avec un sObject, nous recommandons de le convertir au préalable en objet spécifique.
Par exemple :
Account a = new Account(Name = 'Acme', BillingCity = 'San Francisco');
insert a;
sObject s = [SELECT Id, Name FROM Account WHERE Name = 'Acme' LIMIT 1];
ID id = s.ID;
Account convertedAccount = (Account)s;
convertedAccount.name = 'Acme2';
Constructions du langage
salesforce | Types sObject | 35
update convertedAccount;
Contact sal = new Contact(FirstName = 'Sal', Account = convertedAccount);
L'exemple suivant montre comment utiliser SOSL sur un ensemble d'enregistrements afin de déterminer leur type d'objet.
Une fois l'enregistrement sObject générique converti en Contact, Piste ou Compte, vous pouvez modifier ses champs en
conséquence :
public class convertToCLA {
List<Contact> contacts;
List<Lead> leads;
List<Account> accounts;
public void convertType(Integer phoneNumber) {
List<List<sObject>> results = [FIND '4155557000'
IN Phone FIELDS
RETURNING Contact(Id, Phone, FirstName, LastName),
Lead(Id, Phone, FirstName, LastName), Account(Id, Phone, Name)];
sObject[] records = ((List<sObject>)results[0]);
if (!records.isEmpty()) {
for (Integer i = 0; i < records.size(); i++) {
sObject record = records[i];
if (record.getSObjectType() == Contact.sObjectType) {
contacts.add((Contact) record);
} else if (record.getSObjectType() == Lead.sObjectType){
leads.add((Lead) record);
} else if (record.getSObjectType() == Account.sObjectType) {
accounts.add((Account) record);
}
}
}
}
}
Constructions du langage
salesforce | Types sObject | 36
Accès aux champs sObject via des relations
Les enregistrements sObject représentent des relations à d'autres enregistrements avec deux champs : un ID et une adresse
qui pointe vers une représentation du sObject associé. Par exemple, le sObject Contact contient un champ AccountId de
type ID et un champ Account de type Compte qui pointent vers l'enregistrement sObject associé lui-même.
Le champ ID peut être utilisé pour modifier le compte auquel le contact est associé, alors que le champ de référence sObject
peut être utilisé pour accéder aux données à partir du compte. Le champ de référence est renseigné uniquement suite à une
requête SOQL ou SOSL (voir la remarque ci-dessous).
Par exemple, le code Apex ci-dessous montre comment un compte et un contact peuvent être associés entre eux, et comment
utiliser le contact pour modifier un champ dans le compte :
Remarque: Pour offrir un exemple le plus complet possible, ce code utilise quelques éléments présentés plus loin
dans ce guide :
•
•
Pour plus d'informations sur insert et update, reportez-vous à Opération Insert à la page 334 et Opération
Update à la page 334.
Pour plus informations sur SOQL et SOSL, reportez-vous à Requêtes SOQL et SOSL à la page 77.
Account a = new Account(Name = 'Acme');
insert a;
// Inserting the record automatically assigns a
// value to its ID field
Contact c = new Contact(LastName = 'Weissman');
c.AccountId = a.Id;
// The new contact now points at the new account
insert c;
// A SOQL query accesses data for the inserted contact,
// including a populated c.account field
c = [SELECT Account.Name FROM Contact WHERE Id = :c.Id];
// Now fields in both records can be changed through the contact
c.Account.Name = 'salesforce.com';
c.LastName = 'Roth';
// To update the database, the two types of records must be
// updated separately
update c;
// This only changes the contact's last name
update c.Account; // This updates the account name
Constructions du langage
salesforce | Types sObject | 37
Remarque: L'expression c.Account.Name, ainsi que toute autre expression qui traverse une relation, affiche des
caractéristiques légèrement différentes lorsqu'elle est lue en tant que valeur que lorsqu'elle est modifiée :
•
•
Lors de sa lecture en tant que valeur, si c.Account est null, c.Account.Name évalue en null, mais ne génère
pas une exception NullPointerException. Cette conception permet aux développeurs de naviguer entre
plusieurs relations sans avoir à vérifier la présence de valeurs nulles.
Lors de sa modification, si c.Account est null, c.Account.Name génère une exception
NullPointerException.
En outre, la clé du champ sObject peut être utilisée avec insert, update ou upsert pour résoudre des clés étrangères par
ID externe. Par exemple :
Account refAcct = new Account(externalId__c = '12345');
Contact c = new Contact(Account = refAcct, LastName = 'Kay');
insert c;
Un nouveau contact est inséré avec AccountId égal au compte avecexternal_id égal à 12345. Si ce compte n'existe pas,
l'insertion échoue.
Conseil:
Le code ci-dessous est équivalent au code ci-dessus. Cependant, comme il utilise une requête SOQL, il n'est pas aussi
efficace. Si ce code était appelé plusieurs fois, il risquerait d'atteindre la limite d'exécution en nombre maximal de
requêtes SOQL. Pour plus d'informations sur les limites d'exécution, reportez-vous à Compréhension des limitations
et des gouverneurs d'exécution à la page 273.
Account refAcct = [SELECT Id FROM Account WHERE externalId__c='12345'];
Contact c = new Contact(Account = refAcct.Id);
insert c;
Validation de sObjects et de champs
Lors de l'analyse et de la validation du code Apex, toutes les références de sObject et de champ sont validées par rapport aux
noms d'objet et de champ, et une exception est générée si un nom incorrect est utilisé.
En outre, l'analyseur Apex surveille les objets et les champs personnalisés utilisés, dans la syntaxe du code ainsi que dans les
instructions SOQL et SOSL incorporées. La plate-forme empêche les utilisateurs d'effectuer les modifications de type
ci-dessous, si elles entraînent l'invalidation du code Apex :
•
Modifier le nom d'un champ ou d'un objet
Constructions du langage
•
•
•
salesforce | Collections | 38
Convertir un type de données vers un autre
Supprimer un champ ou un objet
Modifier certains éléments à l'échelle de l'organisation, tels que le partage d'enregistrements, le suivi d'historique de champs
ou des types d'enregistrement
Collections
Le langage Apex inclut les types de collection suivants :
•
•
•
Lists
Maps
Sets
Remarque: Le nombre d'éléments qu'une collection peut contenir est illimité. Il existe toutefois une limite générale
en taille de segment mémoire.
Listes
Une liste est une collection ordonnée de d'objets primitifs typés, sObjects, définis par l'utilisateur, Apex ou de collections qui
se différencient par leur index. Par exemple, le tableau suivant est une représentation visuelle d'une liste de chaînes (String) :
Index 0
Index 1
Index 2
Index 3
Index 4
Index 5
'Rouge'
'Orange'
'Jaune'
'Vert'
'Bleu'
'Violet'
La position d'index du premier élément dans une liste est toujours 0.
Puisque les listes peuvent contenir n'importe qu'elle collection, elles peuvent être imbriquées les unes dans les autres et devenir
multidimensionnelles. Par exemple, vous pouvez avoir une liste de listes d'ensembles de nombres entiers. Une liste peut contenir
jusqu'à quatre niveaux de collections imbriquées.
Pour déclarer une liste, utilisez le mot clé List suivi du type de données primitif, sObject, liste imbriquée, carte ou ensemble
entre crochets <>. Par exemple :
// Create an empty list of String
List<String> my_list = new List<String>();
// Create a nested list
List<List<Set<Integer>>> my_list_2 = new List<List<Set<Integer>>>();
// Create a list of account records from a SOQL query
List<Account> accs = [SELECT Id, Name FROM Account LIMIT 1000];
Pour accéder aux éléments d'une liste, utilisez les méthodes système fournies par Apex. Par exemple :
List<Integer> MyList = new List<Integer>(); // Define a new list
MyList.add(47);
// Adds a second element of value 47 to the end
Constructions du langage
salesforce | Collections | 39
// of the list
MyList.get(0);
// Retrieves the element at index 0
MyList.set(0, 1);
// Adds the integer 1 to the list at index 0
MyList.clear();
// Removes all elements from the list
Pour plus d'informations, notamment une liste complète de toutes les méthodes prises en charge, reportez-vous à Méthodes
List à la page 411.
Utilisation d'une notation tabulaire pour des listes unidimensionnelles de primitifs ou de sObjects
Lors de l'utilisation d'une liste unidimensionnelle de primitifs ou de sObjects, vous pouvez utiliser une notation tabulaire plus
traditionnelle pour déclarer et référencer les éléments de liste. Par exemple, vous pouvez déclarer une liste unidimensionnelle
de primitifs ou de sObjects en suivant les données ou le nom du type sObject entre les crochets droits [] :
String[] colors = new List<String>();
Pour référencer un élément d'une liste unidimensionnelle de primitifs ou de sObjects, vous pouvez également suivre le nom
de la liste avec la position d'index de l'élément entre crochets droits. Par exemple :
colors[3] = 'Green';
Toutes les listes sont initialisées sur null. Des valeurs peuvent être attribuées et de la mémoire peut être allouée aux listes en
utilisant une notation littérale. Par exemple :
Exemple
Description
Définit une liste Integer sans élément
List<Integer> ints = new Integer[0];
Définit une liste Account sans élément
List<Account> accts = new Account[]{};
List<Integer> ints = new Integer[6];
List<Account> accts = new Account[]
{new Account(), null, new
Account()};
Définit une liste Integer avec de la mémoire allouée pour six
nombres entiers
Définit une liste Account avec de la mémoire allouée pour
trois comptes, qui comprend un nouvel objet Account en
première position, null en deuxième position et un autre
objet Account en troisième position
Définit la liste Contact avec une nouvelle liste
List<Contact> contacts = new List<Contact>
(otherList);
Constructions du langage
salesforce | Collections | 40
Listes de sObjects
Le langage Apex génère automatiquement des ID pour chaque objet dans une liste de sObjects lors de l'insertion ou de la mise
à jour/insertion dans la base de données avec une instruction DML (langage de manipulation de données). Par conséquent,
une liste de sObjects ne peut pas être insérée ou mise à jour/insérée si elle contient plusieurs fois le même sObject, même avec
un ID null. Cette situation nécessiterait que deux ID soient écrits en mémoire avec la même structure, ce qui est illégal.
Par exemple, l'instruction insert dans le bloc de code ci-dessous génère une exception ListException, car elle tente
d'insérer une liste avec deux références au même sObject (a) :
try {
// Create a list with two references to the same sObject element
Account a = new Account();
Account[] accs = new Account[]{a, a};
// Attempt to insert it...
insert accs;
// Will not get here
System.assert(false);
} catch (ListException e) {
// But will get here
}
Pour plus d'informations sur les instructions DML, reportez-vous à Opérations DML (langage de manipulation de données)
Apex à la page 327.
Vous pouvez utiliser des types de données sObject génériques avec des listes. Vous pouvez également créer une instance
générique d'une liste.
Tri des listes
En utilisant la méthode List.sort, vous pouvez trier des listes de types de données primitifs, des types personnalisés (vos
classes Apex) qui implémentent l'interface Comparable, des éléments SelectOption et des sObjects (objets standard et objets
personnalisés).
Le tri des types de données primitifs est ascendant.
Pour des types personnalisés, les critères de tri et l'ordre de tri dépendent de l'implémentation que vous fournissez pour la
méthode compareTo de l'interface Comparable. Pour plus d'informations sur l'implémentation de l'interface Comparable
pour vos propres classes, reportez-vous à Interface Comparable.
Pour des sObjects, l'ordre de tri est ascendant et utilise une séquence d'étapes présentées dans la section suivante. Cependant,
vous pouvez également implémenter un ordre de tri personnalisé pour des sObjects en encapsulant votre sObject dans une
classe Apex et en implémentant l'interface Comparable, comme indiqué dans Ordre de tri personnalisé pour des sObjects.
Constructions du langage
salesforce | Collections | 41
Pour SelectOption, l'ordre de tri est ascendant, basé sur les champs de valeur et d'étiquette. Pour consulter la séquence d'étapes
de comparaison de SelectOption, reportez-vous à Ordre de tri par défaut pour SelectOption.
Ordre de tri par défaut des sObjects
La méthode List.sort trie les sObjects dans l'ordre ascendant, et compare les sObjects en utilisant une séquence triées
d'étapes qui spécifient les étiquettes ou les champs utilisés. La comparaison commence à la première étape de la séquence et
se termine lorsque les deux sObjects sont triés en utilisant les étiquettes ou les champs spécifiés. La séquence de comparaison
utilisée est la suivante :
1. L'étiquette du type sObject.
Par exemple, un sObject Account précède un Contact.
2. Le champ Name, si applicable.
Par exemple, si la liste inclut deux comptes nommés respectivement A et B, le compte A précède le compte B.
3. Les champs standard, en commençant par les premiers champs dans l'ordre alphabétique, à l'exception des champs ID et
Name.
Par exemple, si deux comptes portent le même nom, le premier champ standard utilisé pour le tri est AccountNumber.
4. Les champs personnalisés, en commençant par les premiers champs dans l'ordre alphabétique.
Par exemple, supposons que deux comptes portent le même nom, ont des champs standard identiques et que deux champs
personnalisés existent, FieldA et FieldB. La valeur de FieldA est utilisée en premier pour le tri.
Les étapes de cette séquence ne sont pas nécessairement toutes exécutées. Par exemple, si une liste contient deux sObjects du
même type avec des valeurs Name uniques, ils sont triés en fonction du champ Name et le tri s'arrête à l'étape 2. Sinon, si les
noms sont identiques ou si le sObject n'a pas de champ Name, le tri passe à l'étape 3 pour trier par champ standard.
Pour les champs de texte, l'algorithme de tri utilise l'ordre de tri Unicode. De plus, les champs vides précèdent les champs non
vides dans l'ordre de tri.
L'exemple ci-dessous présente le tri d'une liste de sObject Account. Cet exemple montre comment le champ Name est utilisé
pour placer le compte Acme devant les deux comptes sForce dans la liste. Comme il existe deux comptes nommés sForce, le
champ Industry est utilisé pour trier les comptes restants, car Industry précède le champ Site dans l'ordre alphabétique.
Account[] acctList = new List<Account>();
acctList.add( new Account(
Name='sForce',
Industry='Biotechnology',
Site='Austin'));
acctList.add(new Account(
Name='sForce',
Industry='Agriculture',
Site='New York'));
acctList.add(new Account(
Name='Acme'));
System.debug(acctList);
Constructions du langage
salesforce | Collections | 42
acctList.sort();
System.assertEquals('Acme', acctList[0].Name);
System.assertEquals('sForce', acctList[1].Name);
System.assertEquals('Agriculture', acctList[1].Industry);
System.assertEquals('sForce', acctList[2].Name);
System.assertEquals('Biotechnology', acctList[2].Industry);
System.debug(acctList);
Cet exemple est similaire au précédent, mais il utilise l'objet personnalisé Merchandise__c. Il montre comment le champ Name
est utilisé pour placer les articles Notebooks avant les Pens dans la liste. Comme il existe deux articles sObjects dont le champ
Name inclut la valeur Pens, le champ Description est utilisé pour trier les articles restants, car Description précède les champs
Price et Total_Inventory dans l'ordre alphabétique.
Merchandise__c[] merchList = new List<Merchandise__c>();
merchList.add( new Merchandise__c(
Name='Pens',
Description__c='Red pens',
Price__c=2,
Total_Inventory__c=1000));
merchList.add( new Merchandise__c(
Name='Notebooks',
Description__c='Cool notebooks',
Price__c=3.50,
Total_Inventory__c=2000));
merchList.add( new Merchandise__c(
Name='Pens',
Description__c='Blue pens',
Price__c=1.75,
Total_Inventory__c=800));
System.debug(merchList);
merchList.sort();
System.assertEquals('Notebooks', merchList[0].Name);
System.assertEquals('Pens', merchList[1].Name);
System.assertEquals('Blue pens', merchList[1].Description__c);
System.assertEquals('Pens', merchList[2].Name);
Constructions du langage
salesforce | Collections | 43
System.assertEquals('Red pens', merchList[2].Description__c);
System.debug(merchList);
Ordre de tri personnalisé des sObjects
Pour implémenter un ordre de tri personnalisé pour des sObjects dans des listes, créez une classe wrapper pour le sObject et
implémentez l'interface Comparable. La classe wrapper contient le sObject en question et implémente la méthode compareTo,
dans laquelle vous spécifiez la logique de tri.
Cet exemple montre comment créer une classe wrapper pour Opportunité. L'implémentation de la méthode compareTo dans
cette classe compare deux opportunités basées sur le champ Amount : la variable membre de la classe contenue dans cette
instance, et l'objet opportunité transmis dans la méthode.
global class OpportunityWrapper implements Comparable {
public Opportunity oppy;
// Constructor
public OpportunityWrapper(Opportunity op) {
oppy = op;
}
// Compare opportunities based on the opportunity amount.
global Integer compareTo(Object compareTo) {
// Cast argument to OpportunityWrapper
OpportunityWrapper compareToOppy = (OpportunityWrapper)compareTo;
// The return value of 0 indicates that both elements are equal.
Integer returnValue = 0;
if (oppy.Amount > compareToOppy.oppy.Amount) {
// Set return value to a positive value.
returnValue = 1;
} else if (oppy.Amount < compareToOppy.oppy.Amount) {
// Set return value to a negative value.
returnValue = -1;
}
return returnValue;
Constructions du langage
salesforce | Collections | 44
}
}
Cet exemple fournit un test pour la classe OpportunityWrapper. Il trie une liste d'objets OpportunityWrapper et vérifie
que les éléments de la liste sont triés par le montant de l'opportunité.
@isTest
private class OpportunityWrapperTest {
static testmethod void test1() {
// Add the opportunity wrapper objects to a list.
OpportunityWrapper[] oppyList = new List<OpportunityWrapper>();
Date closeDate = Date.today().addDays(10);
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='Edge Installation',
CloseDate=closeDate,
StageName='Prospecting',
Amount=50000)));
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='United Oil Installations',
CloseDate=closeDate,
StageName='Needs Analysis',
Amount=100000)));
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='Grand Hotels SLA',
CloseDate=closeDate,
StageName='Prospecting',
Amount=25000)));
// Sort the wrapper objects using the implementation of the
// compareTo method.
oppyList.sort();
// Verify the sort order
System.assertEquals('Grand Hotels SLA', oppyList[0].oppy.Name);
System.assertEquals(25000, oppyList[0].oppy.Amount);
Constructions du langage
salesforce | Collections | 45
System.assertEquals('Edge Installation', oppyList[1].oppy.Name);
System.assertEquals(50000, oppyList[1].oppy.Amount);
System.assertEquals('United Oil Installations', oppyList[2].oppy.Name);
System.assertEquals(100000, oppyList[2].oppy.Amount);
// Write the sorted list contents to the debug log.
System.debug(oppyList);
}
}
Ordre de tri par défaut pour SelectOption
La méthode List.sort trie les éléments SelectOption dans l'ordre ascendant en utilisant les champs de valeur et d'étiquette,
et elle est basée sur une séquence de comparaison.
1. Le champ de valeur est utilisé pour trier le premier.
2. Si deux champ de valeur contiennent la même valeur ou sont vides, le champ d'étiquette est utilisé.
Notez que le champ désactivé n'est pas utilisé pour le tri.
Pour les champs de texte, l'algorithme de tri utilise l'ordre de tri Unicode. De plus, les champs vides précèdent les champs non
vides dans l'ordre de tri.
Dans cet exemple, une liste contient trois éléments SelectOption. Deux éléments, United States et Mexico, ont le même champ
de valeur ('A'). La méthode List.sort trie ces deux éléments par le champ d'étiquette, et place Mexico avant United States,
comme indiqué dans la sortie. Le dernier élément de la liste triée est Canada, trié par son champ de valeur 'C', qui précède
'A'.
List<SelectOption> options = new List<SelectOption>();
options.add(new SelectOption('A','United States'));
options.add(new SelectOption('C','Canada'));
options.add(new SelectOption('A','Mexico'));
System.debug('Before sorting: ' + options);
options.sort();
System.debug('After sorting: ' + options);
La sortie des instructions de débogage est la suivante. Elle affiche le contenu de la liste avant et après le tri.
DEBUG|Before sorting: (System.SelectOption[value="A", label="United States",
disabled="false"],
System.SelectOption[value="C", label="Canada", disabled="false"],
System.SelectOption[value="A", label="Mexico", disabled="false"])
DEBUG|After sorting: (System.SelectOption[value="A", label="Mexico", disabled="false"],
System.SelectOption[value="A", label="United States", disabled="false"],
Constructions du langage
salesforce | Collections | 46
System.SelectOption[value="C", label="Canada", disabled="false"])
Sets
Un ensemble (set) est une collection non triée d'éléments qui ne contient aucun doublon. Les éléments Set peuvent avoir
n'importe quel type : primitif, collection, sObjects, défini par l'utilisateur et Apex intégré. Par exemple, le tableau suivant
représente un ensemble de chaînes qui utilise des noms de villes :
'San Francisco'
'New York'
'Paris'
'Tokyo'
Des ensembles Set peuvent contenir des collections imbriquées les unes dans les autres. Par exemple, vous pouvez avoir un
ensemble de listes d'ensembles de nombres entiers. Un ensemble peut contenir jusqu'à quatre niveaux de collections imbriquées.
Pour déclarer un ensemble, utilisez le mot clé Set suivi du nom du type de données primitif entre crochets <>. Par exemple :
new Set<String>()
Les méthodes de déclaration et de renseignement d'un ensemble sont les suivantes :
Set<String> s1 = new Set<String>{'a', 'b + c'}; // Defines a new set with two elements
Set<String> s2 = new Set<String>(s1); // Defines a new set that contains the
// elements of the set created in the previous step
Pour accéder aux éléments d'un ensemble, utilisez les méthodes système fournies par Apex. Par exemple :
Set<Integer> s = new Set<Integer>(); // Define a new set
s.add(1);
// Add an element to the set
System.assert(s.contains(1));
// Assert that the set contains an element
s.remove(1);
// Remove the element from the set
Pour déterminer si des objets non primitifs sont uniques, les champs des objets sont comparés, à l'exception des objets de type
défini par l'utilisateur. Par exemple si vous essayez d'ajouter deux comptes portant le même nom dans un ensemble, un seul
est ajouté.
// Create two accounts, a1 and a2
Account a1 = new account(name='MyAccount');
Account a2 = new account(name='MyAccount');
// Add both accounts to the new set
Set<Account> accountSet = new Set<Account>{a1, a2};
// Verify that the set only contains one item
Constructions du langage
salesforce | Collections | 47
System.assertEquals(accountSet.size(), 1);
Cependant, si vous ajoutez une description à l'un des comptes, il est considéré comme unique :
// Create two accounts, a1 and a2, and add a description to a2
Account a1 = new account(name='MyAccount');
Account a2 = new account(name='MyAccount', description='My test account');
// Add both accounts to the new set
Set<Account> accountSet = new Set<Account>{a1, a2};
// Verify that the set contains two items
System.assertEquals(accountSet.size(), 2);
Pour déterminer si les objets de type défini par l'utilisateur sont uniques, les méthodes equals et hashCode sont utilisées,
que vous fournissez dans vos classes.
Pour plus d'informations, notamment une liste complète de toutes les méthodes système Set prises en charge, reportez-vous
à Méthodes Set à la page 427.
Notez les limitations suivantes des ensembles :
•
•
Contrairement au langage Java, les développeurs Apex n'ont pas besoin de référencer l'algorithme utilisé pour implémenter
un ensemble dans leurs déclarations (par exemple, HashSet ou TreeSet). Le langage Apex utilise une structure hash
pour tous les ensembles.
Un ensemble est une collection non triée. Ne vous appuyez pas sur l'ordre dans lequel les résultats de l'ensemble sont
renvoyés. L'ordre des objets renvoyés par les ensembles peut changer sans avertissement.
Maps
Un map (mappage) est une collection de paires clé-valeur dans lesquelles chaque clé unique est mappée avec une valeur unique.
Les clés et les valeurs peuvent avoir n'importe quel type : primitif, collection, sObjects, défini par l'utilisateur et Apex intégré.
Par exemple, le tableau suivant présente un mappage de pays et de devises :
Pays (clé)
'États-Unis'
'Japon'
'France'
'Angleterre'
'Inde'
Devise (valeur)
'Dollar'
'Yen'
'Euro'
'Livre Sterling'
'Roupie'
Les clés et les valeurs Map peuvent contenir n'importent quelle collection, ainsi que des collections imbriquées. Par exemple,
vous pouvez avoir un mappage de nombres entiers avec des mappages, qui à leur tour mappent des chaînes avec des listes. Les
clés Map ne peuvent contenir que quatre niveaux de collections imbriquées.
Pour déclarer un mappage, utilisez le mot clé Map suivi des types de données de la clé et de la valeur entre crochets <>. Par
exemple :
Map<String, String> country_currencies = new Map<String, String>();
Constructions du langage
salesforce | Collections | 48
Map<ID, Set<String>> m = new Map<ID, Set<String>>();
Map<ID, Map<ID, Account[]>> m2 = new Map<ID, Map<ID, Account[]>>();
Vous pouvez utiliser des types de données sObject génériques avec des mappages. Vous pouvez également créer une instance
générique d'un mappage.
Comme avec les listes, vous pouvez renseigner des paires clé-valeur de mappage lors de la déclaration du mappage en utilisant
une syntaxe en accolades ({}). Entre les accolades, spécifiez d'abord la clé, puis la valeur de cette clé en utilisant =>. Par exemple
:
Map<String, String> MyStrings = new Map<String, String>{'a' => 'b', 'c' => 'd'.toUpperCase()};
Account[] accs = new Account[5]; // Account[] is synonymous with List<Account>
Map<Integer, List<Account>> m4 = new Map<Integer, List<Account>>{1 => accs};
Dans le premier exemple, la valeur de la clé a est b, et la valeur de la clé c est d. Dans le deuxième exemple, la clé 1 a la valeur
de la liste accs.
L'exemple ci-dessous présente l'utilisation de sObjects en tant que clés de mappage.
Map<Account, String> mapKeyExample = new Map<Account, String>{
new Account(Name='Account1') => '[email protected]',
new Account(Name='Account2') => '[email protected]'
};
Pour accéder aux éléments d'un mappage, utilisez les méthodes Map fournies par Apex. Par exemple :
Account myAcct = new Account();
//Define a new account
Map<Integer, Account> m = new Map<Integer, Account>(); // Define a new map
m.put(1, myAcct);
// Insert a new key-value pair in the map
System.assert(!m.containsKey(3));
// Assert that the map contains a key
Account a = m.get(1);
Set<Integer> s = m.keySet();
// Retrieve a value, given a particular key
// Return a set that contains all of the keys in the map
Pour plus d'informations, notamment une liste complète de toutes les méthodes Map prises en charge, reportez-vous à Méthodes
Map à la page 420.
Notez les points suivants sur les mappages :
•
•
Contrairement au langage Java, les développeurs Apex n'ont pas besoin de référencer l'algorithme utilisé pour implémenter
un mappage dans leurs déclarations (par exemple, HashMap ou TreeMap). Le langage Apex utilise une structure hash
pour tous les mappages.
Ne vous appuyez pas sur l'ordre dans lequel les résultats de mappage sont renvoyés. L'ordre des objets renvoyés par les
mappages peut changer sans avertissement. Accédez toujours aux éléments de mappage par clé.
Constructions du langage
•
•
•
salesforce | Collections | 49
Une clé de mappage peut inclure la valeur null.
L'ajout d'une entrée de mappage avec cette clé, qui correspond à une clé existante dans le mappage, remplace l'entrée
existante de cette clé avec la nouvelle entrée.
Pour déterminer si les clés de mappage de types définis par l'utilisateur sont uniques, les méthodes equals et hashCode
sont utilisées, que vous fournissez dans vos classes. Pour déterminer si tous les autres types non primitifs sont uniques, les
champs des objets sont comparés.
Mappages de tableaux SObject
Des mappages d'un ID ou d'un type de données String avec un sObject peuvent être initialisés à partir d'une liste de sObjects.
Les ID des objets (qui doivent être non nuls et distincts) sont utilisés en tant que clés. L'une des utilisations courantes de ce
type de mappage concerne les « liaisons » en mémoire entre deux tableaux. Par exemple, l'exemple ci-dessous charge un mappage
d'ID et de contacts :
Map<ID, Contact> m = new Map<ID, Contact>([SELECT Id, LastName FROM Contact]);
Dans l'exemple, la requête SOQL renvoie une liste de contacts avec leur champ Id et LastName. L'opérateur new utilise la
liste pour créer un mappage. Pour plus informations, reportez-vous à Requêtes SOQL et SOSL à la page 77.
Type paramétré
En règle générale, Apex est un langage de programmation typé de façon statique, ce qui signifie que les utilisateurs peuvent
spécifier le type de données d'une variable avant son utilisation. L'exemple ci-dessous est légal dans le langage Apex :
Integer x = 1;
L'exemple ci-dessous n'est pas légal si x n'a pas été au préalable défini :
x = 1;
Les lists, maps et sets (listes, mappages et ensembles) sont paramétrés dans Apex : ils peuvent accepter n'importe quel type de
données que le langage Apex prend en charge en tant qu'argument. Le type de données doit être remplacé par un type de
données existant lors de la construction de la liste, du mappage ou de l'ensemble. Par exemple :
List<String> myList = new List<String>();
Sous-type avec des listes paramétrées
Dans le langage Apex, si le type T est un sous-type de U, List<T> est un sous-type de List<U>. L'exemple ci-dessous est
légal :
List<String> slst = new List<String> {'foo', 'bar'};
List<Object> olst = slst;
Utilisation de types personnalisés dans des clés et ensembles de mappages
Lors de l'utilisation d'un type personnalisé (votre classe Apex) pour les éléments clés de mappage ou ensemble, fournissez les
méthodes equals et hashCode dans votre classe. Le langage Apex utilise ces deux méthodes pour déterminer si les clés de
vos objets sont égales et uniques.
Constructions du langage
salesforce | Collections | 50
Ajout des méthodes equals et hashCode à votre classe
Pour vous assurer que les clés de mappage de votre type personnalisé sont correctement comparées et qu'il est possible de
déterminer de façon cohérente si elles sont uniques, fournissez une implémentation des deux méthodes suivantes dans votre
classe :
La méthode equals avec cette signature :
•
public Boolean equals(Object obj) {
// Your implementation
}
Notez les points suivants lors de l'implémentation de la méthode equals. En supposant que x, y et z sont des instances
non nulles de votre classe, la méthode equals doit être :
Réfléchie : x.equals(x)
Symétrique : x.equals(y) doit renvoyer true si et uniquement si y.equals(x) renvoie true
Transitive : si x.equals(y) renvoie true et y.equals(z) renvoie true, x.equals(z) doit renvoyer true
Cohérente : les invocations multiples de x.equals(y) renvoient toujours true ou renvoient toujours false
Pour toute valeur de référence non nulle x, x.equals(null) doit renvoyer false
◊
◊
◊
◊
◊
La méthode equals dans Apex est basée sur la méthode equals dans Java.
La méthode hashCode avec cette signature :
•
public Integer hashCode() {
// Your implementation
}
Notez les points suivants lors de l'implémentation de la méthode hashCode.
◊ Si la méthode hashCode est invoquée plusieurs fois sur le même objet durant l'exécution d'une requête Apex, elle doit
renvoyer la même valeur.
◊ Si deux objets sont égaux, selon la méthode equals, hashCode doit renvoyer la même valeur.
◊ Si deux objets sont différents, selon les résultats de la méthode equals, il n'est pas nécessaire que hashCode renvoie
des valeurs distinctes.
La méthode hashCode dans Apex est basée sur la méthode hashCode dans Java.
Un autre avantage de la fourniture de la méthode equals dans votre classe est la simplification de la comparaison de vos
objets. Vous pouvez utiliser l'opérateur == pour comparer des objets, ou la méthode equals. Par exemple :
// obj1 and obj2 are instances of MyClass
if (obj1 == obj2) {
// Do something
}
if (obj1.equals(obj2)) {
// Do something
Constructions du langage
salesforce | Collections | 51
}
Exemple
Cet exemple présente l'implémentation des méthodes equals et hashCode. La classe fournie par ces méthodes est répertoriée
en premier. Elle contient également un constructeur qui prend deux nombres entiers. Le deuxième exemple est un extrait de
code qui crée trois objets de la classe, dont deux ont la même valeur. Ensuite, les entrées de mappage sont ajoutées en utilisant
les objets semblables en tant que clés. L'exemple vérifie que le mappage ne contient que deux entrées, car la première entrée
a été remplacée par la dernière entrée ajoutée qui a la même clé. L'exemple utilise ensuite l'opérateur == qui fonctionne comme
prévu, car la classe implémente equals. De plus, quelques opérations de mappage supplémentaires sont effectuées, notamment
pour vérifier si le mappage contient certaines clés, et pour écrire toutes les clés et de toutes les valeurs dans le journal de
débogage. Pour terminer, l'exemple crée un ensemble et lui ajoute les mêmes objets. Il vérifie que la taille de l'ensemble est
égal à deux, car deux objets seulement sur les trois sont uniques.
public class PairNumbers {
Integer x,y;
public PairNumbers(Integer a, Integer b) {
x=a;
y=b;
}
public Boolean equals(Object obj) {
if (obj instanceof PairNumbers) {
PairNumbers p = (PairNumbers)obj;
return ((x==p.x) && (y==p.y));
}
return false;
}
public Integer hashCode() {
return (31 * x) ^ y;
}
}
Cet extrait de code utilise la classe PairNumbers.
Map<PairNumbers, String> m = new Map<PairNumbers, String>();
PairNumbers p1 = new PairNumbers(1,2);
PairNumbers p2 = new PairNumbers(3,4);
Constructions du langage
// Duplicate key
PairNumbers p3 = new PairNumbers(1,2);
m.put(p1, 'first');
m.put(p2, 'second');
m.put(p3, 'third');
// Map size is 2 because the entry with
// the duplicate key overwrote the first entry.
System.assertEquals(2, m.size());
// Use the == operator
if (p1 == p3) {
System.debug('p1 and p3 are equal.');
}
// Perform some other operations
System.assertEquals(true, m.containsKey(p1));
System.assertEquals(true, m.containsKey(p2));
System.assertEquals(false, m.containsKey(new PairNumbers(5,6)));
for(PairNumbers pn : m.keySet()) {
System.debug('Key: ' + pn);
}
List<String> mValues = m.values();
System.debug('m.values: ' + mValues);
// Create a set
Set<PairNumbers> s1 = new Set<PairNumbers>();
s1.add(p1);
s1.add(p2);
s1.add(p3);
salesforce | Collections | 52
Constructions du langage
salesforce | Enumérations | 53
// Verify that we have only two elements
// since the p3 is equal to p1.
System.assertEquals(2, s1.size());
Itération de collections
Les collections peuvent correspondre à des listes, des ensembles ou des mappages. La modification des éléments d'une collection
pendant une itération à travers cette collection n'est pas prise en charge et entraîne une erreur. N'ajoutez pas et ne supprimez
pas directement des éléments pendant une itération à travers une collection qui contient ces éléments.
Ajout d'éléments pendant une itération
Pour ajouter des éléments pendant une itération dans une liste, un ensemble ou un mappage, conservez ces nouveaux éléments
dans une liste, un ensemble ou un mappage temporaire, puis ajoutez-les à l'original une fois l'itération de la collection terminée.
Suppression d'éléments pendant une itération
Pour supprimer des éléments pendant une itération dans une liste, créez une liste, puis copiez les éléments que vous souhaitez
conserver. Vous pouvez également ajouter les éléments que vous souhaitez supprimer à une liste temporaire, puis les supprimer
une fois l'itération de la collection terminée.
Remarque:
La méthode List.remove est exécutée de façon linéaire. Utilisez-la pour supprimer les éléments qui ont des
implications en termes de temps et de ressources.
Pour supprimer des éléments pendant une itération dans un mappage ou un ensemble, conservez les clés que vous souhaitez
supprimer dans une liste temporaire, puis supprimez-les une fois l'itération de la collection terminée.
Enumérations
Une énumération (enum) est un type de données abstrait avec des valeurs dont chacune accepte exactement un ensemble fini
d'identifiants que vous spécifiez. Les énumérations sont généralement utilisées pour définir un ensemble de valeurs possibles
qui n'ont pas d'autre ordre numérique, par exemple une suite de cartes ou une saison particulière de l'année. Bien que chaque
valeur corresponde à une valeur entière distincte, les énumérations masquent cette implémentation afin d'éviter toute utilisation
erronée de ces valeurs, par exemple pour effectuer les opérations arithmétiques. Lorsque vous avez créé une énumération, des
variables, des arguments de méthode et des renvois de type enum peuvent être déclarés.
Remarque: Contrairement à Java, le type enum lui-même n'a pas de syntaxe de constructeur.
Pour définir une enum, utilisez le mot clé enum dans votre déclaration et insérez la liste des valeurs possibles entre accolades.
Par exemple, le code suivant crée une enum appelée Season :
public enum Season {WINTER, SPRING, SUMMER, FALL}
En créant l'énumération Season, vous créez également un type de données appelé Season. Vous pouvez l'utiliser comme
tout autre type de données. Par exemple :
Season e = Season.WINTER;
Constructions du langage
salesforce | Enumérations | 54
Season m(Integer x, Season e) {
If (e == Season.SUMMER) return e;
//...
}
Vous pouvez également définir une classe en tant qu'énumération. Notez que lorsque vous créez une classe enum, vous n'utilisez
pas le mot clé class dans la définition.
public enum MyEnumClass { X, Y }
Vous pouvez utiliser une énumération partout où vous pouvez utiliser un autre nom de type de données. Si vous définissez une
variable dont le type est une énumération, tout objet que vous lui attribuez doit être une instance de cette classe enum.
Toutes les méthodes webService peuvent utiliser des types enum dans leur signature. Dans ce cas, le fichier WSDL associé
inclut les définitions de l'énumération et ses valeurs, qui peuvent ensuite être utilisées par le client API.
Le langage Apex fournit les énumérations définies par le système suivantes :
•
System.StatusCode
Cette énumération correspond au code d'erreur de l'API qui est indiqué dans le document WSDL pour toutes les opérations
de l'API. Par exemple :
StatusCode.CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY
StatusCode.INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY
La liste complète des codes de statut est disponible dans le fichier WSDL de votre organisation. Pour plus d'informations
sur l'accès au fichier WSDL pour votre organisation, reportez-vous à « Téléchargement des certificats d'authentification
client et WSDL de Salesforce » dans l'aide en ligne de Salesforce.
•
System.XmlTag :
Cette énumération renvoie une liste de balises XML utilisées pour analyser le résultat XML à partir d'une méthode
webService. Pour plus d'informations, reportez-vous à Classe XmlStreamReader à la page 658.
•
System.LoggingLevel :
Cette énumération est utilisée avec la méthode system.debug pour spécifier le niveau de consignation de tous les appels
debug. Pour plus d'informations, reportez-vous à Méthodes System à la page 529.
•
System.RoundingMode :
Cette énumération est utilisée par des méthodes qui effectuent des opérations mathématiques pour spécifier le comportement
d'arrondi de l'opérations, telles que la méthode Decimal divide et la méthode Double round. Pour plus d'informations,
reportez-vous à Mode d'arrondi à la page 371.
•
System.SoapType :
Cette énumération est renvoyée par la méthode getSoapType de résultat de description du champ. Pour plus informations,
reportez-vous à Valeurs enum Schema.SOAPType à la page 455.
•
System.DisplayType :
Constructions du langage
salesforce | Compréhension des règles de conversion | 55
Cette énumération est renvoyée par la méthode getType de résultat de description du champ. Pour plus informations,
reportez-vous à Valeurs enum Schema.DisplayType à la page 450.
•
System.JSONToken :
Cette énumération est utilisée pour l'analyse du contenu JSON. Pour plus d'informations, reportez-vous à Enum
System.JSONToken à la page 512.
•
ApexPages.Severity :
Cette énumération spécifie la sévérité d'un message Visualforce. Pour plus d'informations, reportez-vous à Enum
ApexPages.Severity à la page 605.
•
Dom.XmlNodeType :
Cette énumération spécifie le type de noeud d'un document DOM. Pour plus d'informations, reportez-vous à Types de
noeud à la page 670.
Remarque: Les énumérations définies par le système ne peuvent pas être utilisées dans des méthodes de service Web.
Toutes les valeurs d'énumération, y compris les énumérations système, ont des méthodes communes associées. Pour plus
d'informations, reportez-vous à Méthodes Enum à la page 431.
Vous ne pouvez pas ajouter des méthodes définies par les utilisateurs à des valeurs d'énumération.
Compréhension des règles de conversion
Généralement, le langage Apex nécessite de convertir explicitement un type de données vers un autre. par exemple, une variable
du type de données Integer ne peut pas être implicitement converti en String. Vous devez utiliser la méthode string.format.
Cependant, quelques types de données peuvent être implicitement convertis, sans utiliser de méthode.
Les nombres forment une hiérarchie de types. Les variables de types numériques inférieurs peuvent toujours être attribuées à
des types supérieurs sans conversion explicite. La liste suivante est une hiérarchie de nombres, du plus faible au plus élevé :
1.
2.
3.
4.
Integer
Long
Double
Decimal
Remarque: Lorsqu'une valeur a été transmise d'un nombre de type inférieur à un nombre de type supérieur, la valeur
est convertie vers le type supérieur du nombre.
Notez que la hiérarchie et la conversion implicite sont différentes de la hiérarchie de nombres Java, langage dans lequel le
nombre d'interface de base est utilisé et la conversion d'objet implicite n'est jamais autorisée.
Outre les nombres, d'autres types de données peuvent être implicitement convertis. Les règles suivantes s'appliquent :
•
•
•
Les ID peuvent toujours être attribués à des chaînes.
Les chaînes peuvent être attribuées à des ID. Cependant, lors de l'exécution, la légitimité de l'ID de la valeur est vérifiée.
Dans la négative, une exception d'exécution est levée.
Le mot-clé instanceOf peut toujours être utilisé afin de tester si une chaîne est un ID.
Constructions du langage
salesforce | Variables | 56
Considérations supplémentaires sur les types de données
Types de données de valeurs numériques
Les valeurs numériques représentent des valeurs Integer, sauf si L (pour un type Long) ou .0 (pour un type Double ou
Decimal) est ajouté. Par exemple, l'expression Long d = 123; déclare une variable Long nommée d et l'attribue à une
valeur numérique Integer (123), qui est implicitement convertie en type Long. La valeur Integer côté droit est comprise
dans la plage de nombres entiers et l'attribution réussit. Cependant, si la valeur numérique côté droit dépasse la valeur
maximale d'un nombre entier (Integer), vous obtenez une erreur de compilation. Dans ce cas, la solution consiste à ajouter
L à la valeur numérique afin qu'elle représente une valeur Long dont la portée est plus large, comme dans l'exemple
suivant : Long d = 2147483648L;.
Dépassement des valeurs de type de données
Les calculs arithmétiques qui produisent des valeurs supérieures à la valeur maximale du type actuel sont considérés
comme un dépassement. Par exemple, Integer i = 2147483647 + 1; produit une valeur –2147483648, car
2147483647 est la valeur maximale d'un Integer. Par conséquent, l'ajout de 1 arrondit à la valeur négative minimale pour
des nombres entiers, soit –2147483648.
Si les calculs arithmétiques génèrent des résultats supérieurs à la valeur maximale du type actuel, le résultat final est
incorrect, car les valeurs calculées supérieures au maximum génèrent un dépassement. Par exemple, l'expression Long
MillsPerYear = 365 * 24 * 60 * 60 * 1000; génère un résultat incorrect, car le produit des nombres entiers
côté droit est supérieur à la valeur Integer maximale, et ils dépassent. Par conséquent, le produit final n'est pas celui
attendu. Pour l'éviter, assurez-vous que le type des valeurs numériques ou des variables que vous utilisez dans des opérations
arithmétiques est suffisamment grand pour contenir les résultats. Dans cet exemple, ajoutez L aux valeurs numériques
pour les rendre Long afin que les produits intermédiaires soient Long et éviter ainsi tout dépassement. L'exemple
ci-dessous montre comment calculer correctement le nombre de millisecondes dans une année en multipliant des valeurs
numériques Long.
Long MillsPerYear = 365L * 24L * 60L * 60L * 1000L;
Long ExpectedValue = 31536000000L;
System.assertEquals(MillsPerYear, ExpectedValue);
Perte de fractions dans des divisions
Lors de la division de valeurs numériques Integer ou Long, la partie fractionnaire du résultat, le cas échéant, est supprimée
avant toute conversion implicite en Double ou Decimal. Par exemple, Double d = 5/3; renvoie 1.0, car le résultat
(1.666...) est un Integer arrondi à 1 avant d'être implicitement converti en Double. Pour conserver la valeur fractionnaire,
assurez-vous d'utiliser des valeurs numériques Double ou Decimal dans la division. Par exemple, Double d = 5.0/3.0;
renvoie 1.6666666666666667, car 5.0 et 3.0 représentent des valeurs Double, qui génèrent un quotient Double sans
perte de valeur fractionnaire.
Variables
Les variables locales sont déclarées avec une syntaxe de style Java. Par exemple :
Integer i = 0;
String str;
Account a;
Account[] accts;
Constructions du langage
salesforce | Sensibilité à la casse | 57
Set<String> s;
Map<ID, Account> m;
Comme dans Java, les variables multiples peuvent être déclarées et initialisées dans une instruction unique, qui utilise la virgule
comme séparateur. Par exemple :
Integer i, j, k;
Toutes les variables autorisent null en tant que valeur et sont initialisées sur null si elles ne sont pas attribuées à une autre
valeur. Par exemple, dans l'exemple ci-dessous, i et k sont des valeurs attribuées, alors que j est définie sur null, car elle n'est
pas attribuée :
Integer i = 0, j, k = 1;
Les variables peuvent être définies à partir de n'importe quel point d'un bloc, et appliquent la portée à partir de ce point. Les
sous-blocs ne peuvent pas être redéfinis en nom de variable qui a déjà été utilisé dans un bloc parent, mais les blocs parallèles
peuvent réutiliser un nom de variable. Par exemple :
Integer i;
{
// Integer i;
This declaration is not allowed
}
for (Integer j = 0; j < 10; j++);
for (Integer j = 0; j < 10; j++);
Sensibilité à la casse
Pour éviter toute confusion avec les requêtes SOQL et SOSL insensibles à la casse, le code Apex est également insensible à
la casse. Cela signifie :
•
Les noms de variables et de méthodes ne sont pas sensibles à la casse. Par exemple :
Integer I;
//Integer i;
•
This would be an error.
Les références à des noms d'objet et de champ ne sont pas sensibles à la casse. Par exemple :
Account a1;
ACCOUNT a2;
•
Les instructions SOQL et SOSL ne sont pas sensibles à la casse. Par exemple :
Account[] accts = [sELect ID From ACCouNT where nAme = 'fred'];
Constructions du langage
salesforce | Constantes | 58
Notez également que le langage Apex utilise les mêmes sémantiques de filtrage que SOQL, qui représente la base des
comparaisons dans l'API SOAP et dans l'interface utilisateur de Salesforce. L'utilisation de ces sémantiques peut générer des
comportements intéressants. Par exemple, si un utilisateur final génère un rapport basé sur un filtre pour des valeurs précédant
'm' dans l'alphabet (c.-à-d. des valeurs < 'm'), des champs nuls sont renvoyés dans les résultats. Les utilisateurs considèrent
généralement un champ sans valeur comme un caractère « espace », plutôt qu'une valeur « nulle », ce qui justifie ce comportement.
Par conséquent, dans le langage Apex, les expressions suivantes sont toutes évaluées sur true :
String s;
System.assert('a' == 'A');
System.assert(s < 'b');
System.assert(!(s > 'b'));
Remarque: Bien que s < 'b' évalue à true dans l'exemple ci-dessus, 'b.'compareTo(s) génère une erreur, car
vous essayez de comparer une lettre à une valeur nulle.
Constantes
Les constantes peuvent être définies en utilisant le mot clé final, ce qui signifie que la variable peut être attribuée au maximum
une fois, dans la déclaration elle-même ou dans une méthode d'initialisation statique si la constante est définie dans une classe.
Par exemple :
public class myCls {
static final Integer PRIVATE_INT_CONST;
static final Integer PRIVATE_INT_CONST2 = 200;
public static Integer calculate() {
return 2 + 7;
}
static {
PRIVATE_INT_CONST = calculate();
}
}
Pour plus d'informations, reportez-vous à Utilisation du mot clé final à la page 152.
Constructions du langage
salesforce | Expressions | 59
Expressions
Une expression est une construction formée d'invocations de variables, d'opérateurs et de méthodes, qui évalue une valeur
unique. Cette section présente les expressions du langage Apex et inclut les rubriques suivantes :
•
•
•
•
•
Compréhension des expressions
Compréhension des opérateurs d'expression
Compréhension des précédences d'opérateur
Extension d'expressions sObject et List
Utilisation de commentaires
Compréhension des expressions
Une expression est une construction formée d'invocations de variables, d'opérateurs et de méthodes, qui évalue une valeur
unique. Dans le langage Apex, une expression correspond toujours à l'un des types suivants :
•
Une expression littérale. Par exemple :
1 + 1
•
Un sObject, objet Apex, liste, ensemble ou mappage nouveau. Par exemple :
new Account(<field_initializers>)
new Integer[<n>]
new Account[]{<elements>}
new List<Account>()
new Set<String>{}
new Map<String, Integer>()
new myRenamingClass(string oldName, string newName)
•
Toute valeur qui peut agir à gauche d'un opérateur d'attribution (valeurs L), y compris des variables, des positions de listes
unidimensionnelles et la plupart des références de champ sObject ou d'objet Apex. Par exemple :
Integer i
myList[3]
myContact.name
myRenamingClass.oldName
•
Toute référence de champ sObject qui n'est pas une valeur L, y compris :
◊ L'ID d'un sObject dans une liste (reportez-vous à Listes)
◊ Un ensemble d'enregistrements enfants associé à un sObject (par exemple, l'ensemble de contacts associé à un compte
particulier). Ce type d'expression génère un résultat de requête, comme les requêtes SOQL et SOSL.
Constructions du langage
salesforce | Compréhension des opérateurs d'expression | 60
Une requête SOQL ou SOSL entre crochets droits, qui permet une évaluation instantanée dans Apex. Par exemple :
•
Account[] aa = [SELECT Id, Name FROM Account WHERE Name ='Acme'];
Integer i = [SELECT COUNT() FROM Contact WHERE LastName ='Weissman'];
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name),
Contact, Opportunity, Lead];
Pour plus informations, reportez-vous à Requêtes SOQL et SOSL à la page 77.
Une invocation de méthode statique ou d'instance. Par exemple :
•
System.assert(true)
myRenamingClass.replaceNames()
changePoint(new Point(x, y));
Compréhension des opérateurs d'expression
Les expressions peuvent être liées entre elles avec des opérateurs pour créer des expressions composées. Le langage Apex prend
en charge les opérateurs suivants :
Opérateur
Syntaxe
Description
=
x = y
Opérateur d'affectation (associatif à droite). Attribue la valeur de y à la valeur
L de x. Notez que le type de données x doit correspondre au type de données
y, et ne peut pas être null.
+=
x += y
Opérateur d'affectation d'addition (associatif à droite). Ajoute la valeur de
y à la valeur d'origine de x, puis réattribue la nouvelle valeur à x. Pour plus
d'informations, reportez-vous à +. x et y ne peuvent pas être null.
*=
x *= y
Opérateur d'affectation de multiplication (associatif à droite). Multiplie la
valeur de y par la valeur d'origine de x, puis réattribue la nouvelle valeur à x.
Notez que x et y doivent être des Integer ou des Double, ou une combinaison
des deux. x et y ne peuvent pas être null.
-=
x -= y
Opérateur d'affectation de soustraction (associatif à droite). Soustrait la
valeur de y de la valeur d'origine de x, puis réattribue la nouvelle valeur à x.
Notez que x et y doivent être des Integer ou des Double, ou une combinaison
des deux. x et y ne peuvent pas être null.
/=
x /= y
Opérateur d'affectation de division (associatif à droite). Divise la valeur
d'origine de x par la valeur de y, puis réattribue la nouvelle valeur à x. Notez
que x et y doivent être des Integer ou des Double, ou une combinaison des
deux. x et y ne peuvent pas être null.
Constructions du langage
salesforce | Compréhension des opérateurs d'expression | 61
Opérateur
Syntaxe
Description
|=
x |= y
Opérateur d'affectation OR (associatif à droite). Si x, booléen, et y, booléen,
sont tous les deux false, x reste false. Sinon, la valeur true est attribuée à x.
Remarque :
•
•
&=
x &= y
Cet opérateur exhibe un comportement « court-circuit », ce qui signifie
que y est évalué uniquement si x est false.
x et y ne peuvent pas être null.
Opérateur d'affectation AND (associatif à droite). Si x, booléen, et y, booléen,
sont tous les deux true, x reste true. Sinon, la valeur false est attribuée à x.
Remarque :
•
•
Cet opérateur exhibe un comportement « court-circuit », ce qui signifie
que y est évalué uniquement si x est true.
x et y ne peuvent pas être null.
<<=
x <<= y
Opérateur d'affectation décalage gauche au niveau du bit. Décale chaque
bit dans x vers la gauche de y bits, de sorte que les bits de poids fort sont
perdus, et les nouveaux bits droits sont définis sur 0. Cette valeur est ensuite
réattribuée à x.
>>=
x >>= y
Opérateur d'affectation décalage droit au niveau du bit. Décale chaque bit
dans x vers la droite de y bits, de sorte que les bits de poids faible sont perdus,
et les nouveaux bits gauches sont définis sur 0 pour des valeurs positives de y
et sur 1 pour des valeurs négatives de y. Cette valeur est ensuite réattribuée à
x.
>>>=
x >>>= y
Opérateur d'affectation décalage droit non signé au niveau du bit. Décale
chaque bit dans x vers la droite de y bits, de sorte que les bits de poids faible
sont perdus, et les nouveaux bits gauches sont définis sur 0 pour toutes les
valeurs de y. Cette valeur est ensuite réattribuée à x.
? :
x ? y : z
Opérateur ternaire (associatif à droite). Cet opérateur agit en tant que
paramètre abrégé pour les instructions if-then-else. Si x, booléen, est true, y
est le résultat. Sinon, z est le résultat. Notez que x ne peut pas être null.
&&
x && y
Opérateur logique AND (associatif à gauche). Si x, booléen, et y, booléen,
sont tous les deux true, l'expression évalue à true. Sinon, l'expression évalue à
false.
Remarque :
•
•
•
&& est prioritaire sur ||
Cet opérateur exhibe un comportement « court-circuit », ce qui signifie
que y est évalué uniquement si x est true.
x et y ne peuvent pas être null.
Constructions du langage
salesforce | Compréhension des opérateurs d'expression | 62
Opérateur
Syntaxe
Description
||
x || y
Opérateur logique OR (associatif à gauche). Si x, booléen, et y, booléen,
sont tous les deux false, l'expression évalue à false. Sinon, l'expression évalue
à true.
Remarque :
•
•
•
==
x == y
&& est prioritaire sur ||
Cet opérateur exhibe un comportement « court-circuit », ce qui signifie
que y est évalué uniquement si x est false.
x et y ne peuvent pas être null.
Opérateur d'égalité. Si la valeur de x est égale à la valeur de y, l'expression
évalue à true. Sinon, l'expression évalue à false.
Remarque :
•
Contrairement au langage Java, == dans Apex compare l'égalité de la valeur
de l'objet, pas l'égalité de la référence. Par conséquent :
◊ La comparaison de chaînes en utilisant == n'est pas sensible à la casse
◊ La comparaison d'ID en utilisant == est sensible à la casse, et ne fait
pas la distinction entre les formats à 15 caractères et à 18 caractères
•
•
•
•
•
===
x === y
Pour les sObject et les tableaux sObject, == effectue une vérification
approfondie de toutes les valeurs de champ sObject avant de renvoyer son
résultat. De la même façon pour les collections, les types Apex intégrés et
les types définis par l'utilisateur.
Pour des enregistrements, chaque champ doit avoir la même valeur pour
== pour évaluer sur true.
x ou y peuvent être le null littéral.
La comparaison de deux valeurs quelconques ne peut jamais donner null.
SOQL et SOSL utilisent = pour leur opérateur d'égalité, pas ==. Bien que
le langage Apex et SOQL et SOSL soient étroitement liés, cette différence
de syntaxe regrettable existe, car la plupart des langages modernes utilisent
= pour l'affectation et == pour l'égalité. Les concepteurs du langage Apex
ont considéré qu'il était préférable de conserver ce modèle que de forcer
les développeurs à apprendre un nouvel opérateur d'affectation. Par
conséquent, les développeurs Apex doivent utiliser == pour des tests
d'égalité dans le corps principal du code Apex, et = pour l'égalité dans les
requêtes SOQL et SOSL.
Opérateur d'égalité identique. Si x et y référencent un emplacement identique
dans la mémoire, l'expression évalue à true. Sinon, l'expression évalue à false.
Notez que cet opérateur fonctionne uniquement pour les sObjects ou les
collections (telles que mappage ou liste). Pour un objet Apex (tel qu'une
Exception ou l'instanciation d'une classe), l'opérateur d'égalité identique est
le même que l'opérateur d'égalité.
Constructions du langage
salesforce | Compréhension des opérateurs d'expression | 63
Opérateur
Syntaxe
Description
<
x < y
Opérateur inférieur à. Si x est inférieur à y, l'expression évalue à true. Sinon,
l'expression évalue à false.
Remarque :
•
•
•
•
•
•
•
>
x > y
Contrairement à d'autres procédures stockées dans la base de données,
Apex ne prend pas en charge la logique booléenne à trois états, et la
comparaison de deux valeurs quelconques ne peut jamais donner null.
Si x ou y est égal à null et est un Integer, Double, Date ou Datetime,
l'expression est false.
Une valeur String ou ID non null est toujours supérieure à une valeur
null.
Si x et y sont des ID, ils doivent référencer le même type d'objet. Sinon,
une erreur d'exécution est générée.
Si x ou y est un ID et que l'autre valeur est une String, la valeur String est
validée et traitée en tant qu'ID.
x et y ne peuvent pas être booléens.
La comparaison de deux chaînes est effectuée conformément aux
paramètres régionaux de l'utilisateur contextuel.
Opérateur supérieur à. Si x est supérieur à y, l'expression évalue à true. Sinon,
l'expression évalue à false.
Remarque :
•
•
•
•
•
•
•
<=
x <= y
La comparaison de deux valeurs quelconques ne peut jamais donner null.
Si x ou y est égal à null et est un Integer, Double, Date ou Datetime,
l'expression est false.
Une valeur String ou ID non null est toujours supérieure à une valeur
null.
Si x et y sont des ID, ils doivent référencer le même type d'objet. Sinon,
une erreur d'exécution est générée.
Si x ou y est un ID et que l'autre valeur est une String, la valeur String est
validée et traitée en tant qu'ID.
x et y ne peuvent pas être booléens.
La comparaison de deux chaînes est effectuée conformément aux
paramètres régionaux de l'utilisateur contextuel.
Opérateur inférieur ou égal à. Si x est inférieur ou égal à y, l'expression évalue
à true. Sinon, l'expression évalue à false.
Remarque :
•
•
•
La comparaison de deux valeurs quelconques ne peut jamais donner null.
Si x ou y est égal à null et est un Integer, Double, Date ou Datetime,
l'expression est false.
Une valeur String ou ID non null est toujours supérieure à une valeur
null.
Constructions du langage
Opérateur
Syntaxe
salesforce | Compréhension des opérateurs d'expression | 64
Description
•
•
•
•
>=
x >= y
Si x et y sont des ID, ils doivent référencer le même type d'objet. Sinon,
une erreur d'exécution est générée.
Si x ou y est un ID et que l'autre valeur est une String, la valeur String est
validée et traitée en tant qu'ID.
x et y ne peuvent pas être booléens.
La comparaison de deux chaînes est effectuée conformément aux
paramètres régionaux de l'utilisateur contextuel.
Opérateur supérieur ou égal à. Si x est supérieur ou égal à y, l'expression
évalue à true. Sinon, l'expression évalue à false.
Remarque :
•
•
•
•
•
•
•
!=
x != y
La comparaison de deux valeurs quelconques ne peut jamais donner null.
Si x ou y est égal à null et est un Integer, Double, Date ou Datetime,
l'expression est false.
Une valeur String ou ID non null est toujours supérieure à une valeur
null.
Si x et y sont des ID, ils doivent référencer le même type d'objet. Sinon,
une erreur d'exécution est générée.
Si x ou y est un ID et que l'autre valeur est une String, la valeur String est
validée et traitée en tant qu'ID.
x et y ne peuvent pas être booléens.
La comparaison de deux chaînes est effectuée conformément aux
paramètres régionaux de l'utilisateur contextuel.
Opérateur d'inégalité. Si la valeur de x est différente de la valeur de y,
l'expression évalue à true. Sinon, l'expression évalue à false.
Remarque :
•
•
•
•
•
!==
x !== y
Contrairement au langage Java, != dans Apex compare l'égalité de la valeur
de l'objet, pas l'égalité de la référence.
Pour les sObject et les tableaux sObject, != effectue une vérification
approfondie de toutes les valeurs de champ sObject avant de renvoyer son
résultat.
Pour des enregistrements, != évalue à true si les enregistrements ont des
valeurs différentes pour un champ quelconque.
x ou y peuvent être le null littéral.
La comparaison de deux valeurs quelconques ne peut jamais donner null.
Opérateur d'inégalité identique. Si x et y ne référencent pas un emplacement
identique dans la mémoire, l'expression évalue à true. Sinon, l'expression évalue
à false. Notez que cet opérateur fonctionne uniquement pour des sObjects,
des collections (telles que le mappage ou liste) ou un objet Apex (tel qu'une
Exception ou l'instanciation d'une classe).
Constructions du langage
salesforce | Compréhension des opérateurs d'expression | 65
Opérateur
Syntaxe
Description
+
x + y
Opérateur d'addition. Ajoute la valeur de x à la valeur de y en fonction des
règles suivantes :
• Si x et y sont des Integer ou des Double, il ajoute la valeur de x à la valeur
de y. Si un Double est utilisé, le résultat est un Double.
• Si x est une Date et y un Integer, il renvoie une nouvelle Date qui est
incrémentée par le nombre de jours spécifié.
• Si x est une Datetime et y est un Integer ou un Double, il renvoie une
nouvelle Date qui est incrémentée par le nombre de jours spécifié, avec la
partie fractionnaire correspondant à une partie du jour.
• Si x est une String et y est une String et n'importe quel autre type
d'argument non null, il concatène y à la fin de x.
-
x - y
Opérateur de soustraction. Soustrait la valeur de y de la valeur de x en
fonction des règles suivantes :
• Si x et y sont des Integer ou des Double, il soustrait la valeur de x de la
valeur de y. Si un Double est utilisé, le résultat est un Double.
• Si x est une Date et y un Integer, il renvoie une nouvelle Date qui est
décrémentée par le nombre de jours spécifié.
• Si x est une Datetime et y est un Integer ou un Double, il renvoie une
nouvelle Date qui est décrémentée par le nombre de jours spécifié, avec la
partie fractionnaire correspondant à une partie du jour.
*
x * y
Opérateur de multiplication. Multiplie x, un Integer ou un Double, avec y,
un autre Integer ou Double. Notez que si un double est utilisé, le résultat est
un Double.
/
x / y
Opérateur de division. Divise x, un Integer ou un Double, par y, un autre
Integer ou Double. Notez que si un double est utilisé, le résultat est un Double.
!
!x
Opérateur de complément logique. Il inverse la valeur d'un booléen, de sorte
que true devient false, et false devient true.
-
-x
Opérateur de négation unaire. Multiplie la valeur de x, un Integer ou un
Double, par -1. Notez que l'équivalent positif + est également valide en termes
de syntaxe, mais n'a aucun effet mathématique.
++
x++
Opérateur d'incrément. Ajoute 1 à la valeur de x, une variable de type
numérique. Si elle a un préfixe (++x), l'expression évalue à la valeur de x après
l'incrément. Si elle a un suffixe (x++), l'expression évalue à la valeur de x avant
l'incrément.
++x
--
x---x
&
x & y
Opérateur de décrément. Soustrait 1 de la valeur de x, une variable de type
numérique. Si elle a un préfixe (--x), l'expression évalue à la valeur de x après
le décrément. Si elle a un suffixe (x--), l'expression évalue à la valeur de x
avant le décrément.
Opérateur AND au niveau du bit. Associe avec des AND chaque bit dans x
au bit correspondant dans y de sorte que le bit résultat est défini sur 1 si les
Constructions du langage
Opérateur
salesforce | Compréhension des précédences d'opérateur | 66
Syntaxe
Description
deux bits sont définis sur 1. Cet opérateur n'est pas valide pour les types Long
ou Integer.
|
x | y
Opérateur OR au niveau du bit. Associe avec des OR chaque bit dans x au
bit correspondant dans y de sorte que le bit résultat est défini sur 1 si un bit
au moins est défini sur 1. Cet opérateur n'est pas valide pour les types Long
ou Integer.
^
x ^ y
Opérateur OR exclusif au niveau du bit. Associe avec des OR exclusifs chaque
bit dans x au bit correspondant dans y de sorte que le bit résultat est défini
sur 1 si exactement un bit est défini sur 1 et l'autre bit est défini sur 0.
^=
x ^= y
Opérateur OR exclusif au niveau du bit. Associe avec des OR exclusifs chaque
bit dans x au bit correspondant dans y de sorte que le bit résultat est défini
sur 1 si exactement un bit est défini sur 1 et l'autre bit est défini sur 0.
<<
x << y
Opérateur de décalage gauche au niveau du bit. Décale chaque bit dans x
vers la gauche de y bits, de sorte que les bits de poids fort sont perdus, et les
nouveaux bits droits sont définis sur 0.
>>
x >> y
Opérateur de décalage droit signé au niveau du bit. Décale chaque bit dans
x vers la droite de y bits, de sorte que les bits de poids faible sont perdus, et
les nouveaux bits gauches sont définis sur 0 pour des valeurs positives de y et
sur 1 pour des valeurs négatives de y.
>>>
x >>> y
Opérateur de décalage droit non signé au niveau du bit. Décale chaque bit
dans x vers la droite de y bits, de sorte que les bits de poids faible sont perdus,
et les nouveaux bits gauches sont définis sur 0 pour toutes les valeurs de y.
()
(x)
Parenthèses. Élève la priorité d'une expression x de sorte qu'elle est évaluée
en premier dans une expression composée.
Compréhension des précédences d'opérateur
Le langage Apex utilisez les règles précédences d'opérateur suivantes :
Précédence
Opérateurs
Description
1
{} () ++ --
Regroupement, et incréments et décréments de
préfixe
2
! -x +x (type) new
Négation unaire, conversion du type et création
d'objet
3
* /
Multiplication et division
4
+ -
Addition et soustraction
5
< <= > >= instanceof
Comparaisons supérieur à et inférieur à, tests de
référence
Constructions du langage
salesforce | Extension d'expressions sObject et List | 67
Précédence
Opérateurs
Description
6
== !=
Comparaisons : égal à et différent de
7
&&
AND logique
8
||
OR logique
9
= += -= *= /= &=
Opérateurs d'affectation
Extension d'expressions sObject et List
Comme dans le langage Java, les expressions sObject et List peuvent être étendues avec respectivement des références de
méthode et des expressions de liste pour former de nouvelles expressions.
Dans l'exemple suivant, une nouvelle variable contenant la longueur du nom du nouveau compte est attribuée à
acctNameLength.
Integer acctNameLength = new Account[]{new Account(Name='Acme')}[0].Name.length();
Ci-dessus, new Account[] génère une liste.
La liste est renseignée par l'instruction SOQL {new Account(name='Acme')}.
L'élément 0, le premier de la liste, est ensuite accédé par la partie suivante de la chaîne [0].
Le nom du sObject dans la liste est accédé, suivi par la méthode renvoyant la longueur name.length().
Dans l'exemple suivant, un nom changé en lettres minuscules est renvoyé.
String nameChange = [SELECT Name FROM Account][0].Name.toLowerCase();
Utilisation de commentaires
Les commentaires à une et à plusieurs lignes sont prises en charge dans le code Apex :
•
Pour créer un commentaire sur une ligne, utilisez //. Tous les caractères sur la même ligne à droite de // sont ignorés par
l'analyseur. Par exemple :
Integer i = 1; // This comment is ignored by the parser
•
Pour créer un commentaire sur plusieurs lignes, utilisez /* et */ pour marquer le début et la fin du bloc de commentaires.
Par exemple :
Integer i = 1; /* This comment can wrap over multiple
lines without getting interpreted by the
parser. */
Constructions du langage
salesforce | Instructions d'attribution | 68
Instructions d'attribution
Une instruction d'attribution place une valeur dans une variable, généralement sous l'un des deux formats suivants :
[LValue] = [new_value_expression];
[LValue] = [[inline_soql_query]];
Dans les formats ci-dessus, [LValue] représente une expression qui peut être placée à gauche d'un opérateur d'affectation.
Elles comprennent :
•
Une simple variable. Par exemple :
Integer i = 1;
Account a = new Account();
Account[] accts = [SELECT Id FROM Account];
•
Un élément de liste déréférencé : Par exemple :
ints[0] = 1;
accts[0].Name = 'Acme';
•
Une référence de champ sObject que l'utilisateur contextuel est autorisé à modifier. Par exemple :
Account a = new Account(Name = 'Acme', BillingCity = 'San Francisco');
// IDs cannot be set prior to an insert call
// a.Id = '00300000003T2PGAA0';
// Instead, insert the record. The system automatically assigns it an ID.
insert a;
// Fields also must be writeable for the context user
// a.CreatedDate = System.today();
This code is invalid because
//
createdDate is read-only!
// Since the account a has been inserted, it is now possible to
// create a new contact that is related to it
Contact c = new Contact(LastName = 'Roth', Account = a);
Constructions du langage
salesforce | Instructions conditionnelles (If-Else) | 69
// Notice that you can write to the account name directly through the contact
c.Account.Name = 'salesforce.com';
L'attribution est toujours effectuée par référence. Par exemple :
Account a = new Account();
Account b;
Account[] c = new Account[]{};
a.Name = 'Acme';
b = a;
c.add(a);
// These asserts should now be true. You can reference the data
// originally allocated to account a through account b and account list c.
System.assertEquals(b.Name, 'Acme');
System.assertEquals(c[0].Name, 'Acme');
De la même façon, deux listes peuvent pointer vers la même valeur dans la mémoire. Par exemple :
Account[] a = new Account[]{new Account()};
Account[] b = a;
a[0].Name = 'Acme';
System.assert(b[0].Name == 'Acme');
En plus de =, les autres opérateurs d'affectation incluent +=, *=, /=, |=, &=, ++ et --. Reportez-vous à Compréhension des
opérateurs d'expression à la page 60.
Instructions conditionnelles (If-Else)
L'instruction conditionnelle dans Apex fonctionne de façon similaire à Java :
if ([Boolean_condition])
// Statement 1
else
// Statement 2
La partie else est toujours facultative, et toujours groupée avec le if le plus proche. Par exemple :
Integer x, sign;
Constructions du langage
// Your code
if (x <= 0) if (x == 0) sign = 0; else sign = -1;
est équivalent à :
Integer x, sign;
// Your code
if (x <= 0) {
if (x == 0) {
sign = 0;
} else
{
sign = -1;
}
}
Les instructions else if répétées sont également autorisées. Par exemple :
if (place == 1) {
medal_color = 'gold';
} else if (place == 2) {
medal_color = 'silver';
} else if (place == 3) {
medal_color = 'bronze';
} else {
medal_color = null;
}
Boucles
Le langage Apex prend en charge les types de boucle procédurale suivants :
•
•
•
•
•
do {statement} while (Boolean_condition);
while (Boolean_condition) statement;
for (initialization; Boolean_exit_condition; increment) statement;
for (variable : array_or_set) statement;
for (variable : [inline_soql_query]) statement;
Toutes les boucles autorisent les structures de contrôle de boucles :
salesforce | Boucles | 70
Constructions du langage
salesforce | Boucles Do-While | 71
break; existe dans la boucle entière
•
•
continue; passe à l'itération suivante de la boucle
Boucles Do-While
La boucle do-while du langage Apex exécute à répétition un bloc de code tant qu'une condition booléenne particulière reste
vraie. Sa syntaxe est la suivante :
do {
code_block
} while (condition);
Remarque: Des Accolades ({}) sont toujours requises autour d'un code_block.
Comme dans Java, la boucle Apex do-while vérifie l'instruction de condition booléenne après l'exécution de la première
boucle. Par conséquent, le bloc de code est toujours exécuté au moins une fois.
Par exemple, le code suivant sort les chiffres de 1 à 10 dans le journal de débogage :
Integer count = 1;
do {
System.debug(count);
count++;
} while (count < 11);
Boucles While
La boucle while du langage Apex exécute à répétition un bloc de code tant qu'une condition booléenne particulière reste
vraie. Sa syntaxe est la suivante :
while (condition) {
code_block
}
Remarque: Des accolades ({}) sont requises autour d'un code_block uniquement si le bloc contient plusieurs
instructions.
Contrairement à la boucle do-while, la boucle while vérifie l'instruction de condition booléenne avant l'exécution de la
première boucle. Par conséquent, il est possible que le bloc de code ne soit jamais exécuté.
Constructions du langage
salesforce | Boucles For | 72
Par exemple, le code suivant sort les chiffres de 1 à 10 dans le journal de débogage :
Integer count = 1;
while (count < 11) {
System.debug(count);
count++;
}
Boucles For
Le langage Apex prend en charge trois variantes de la boucle for :
•
La boucle traditionnelle for :
for (init_stmt; exit_condition; increment_stmt) {
code_block
}
•
La boucle for d'itération de liste ou d'ensemble :
for (variable : list_or_set) {
code_block
}
où variable doit avoir un type primitif ou sObject identique à celui de list_or_set.
•
La boucle for SOQL :
for (variable : [soql_query]) {
code_block
}
ou
for (variable_list : [soql_query]) {
code_block
}
où variable et variable_list doivent avoir un type sObject identique à celui renvoyé par la requête soql_query.
Remarque: Des accolades ({}) sont requises autour d'un code_block uniquement si le bloc contient plusieurs
instructions.
Constructions du langage
salesforce | Boucles For | 73
Chaque type est présenté dans les sections suivantes.
Boucles For traditionnelles
La boucle traditionnelle for dans Apex correspond à la syntaxe traditionnelle utilisée dans Java et d'autres langages. Sa syntaxe
est la suivante :
for (init_stmt; exit_condition; increment_stmt) {
code_block
}
Lors de l'exécution de ce type de boucle for, le moteur d'exécution Apex exécute les étapes suivantes, dans l'ordre :
1. Exécution du composant init_stmt de la boucle. Notez que plusieurs variantes peuvent être déclarées et/ou initialisées
dans cette instruction.
2. Exécution de la vérification exit_condition. Si true, la boucle continue. Si false, la boucle s'arrête.
3. Exécution du code_block.
4. Exécution de l'instruction increment_stmt.
5. Retour à l'étape 2.
Par exemple, le code suivant sort les chiffres de 1 à 10 dans le journal de débogage. Notez qu'une variable d'initialisation
supplémentaire, j, est incluse pour démontrer la syntaxe :
for (Integer i = 0, j = 0; i < 10; i++) {
System.debug(i+1);
}
Boucles For d'itération de List ou de Set
La boucle for d'itération de list ou de set est répétée sur tous les éléments d'une liste ou d'un ensemble. Sa syntaxe est la
suivante :
for (variable : list_or_set) {
code_block
}
où variable doit avoir un type primitif ou sObject identique à celui de list_or_set.
Lors de l'exécution de ce type de boucle for, le moteur d'exécution Apex attribue une variable à chaque élément dans
list_or_set, puis exécute le code_block pour chaque valeur.
Par exemple, le code suivant sort les chiffres de 1 à 10 dans le journal de débogage :
Integer[] myInts = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (Integer i : myInts) {
Constructions du langage
salesforce | Boucles For | 74
System.debug(i);
}
Boucles For SOQL
Les boucles for SOQL sont répétées sur tous les enregistrements sObject renvoyés par une requête SOQL. La syntaxe d'une
boucle for SOQL est :
for (variable : [soql_query]) {
code_block
}
ou
for (variable_list : [soql_query]) {
code_block
}
où variable et variable_list doivent être du même type que les sObjects renvoyés par la requête soql_query. Comme
dans les requêtes SOQL standard, l'instruction [soql_query] peut référencer des expressions de code dans leur clause WHERE
en utilisant la syntaxe :. Par exemple :
String s = 'Acme';
for (Account a : [SELECT Id, Name from Account
where Name LIKE :(s+'%')]) {
// Your code
}
L'exemple suivant combine la création d'une liste à partir d'une requête SOQL avec la méthode DML update.
// Create a list of account records from a SOQL query
List<Account> accs = [SELECT Id, Name FROM Account WHERE Name = 'Siebel'];
// Loop through the list and update the Name field
for(Account a : accs){
a.Name = 'Oracle';
}
// Update the database
update accs;
Constructions du langage
salesforce | Boucles For | 75
Boucles For SOQL et requêtes SOQL standard
Les boucles for SOQL diffèrent des instructions SOQL standard par la méthode qu'elles utilisent pour récupérer les sObjects.
Alors que les requêtes standard présentées dans Requêtes SOQL et SOSL peuvent récupérer le count d'une requête ou un
nombre d'enregistrements d'objets, les boucles for SOQL récupèrent tous les sObjects, en utilisant une segmentation efficace
avec des appels aux méthodes query et queryMore de l'API SOAP. Les développeurs doivent toujours utiliser une boucle
for SOQL pour traiter les résultats de requête qui renvoient de nombreux enregistrements, afin d'éviter les limites en taille
de segment mémoire.
Notez que les requêtes qui incluent une fonction aggregate ne prennent pas en charge queryMore. Une exception d'exécution
est levée si vous utilisez une requête contenant une fonction aggregate qui renvoie plus de 2000 lignes dans une boucle for.
Format des boucles For SOQL
Les boucles for SOQL peuvent traiter des enregistrements individuels en utilisant une variable sObject unique, ou par lots
de 200 sObjects à la fois en utilisant une liste sObject :
Le format sObject unique exécute le <code_block> de la boucle for une fois par enregistrement sObject. Il est par
conséquent facile à comprendre et à utiliser, mais très inefficace si vous souhaitez utiliser des instructions DML (langage
de manipulation de données) dans le corps de la boucle for. Chaque instruction DML traite finalement un seul sObject
à la fois.
Le format de liste sObject exécute le <code_block> de la boucle for une fois par liste de 200 sObjects. Par conséquent,
il est plus difficile à comprendre et à utiliser, mais représente le format idéal pour utiliser des instructions DML dans le
corps de la boucle for. Chaque instruction DML peut traiter en masse une liste de sObjects à la fois.
•
•
Par exemple, le code suivant illustre la différence entre les deux types de boucle for de requête SOQL :
// Create a savepoint because the data should not be committed to the database
Savepoint sp = Database.setSavepoint();
insert new Account[]{new Account(Name = 'yyy'),
new Account(Name = 'yyy'),
new Account(Name = 'yyy')};
// The single sObject format executes the for loop once per returned record
Integer i = 0;
for (Account tmp : [SELECT Id FROM Account WHERE Name = 'yyy']) {
i++;
}
System.assert(i == 3); // Since there were three accounts named 'yyy' in the
// database, the loop executed three times
// The sObject list format executes the for loop once per returned batch
// of records
Constructions du langage
salesforce | Boucles For | 76
i = 0;
Integer j;
for (Account[] tmp : [SELECT Id FROM Account WHERE Name = 'yyy']) {
j = tmp.size();
i++;
}
System.assert(j == 3); // The list should have contained the three accounts
// named 'yyy'
System.assert(i == 1); // Since a single batch can hold up to 100 records and,
// only three records should have been returned, the
// loop should have executed only once
// Revert the database to the original state
Database.rollback(sp);
Remarque:
•
•
•
Les mots clés break et continue peuvent être utilisés dans les deux types de format de boucle for des requêtes
en ligne. Lors de l'utilisation du format de liste sObject, continue passe à la liste suivante de sObjects.
Les instructions DML peuvent traiter uniquement 10 000 enregistrements à la fois, et les boucles for de liste
sObject traitent les enregistrements par lots de 200. Par conséquent, si vous insérez, mettez à jour ou supprimez
plusieurs enregistrements dans les enregistrements renvoyés dans une boucle for de liste sObject, vous pouvez
rencontrer des erreurs de limite lors de l'exécution. Reportez-vous à Compréhension des limitations et des
gouverneurs d'exécution à la page 273.
Vous pouvez obtenir une exception QueryException dans une boucle for SOQL avec le message Aggregate
query has too many rows for direct assignment, use FOR loop. Cette exception est parfois
générée en accédant à un vaste ensemble d'enregistrements enfants d'un sObject récupéré dans la boucle, ou en
obtenant la taille d'un tel ensemble d'enregistrements. Pour éviter cette exception, utilisez une boucle for pour
itérer sur les enregistrements enfants, comme suit :
Integer count=0;
for (Contact c : returnedAccount.Contacts) {
count++;
// Do some other processing
}
Constructions du langage
salesforce | Requêtes SOQL et SOSL | 77
Requêtes SOQL et SOSL
Vous pouvez évaluer sur le champ les instructions SOQL (Object Query Language) de Salesforce ou SOSL (Object Search
Language) de Salesforce dans le langage Apex en les plaçant entre crochets droits.
Instructions SOQL
Les instructions SOQL évaluent une liste de sObjects, un sObject unique ou un Integer pour les requêtes de méthode count.
Par exemple, vous pouvez récupérer une liste de comptes nommés Acme :
List<Account> aa = [SELECT Id, Name FROM Account WHERE Name = 'Acme'];
Dans cette liste, vous pouvez accéder à des éléments individuels :
if (!aa.isEmpty()) {
// Execute commands
}
Vous pouvez également créer des objets à partir des requêtes SOQL dans les objets existants. L'exemple suivant crée un contact
à partir du premier compte avec un nombre d'employés supérieur à 10 :
Contact c = new Contact(Account = [SELECT Name FROM Account
WHERE NumberOfEmployees > 10 LIMIT 1]);
c.FirstName = 'James';
c.LastName = 'Yoyce';
Notez que l'objet créé contient des valeurs nulles pour ses champs, qui doivent être définies.
La méthode count peut être utilisée pour envoyer le nombre de lignes retournées par une requête. L'exemple suivant renvoie
le nombre total de contacts qui incluent le nom Weissman :
Integer i = [SELECT COUNT() FROM Contact WHERE LastName = 'Weissman'];
Vous pouvez également effectuer des opérations sur les résultats à l'aide d'arithmétique standard :
Integer j = 5 * [SELECT COUNT() FROM Account];
Pour une description complète de la syntaxe de la requête SOQL, reportez-vous au guide Salesforce SOQL and SOSL Reference
Guide.
Instructions SOSL
Les instructions SOSL évaluent à une liste de listes de sObjects, dans laquelle chaque liste contient les résultats de la recherche
d'un type sObject particulier. Les listes de résultats sont toujours renvoyées dans le même ordre, telles que spécifiées dans la
requête SOSL. Si une requête SOSL ne renvoie aucun enregistrement pour un type sObject spécifié, les résultats de recherche
incluent une liste vide pour cet sObject.
Constructions du langage
salesforce | Utilisation des résultats de requêtes SOQL et
SOSL | 78
Par exemple, vous pouvez renvoyer une liste de comptes, de contacts, d'opportunités et de pistes qui commencent par le
mappage de phrases :
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name),
Contact, Opportunity, Lead];
Remarque:
La syntaxe de la clause FIND dans Apex diffère de la syntaxe de la clause FIND dans l'API SOAP :
•
Dans Apex, la valeur de la clause FIND est comprise entre apostrophes. Par exemple :
FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead
•
Dans l'API Force.com, la valeur de la clause FIND est comprise entre accolades. Par exemple :
FIND {map*} IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead
Dans searchList, vous pouvez créer des tableaux pour chaque objet renvoyé :
Account [] accounts = ((List<Account>)searchList[0]);
Contact [] contacts = ((List<Contact>)searchList[1]);
Opportunity [] opportunities = ((List<Opportunity>)searchList[2]);
Lead [] leads = ((List<Lead>)searchList[3]);
Pour une description complète de la syntaxe de la requête SOSL, reportez-vous au guide Salesforce SOQL and SOSL Reference
Guide.
Utilisation des résultats de requêtes SOQL et SOSL
Les requêtes SOQL et SOSL renvoi des données uniquement pour les champs sObject sélectionnés dans la requête d'origine.
Si vous essayez d'accéder à un champ qui n'a pas été sélectionné dans la requête SOQL ou SOSL (autre qu'un ID), vous recevez
une erreur d'exécution, même si le champ contient une valeur dans la base de données. L'exemple de code suivant génère une
erreur d'exécution :
insert new Account(Name = 'Singha');
Account acc = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1];
// Note that name is not selected
String name = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1].Name;
L'exemple suivant est le même code réécrit afin de ne pas produire l'erreur d'exécution. Notez que Name a été ajouté à l'instruction
select, après Id.
insert new Account(Name = 'Singha');
Account acc = [SELECT Id FROM Account WHERE Name = 'Singha' LIMIT 1];
// Note that name is now selected
Constructions du langage
salesforce | Utilisation de fonctions Aggregate SOQL | 79
String name = [SELECT Id, Name FROM Account WHERE Name = 'Singha' LIMIT 1].Name;
Même si un seul champ sObject est sélectionné, une requête SOQL ou SOSL renvoie toujours les données sous la forme
d'enregistrements complets. Par conséquent, vous devez déréférencer le champ pour pouvoir y accéder. Par exemple, le code
ci-dessous récupère une liste de sObject dans la base de données avec une requête SOQL, accède au premier enregistrement
de compte de la liste, puis déréférence le champ AnnualRevenue de l'enregistrement :
Double rev = [SELECT AnnualRevenue FROM Account
WHERE Name = 'Acme'][0].AnnualRevenue;
// When only one result is returned in a SOQL query, it is not necessary
// to include the list's index.
Double rev2 = [SELECT AnnualRevenue FROM Account
WHERE Name = 'Acme' LIMIT 1].AnnualRevenue;
Il n'est pas nécessaire de déréférencer un champ sObject dans le résultat d'une requête SOQL uniquement lorsque la requête
renvoie un Integer suite à une opération COUNT :
Integer i = [SELECT COUNT() FROM Account];
Les champs dans les enregistrements renvoyés par des requêtes SOSL doivent toujours être déréférencés.
Notez également que les champs sObject qui contiennent des formules renvoient la valeur du champ lors de l'émission de la
requête SOQL ou SOSL. Toute modification apportée à d'autres champs utilisés dans la formule s'applique à la valeur du
champ de formule uniquement après la sauvegarde de l'enregistrement et une nouvelle requête créée pour cet enregistrement
dans Apex. Comme d'autres champs sObject en lecture seule, les valeurs des champs de formule ne sont pas modifiables dans
Apex.
Utilisation de fonctions Aggregate SOQL
Les fonctions aggregate dans SOQL, telles que SUM() et MAX(), permettent de regrouper et de récapituler vos données dans
une requête. Pour plus d'informations sur les fonctions aggregate, reportez-vous à « Aggregate Functions » dans le guide
Salesforce SOQL and SOSL Reference Guide.
Vous pouvez utiliser des fonctions aggregate sans utiliser de clause GROUP BY. Par exemple vous pouvez utiliser la fonction
aggregate AVG() pour rechercher le montant (Amount) moyen de toutes les opportunités.
AggregateResult[] groupedResults
= [SELECT AVG(Amount)aver FROM Opportunity];
Object avgAmount = groupedResults[0].get('aver');
Notez que toute requête qui inclut une fonction aggregate renvoie ses résultats dans un tableau d'objets AggregateResult.
AggregateResult est un sObject en lecture seule, utilisé uniquement pour des résultats de requête.
Constructions du langage
salesforce | Utilisation de très grandes requêtes SOQL | 80
Les fonctions aggregate forment un outil plus puissant pour générer des rapports lorsque vous les utilisez avec une clause GROUP
BY. Par exemple, vous pouvez rechercher le Amount moyen de toutes vos opportunités par campagne.
AggregateResult[] groupedResults
= [SELECT CampaignId, AVG(Amount)
FROM Opportunity
GROUP BY CampaignId];
for (AggregateResult ar : groupedResults)
{
System.debug('Campaign ID' + ar.get('CampaignId'));
System.debug('Average amount' + ar.get('expr0'));
}
Tout champ agrégé dans une liste SELECT qui n'a pas d'alias obtient automatiquement un alias implicite avec un format expri,
où i indique l'ordre des champs agrégés sans alias explicite. La valeur de i commence à 0 et est incrémentée pour chaque
champ agrégé sans alias explicite. Pour plus d'informations, reportez-vous à « Using Aliases with GROUP BY » dans le guide
Salesforce SOQL and SOSL Reference Guide.
Remarque: Les requêtes qui incluent des fonctions aggregate sont soumises aux mêmes limitations du gouverneur
que les autres requêtes SOQL concernant le nombre total d'enregistrements renvoyés. Cette limite inclut tous les
enregistrements que contient l'agrégation, pas seulement le nombre de lignes renvoyées par la requête. Si vous atteignez
cette limite, ajoutez une condition à la clause WHERE pour réduire le nombre d'enregistrements traités par la requête.
Utilisation de très grandes requêtes SOQL
Votre requête SOQL peut renvoyer de nombreux sObjects qui dépassent la limite de la taille de segment mémoire et génèrent
une erreur. Pour la résoudre, utilisez une boucle for de requête SOQL, qui peut traiter plusieurs lots d'enregistrements en
utilisant des appels internes à query et à queryMore.
Par exemple, si les résultats sont trop grands, la syntaxe ci-dessous peut entraîner une exception d'exécution.
Account[] accts = [SELECT Id FROM Account];
À la place, utilisez une boucle for de requête SOQL dans l'un des exemples ci-dessous :
// Use this format if you are not executing DML statements
// within the for loop
for (Account a : [SELECT Id, Name FROM Account
WHERE Name LIKE 'Acme%']) {
// Your code without DML statements here
}
// Use this format for efficiency if you are executing DML statements
Constructions du langage
salesforce | Utilisation de très grandes requêtes SOQL | 81
// within the for loop
for (List<Account> accts : [SELECT Id, Name FROM Account
WHERE Name LIKE 'Acme%']) {
// Your code here
update accts;
}
L'exemple suivant montre une boucle for de requête SOQL utilisée pour mettre à jour en masse les enregistrements. Supposons
que vous souhaitez modifier le nom de contact dans tous les enregistrements de contact dont le nom et le prénom correspondent
à un critère spécifique :
public void massUpdate() {
for (List<Contact> contacts:
[SELECT FirstName, LastName FROM Contact]) {
for(Contact c : contacts) {
if (c.FirstName == 'Barbara' &&
c.LastName == 'Gordon') {
c.LastName = 'Wayne';
}
}
update contacts;
}
}
Au lieu d'utiliser une requête SOQL dans une boucle for, la méthode recommandée de mise à jour en masse des enregistrements
consiste à utiliser Apex par lot, qui réduit les risques d'atteindre les limitations du gouverneur.
Pour plus informations, reportez-vous à Boucles For SOQL à la page 74.
Requêtes SOQL plus efficaces
Pour de meilleures performances, les requêtes SOQL doivent être sélectives, notamment pour les requêtes dans des déclencheurs.
Pour éviter les délais d'exécution importants, les requêtes SOQL non sélectives peuvent être terminées par le système. Les
développeurs reçoivent un message d'erreur lorsqu'une requête non sélective dans un déclencheur est exécutée sur un objet qui
contient plus de 100 000 enregistrements. Pour éviter cette erreur, assurez-vous d'utiliser une requête sélective.
Critères de requête SOQL sélective
•
•
Une requête est sélective lorsque l'un des filtres de requête se trouve dans un champ indexé et que le filtre de requête
maintient le nombre de lignes généré sous le seuil défini par le système. Les performances de la requête SOQL
augmentent lorsque deux filtres ou plus utilisés dans la clause WHERE remplissent les conditions spécifiées.
Le seuil de sélectivité est de 10 % des enregistrements pour le premier million d'enregistrements, et moins de 5 %
des enregistrements à compter du premier million d'enregistrements, jusqu'à un maximum de 333 000 enregistrements.
Constructions du langage
salesforce | Utilisation de très grandes requêtes SOQL | 82
Dans certains cas, par exemple lorsqu'un filtre de requête se trouve dans un champ standard indexé, le seuil peut être
plus élevé. En outre, le seuil de sélectivité peut être modifié.
Considérations sur les index personnalisés pour des requêtes SOQL sélectives
•
•
•
•
•
Les champs suivants sont indexés par défaut : clés primaires (champs ID, Nom et Propriétaire), clés étrangères
(champs de référence ou de relation principal-details), dates d'audit (telles que LastModifiedDate) et champs
personnalisés marqués en tant qu'ID externe ou Unique.
Les champs non indexés par défaut peuvent être automatiquement indexés ultérieurement si l'optimiseur Salesforce
détermine qu'un index peut améliorer les performances des requêtes fréquemment exécutées.
Le support Salesforce.com peut ajouter des index personnalisés aux requêtes pour les clients.
Il n'est pas possible de créer un index personnalisé dans les types de champ suivants : listes de sélection multiple,
champs de devise dans une organisation multidevises, champs de texte longs, certains champs de formule et champs
binaires (champs de type blob, fichier ou texte crypté). Notez que de nouveaux types de données, généralement
complexes, peuvent être ajoutés à Salesforce et leurs champs peuvent ne pas autoriser l'indexation personnalisée.
Généralement, un index personnalisé n'est pas utilisé dans les cas suivants :
◊ La ou les valeurs demandées dépassent le seuil défini par le système évoqué plus haut.
◊ L'opérateur de filtrage est un opérateur négatif, tel que NOT EQUAL TO (ou !=), NOT CONTAINS et NOT STARTS
WITH.
◊ L'opérateur CONTAINS est utilisé dans le filtre et le nombre de lignes à scanner dépasse 333 000, car l'opérateur
CONTAINS nécessite un scan complet de l'index. Notez que ce seuil peut être modifié.
◊ Lors d'une comparaison avec une valeur vide (Name != '').
Cependant, il existe d'autres scénarios complexes dans lesquels les index personnalisés ne sont pas utilisés. Si votre
cas n'est pas mentionné ici ou si vous souhaitez obtenir une aide supplémentaire sur les requêtes non sélectives,
contactez votre représentant salesforce.com.
Exemples de requêtes SOQL sélectives
Pour mieux comprendre si une requête sur un objet volumineux est sélective ou non, analysons quelques requêtes. Pour
ces requêtes, supposons qu'il existe 100 000 enregistrements (qui comprennent les enregistrements supprimés
provisoirement, c.-à-d. présents dans la Corbeille) pour le sObject Account.
Requête 1 :
SELECT Id FROM Account WHERE Id IN (<list of account IDs>)
La clause WHERE se trouve dans un champ indexé (ID). Si SELECT COUNT() FROM Account WHERE Id IN (<list
of account IDs>) renvoie un nombre d'enregistrements inférieur au seuil de sélectivité, l'index dans ID est utilisé.
Ce cas est le plus fréquent, car la liste d'ID contient une faible quantité d'enregistrements.
Requête 2 :
SELECT Id FROM Account WHERE Name != ''
Puisque Account est un objet volumineux, même si Name est indexé (clé primaire), ce filtre renvoie la plupart des
enregistrements, rendant la requête non sélective.
Requête 3 :
SELECT Id FROM Account WHERE Name != '' AND CustomField__c = 'ValueA'
Constructions du langage
salesforce | Utilisation de requêtes SOQL renvoyant un
enregistrement | 83
Ici nous devons déterminer si chaque filtre, considéré individuellement, est sélectif. Comme nous l'avons vu dans l'exemple
précédent, le premier filtre n'est pas sélectif. Examinons le deuxième. Si le nombre d'enregistrements renvoyé par SELECT
COUNT() FROM Account WHERE CustomField__c = 'ValueA' est inférieur au seuil de sélectivité, et que
CustomField__c est indexé, la requête est sélective.
Utilisation de requêtes SOQL renvoyant un enregistrement
Des requêtes SOQL peuvent être utilisées pour attribuer une valeur sObject unique lorsque la liste de résultats contient un
seul élément. Lorsque la valeur L d'une expression est un type sObject unique, Apex attribue automatiquement l'enregistrement
sObject unique dans la liste des résultats de requêtes à la valeur L. Une exception d'exécution est levée si aucun sObject ou
plusieurs sObjects sont détectés dans la liste. Par exemple :
List<Account> accts = [SELECT Id FROM Account];
// These lines of code are only valid if one row is returned from
// the query. Notice that the second line dereferences the field from the
// query without assigning it to an intermediary sObject variable.
Account acct = [SELECT Id FROM Account];
String name = [SELECT Name FROM Account].Name;
Amélioration des performances en annulant la recherche des valeurs nulles
Dans vos requêtes SOQL et SOSL, évitez de rechercher les enregistrements qui contiennent des valeurs nulles. Commencez
par exclure ces valeurs afin d'améliorer les performances. Dans l'exemple suivant, tous les enregistrements dont la valeur
treadID est Null sont exclus des valeurs renvoyées.
Public class TagWS {
/* getThreadTags
*
* a quick method to pull tags not in the existing list
*
*/
public static webservice List<String>
getThreadTags(String threadId, List<String> tags) {
system.debug(LoggingLevel.Debug,tags);
List<String> retVals = new List<String>();
Set<String> tagSet = new Set<String>();
Constructions du langage
salesforce | Compréhension des requêtes SOQL de clé
étrangère et de relations parent-enfant | 84
Set<String> origTagSet = new Set<String>();
origTagSet.addAll(tags);
// Note WHERE clause verifies that threadId is not null
for(CSO_CaseThread_Tag__c t :
[SELECT Name FROM CSO_CaseThread_Tag__c
WHERE Thread__c = :threadId AND
WHERE threadID != null])
{
tagSet.add(t.Name);
}
for(String x : origTagSet) {
// return a minus version of it so the UI knows to clear it
if(!tagSet.contains(x)) retVals.add('-' + x);
}
for(String x : tagSet) {
// return a plus version so the UI knows it's new
if(!origTagSet.contains(x)) retvals.add('+' + x);
}
return retVals;
}
Compréhension des requêtes SOQL de clé étrangère et de relations parent-enfant
L'instruction SELECT d'une requête SOQL peut correspondre à n'importe quelle instruction SOQL valide, y compris des
liaisons de clé étrangère et d'enregistrements parent-enfant. Si des liaisons de clé étrangère sont incluses, les sObjects qui en
résultent peuvent être référencés en utilisant une notation de champ normale. Par exemple :
System.debug([SELECT Account.Name FROM Contact
WHERE FirstName = 'Caroline'].Account.Name);
Constructions du langage
salesforce | Utilisation de relations polymorphiques dans des
requêtes SOQL | 85
De plus, les relations parent-enfant dans les sObjects agissent aussi comme des requêtes SOQL. Par exemple :
for (Account a : [SELECT Id, Name, (SELECT LastName FROM Contacts)
FROM Account
WHERE Name = 'Acme']) {
Contact[] cons = a.Contacts;
}
//The following example also works because we limit to only 1 contact
for (Account a : [SELECT Id, Name, (SELECT LastName FROM Contacts LIMIT 1)
FROM Account
WHERE Name = 'testAgg']) {
Contact c = a.Contacts;
}
Utilisation de relations polymorphiques dans des requêtes SOQL
Une relation polymorphique est une relation entre des objets, dans laquelle les objets référencés peuvent avoir plusieurs types
différents. Par exemple, le champ de relation What d'un Événement peut être un Compte, une Campagne ou une Opportunité.
Cette section présente l'utilisation de requêtes SOQL avec des relations polymorphiques dans le langage Apex. Pour plus
d'informations générales sur les relations polymorphiques, reportez-vous à Understanding Polymorphic Keys and Relationships
dans le guide Force.com SOQL and SOSL Reference.
Vous pouvez utiliser des requêtes SOQL qui référencent des champs polymorphiques dans le langage Apex, pour obtenir des
résultats qui dépendent du type d'objet référencé par le champ polymorphique. Une approche consiste à filtrer vos résultats en
utilisant le qualificateur Type. Cet exemple demande les événements (Events) qui sont associés à un compte (Account) ou
une opportunité (Opportunity) via le champ What.
List<Event> = [SELECT Description FROM Event WHERE What.Type IN ('Account', 'Opportunity')];
Une autre approche consiste à utiliser la clause TYPEOF dans l'instruction SOQL SELECT. Cet exemple demande également
les événements (Events) qui sont associés à un compte (Account) ou une opportunité (Opportunity) via le champ What.
List<Event> = [SELECT TYPEOF What WHEN Account THEN Phone WHEN Opportunity THEN Amount END
FROM Event];
Remarque: Actuellement, TYPEOF est disponible en tant qu'aperçu du développeur dans la fonctionnalité
Polymorphisme SOQL. Pour plus d'informations sur l'activation de TYPEOF pour votre organisation, contactez
salesforce.com.
Ces requêtes renvoient une liste de sObjects dont le champ de relation référence les types d'objet souhaités.
Constructions du langage
salesforce | Utilisation de relations polymorphiques dans des
requêtes SOQL | 86
Pour accéder à l'objet référencé dans une relation polymorphique, vous pouvez utiliser le mot clé instanceof afin de déterminer
le type d'objet. L'exemple suivant utilise instanceof pour déterminer si un Account ou une Opportunity est associé à un
Event.
Event myEvent = eventFromQuery;
if (myEvent.What instanceof Account) {
// myEvent.What references an Account, so process accordingly
} else if (myEvent.What instanceof Opportunity) {
// myEvent.What references an Opportunity, so process accordingly
}
Notez que vous devez attribuer le sObject référencé, que la requête renvoie, à une variable du type approprié avant de la
transmettre à une autre méthode. L'exemple suivant demande l'utilisateur ou groupe propriétaire des objets personnalisés
Merchandise__c en utilisant une requête SOQL avec une clause TYPEOF, utilise instanceof pour déterminer le type de
propriétaire, puis attribue les objets du propriétaire à des variables de type User ou Group avant de les transmettre à des
méthodes de marchandises.
public class PolymorphismExampleClass {
// Utility method for a User
public static void processUser(User theUser) {
System.debug('Processed User');
}
// Utility method for a Group
public static void processGroup(Group theGroup) {
System.debug('Processed Group');
}
public static void processOwnersOfMerchandise() {
// Select records based on the Owner polymorphic relationship field
List<Merchandise__c> merchandiseList = [SELECT TYPEOF Owner WHEN User THEN LastName
WHEN Group THEN Email END FROM Merchandise__c];
// We now have a list of Merchandise__c records owned by either a User or Group
for (Merchandise__c merch: merchandiseList) {
// We can use instanceof to check the polymorphic relationship type
// Note that we have to assign the polymorphic reference to the appropriate
// sObject type before passing to a method
Constructions du langage
salesforce | Utilisation de variables Apex dans des requêtes
SOQL et SOSL | 87
if (merch.Owner instanceof User) {
User userOwner = merch.Owner;
processUser(userOwner);
} else if (merch.Owner instanceof Group) {
Group groupOwner = merch.Owner;
processGroup(groupOwner);
}
}
}
}
Utilisation de variables Apex dans des requêtes SOQL et SOSL
Dans le langage Apex, les instructions SOQL et SOSL peuvent référencer des variables et des expressions de code Apex si
elles sont précédées de deux points (:). Cette utilisation de variable de code local dans une instruction SOQL ou SOSL est
appelée liaison. L'analyseur Apex commence par évaluer la variable locale dans le contexte du code avant d'exécuter l'instruction
SOQL ou SOSL. Les expressions de liaison peuvent être utilisées en tant que :
•
•
•
•
•
•
Chaîne de recherche dans des clauses FIND.
Littéraux de filtrage dans des clauses WHERE.
Valeur de l'opérateur IN ou NOT IN dans des clauses WHERE, permettant le filtrage dans un ensemble de valeurs dynamique.
Notez que cette utilisation est spécifique à une liste d'ID ou de String, bien qu'elle fonctionne avec des listes de n'importe
quel type.
Noms de division dans des clauses WITH DIVISION.
Valeur numérique dans des clauses LIMIT.
Valeur numérique dans des clauses OFFSET.
L'expression de liaison ne peuvent pas être utilisées avec d'autres clauses, telles que INCLUDES.
Par exemple :
Account A = new Account(Name='xxx');
insert A;
Account B;
// A simple bind
B = [SELECT Id FROM Account WHERE Id = :A.Id];
// A bind with arithmetic
B = [SELECT Id FROM Account
Constructions du langage
salesforce | Utilisation de variables Apex dans des requêtes
SOQL et SOSL | 88
WHERE Name = :('x' + 'xx')];
String s = 'XXX';
// A bind with expressions
B = [SELECT Id FROM Account
WHERE Name = :'XXXX'.substring(0,3)];
// A bind with an expression that is itself a query result
B = [SELECT Id FROM Account
WHERE Name = :[SELECT Name FROM Account
WHERE Id = :A.Id].Name];
Contact C = new Contact(LastName='xxx', AccountId=A.Id);
insert new Contact[]{C, new Contact(LastName='yyy',
accountId=A.id)};
// Binds in both the parent and aggregate queries
B = [SELECT Id, (SELECT Id FROM Contacts
WHERE Id = :C.Id)
FROM Account
WHERE Id = :A.Id];
// One contact returned
Contact D = B.Contacts;
// A limit bind
Integer i = 1;
B = [SELECT Id FROM Account LIMIT :i];
// An OFFSET bind
Integer offsetVal = 10;
List<Account> offsetList = [SELECT Id FROM Account OFFSET :offsetVal];
Constructions du langage
salesforce | Utilisation de variables Apex dans des requêtes
SOQL et SOSL | 89
// An IN-bind with an Id list. Note that a list of sObjects
// can also be used--the Ids of the objects are used for
// the bind
Contact[] cc = [SELECT Id FROM Contact LIMIT 2];
Task[] tt = [SELECT Id FROM Task WHERE WhoId IN :cc];
// An IN-bind with a String list
String[] ss = new String[]{'a', 'b'};
Account[] aa = [SELECT Id FROM Account
WHERE AccountNumber IN :ss];
// A SOSL query with binds in all possible clauses
String myString1 = 'aaa';
String myString2 = 'bbb';
Integer myInt3 = 11;
String myString4 = 'ccc';
Integer myInt5 = 22;
List<List<SObject>> searchList = [FIND :myString1 IN ALL FIELDS
RETURNING
Account (Id, Name WHERE Name LIKE :myString2
LIMIT :myInt3),
Contact,
Opportunity,
Lead
WITH DIVISION =:myString4
LIMIT :myInt5];
Constructions du langage
salesforce | Demande de tous les enregistrements avec une
instruction SOQL | 90
Demande de tous les enregistrements avec une instruction SOQL
Les instructions SOQL peuvent utiliser les mots clés ALL ROWS pour interroger tous les enregistrements dans une organisation,
y compris les enregistrements supprimés et les activités archivées. Par exemple :
System.assertEquals(2, [SELECT COUNT() FROM Contact WHERE AccountId = a.Id ALL ROWS]);
Vous pouvez utiliser ALL ROWS pour interroger des enregistrements dans la Corbeille de votre organisation. Vous ne pouvez
pas utiliser les mots clés ALL ROWS avec les mots clés FOR UPDATE.
Instructions de verrouillage
Apex permet aux développeurs de verrouiller des enregistrements sObject pendant leur mise à jour afin d'éviter les conditions
« race » et d'autres menaces de sécurité. Lorsqu'un enregistrement sObject est verrouillé, aucun autre programme ni utilisateur
n'est autorisé à effectuer des mises à jour.
Pour verrouiller un ensemble d'enregistrements sObject dans le langage Apex, incorporez les mots clés FOR UPDATE après
n'importe quelle instruction SOQL en ligne. Par exemple, l'instruction suivante, en plus d'interroger deux comptes, verrouille
également les comptes qui sont renvoyés :
Account [] accts = [SELECT Id FROM Account LIMIT 2 FOR UPDATE];
Remarque: Vous ne pouvez pas utiliser les mots clés ORDER BY dans une requête SOQL qui utilise le verrouillage.
Lorsque les comptes sont verrouillés par cet appel, les instructions DML (langage de manipulation de données) peuvent
modifier leur valeurs de champ dans la base de données dans la transaction.
ATTENTION: Définissez avec prudence des verrous dans votre code Apex. Reportez-vous à Éviter les impasses,
ci-dessous.
Verrouillage d'une boucle For SOQL
Les mots clés FOR UPDATE peuvent également être utilisés dans des boucles SOQL for. Par exemple :
for (Account[] accts : [SELECT Id FROM Account
FOR UPDATE]) {
// Your code
}
Comme indiqué dans Boucles For SOQL, l'exemple ci-dessus correspond en interne à des appels aux méthodes query() et
queryMore() dans l'API SOAP.
Constructions du langage
salesforce | Éviter les impasses | 91
Notez qui n'existe aucune instruction commit. Si votre déclencheur Apex réussit, toute modification apportée à la base de
données s'applique automatiquement. Si votre déclencheur Apex échoue, les modifications apportées à la base de données sont
annulées.
Éviter les impasses
Notez que le langage Apex peut conduire à des impasses, comme tout autre langage logique de procédural qui nécessite la mise
à jour de multiples tableaux ou lignes de base de données. Pour éviter ces impasses, le moteur d'exécution Apex commence
par verrouiller les enregistrements parent sObject, puis les enfants.
En tant que développeur, soyez prudent(e) en verrouillant des lignes pour vous assurer qu'elles créent pas d'impasses. Pour
éviter les impasses, utilisez les techniques de contournement standard en accédant aux tableaux et aux lignes dans le même
ordre à partir de n'importe quel emplacement dans l'application.
Contrôle des transactions
Toutes les requêtes sont délimitées par le déclencheur, une méthode de classe, un service Web, une page Visualforce ou un
bloc anonyme qui exécute le code Apex. Si la requête complète réussit, toutes les modifications sont appliquées dans la base
de données. Par exemple, supposons qu'une page Visualforce a appelé un contrôleur Apex, qui à son tour a appelé une classe
Apex supplémentaire. Les modifications sont appliquées dans la base de données lorsque tout le code Apex et la page Visualforce
ont été exécutés. Si la requête échoue, toutes les modifications apportées à la base de données sont annulées.
Cependant, durant le traitement des enregistrements, il arrive parfois que vos règles métier nécessitent l'annulation d'un travail
partiel (instructions DML déjà exécutées) afin de poursuivre le traitement dans une autre direction. Le langage Apex permet
de générer un point d'enregistrement, c.-à-d. un point dans la requête qui précise l'état actuel de la base de données. Toute
instruction DML qui se produit après le point d'enregistrement peut être abandonnée et les conditions de la base de données
préalables à la génération du point d'enregistrement peuvent être restaurées.
Les limitations suivantes s'appliquent à la génération des variables du point d'enregistrement et à la restauration de la base de
données :
•
•
•
•
•
•
Si vous définissez plusieurs points d'enregistrement, puis restaurez un point d'enregistrement qui ne correspond pas au
dernier point d'enregistrement généré, les variables des points d'enregistrement ultérieurs ne sont plus valides. Par exemple,
si vous générez un premier point d'enregistrement SP1, puis un deuxième point d'enregistrement SP2, et que vous restaurez
vers le point d'enregistrement SP1, la variable SP2 n'est plus valide. Vous recevez une erreur d'exécution lorsque vous
essayez de l'utiliser.
Les références à des points d'enregistrements ne peuvent pas croiser des invocations de déclencheur, car chaque invocation
de déclencheur correspond à un nouveau contexte d'exécution. Si vous déclarez un point d'enregistrement en tant que
variable statique, puis essayez de l'utiliser à travers des contextes de déclencheur, vous obtenez une erreur d'exécution.
Chaque point d'enregistrement que vous définissez est prise en compte dans les limitations du gouverneur pour les instructions
DML.
Les variables statiques ne sont pas restaurées lors d'une annulation. Si vous essayez de réexécuter le déclencheur, les variables
statiques conservent les valeurs de la première exécution.
Chaque annulation est prise en compte dans les limitations du gouverneur pour les instructions DML. Vous obtenez une
erreur d'exécution si vous essayez de restaurer la base de données un nombre de fois excessif.
L'ID dans un sObject inséré après la définition d'un point enregistrement n'est pas effacé après une annulation. Créez un
nouveau sObject à insérer après une annulation. Une tentative d'insertion du sObject en utilisant la même variable créée
avant l'annulation échoue, car la variable du sObject inclut un ID. La mise à jour ou la mise à jour/insertion du sObject en
Constructions du langage
salesforce | Instructions d'exception | 92
utilisant la même variable échoue également, car le sObject ne figure pas dans la base de données et, par conséquent, ne
peut pas être mis à jour.
L'exemple suivant utilise les méthodes Database setSavepoint et rollback.
Account a = new Account(Name = 'xxx'); insert a;
System.assertEquals(null, [SELECT AccountNumber FROM Account WHERE Id = :a.Id].
AccountNumber);
// Create a savepoint while AccountNumber is null
Savepoint sp = Database.setSavepoint();
// Change the account number
a.AccountNumber = '123';
update a;
System.assertEquals('123', [SELECT AccountNumber FROM Account WHERE Id = :a.Id].
AccountNumber);
// Rollback to the previous null value
Database.rollback(sp);
System.assertEquals(null, [SELECT AccountNumber FROM Account WHERE Id = :a.Id].
AccountNumber);
Instructions d'exception
Le langage Apex utilise des exceptions pour consigner des erreurs et d'autres événements qui gênent l'exécution normale du
code. Des instructions throw peuvent être utilisées pour générer des exceptions, et try, catch et finally permettent
d'effectuer une restauration sans heurt suite à une exception.
Vous pouvez également créer vos propres exceptions en utilisant la classe Exception. Pour plus d'informations, reportez-vous
à Classe Exception à la page 585.
Instructions Throw
Une instruction throw permet de signaler une erreur qui s'est produite. Pour signaler une exception, utilisez l'instruction
throw en lui ajoutant un objet d'exception pour fournir des informations sur l'erreur spécifique. Par exemple :
throw exceptionObject;
Constructions du langage
salesforce | Instructions Try-Catch-Finally | 93
Instructions Try-Catch-Finally
Les instructions try, catch et finally peuvent être utilisées pour restaurer sans heurt suite au signalement d'une exception
:
L'instruction try identifie un bloc de code dans lequel une exception peut se produire.
L'instruction catch identifie un bloc de code qui peut traiter un type particulier d'exception. Une instruction try unique
peut être associé à plusieurs instructions catch. Cependant, chaque instruction catch doit avoir un type d'exception
unique.
L'instruction facultative finally identifie un bloc de code dont l'exécution est garantie et permet de nettoyer le code
inclus dans le bloc try. Une instruction try unique peut être associée à une instruction finally.
•
•
•
Syntaxe
La syntaxe de ces instructions est la suivante :
try {
code_block
} catch (exceptionType) {
code_block
}
// Optional catch statements for other exception types.
// Note that the general exception type, 'Exception',
// must be the last catch block when it is used.
} catch (Exception e) {
code_block
}
// Optional finally statement
} finally {
code_block
}
Exemple
Par exemple :
try {
// Your code here
} catch (ListException e) {
// List Exception handling code here
Constructions du langage
salesforce | Instructions Try-Catch-Finally | 94
} catch (Exception e) {
// Generic exception handling code here
}
Remarque: Les exceptions de limitation générées par un gouverneur d'exécution ne peuvent pas être détectées.
Reportez-vous à Compréhension des limitations et des gouverneurs d'exécution à la page 273.
Chapitre 3
Invocation de code Apex
Sujets :
•
•
•
•
Déclencheurs
Planificateur Apex
Blocs anonymes
Apex dans AJAX
Vous pouvez invoquer votre code Apex à l'aide de plusieurs mécanismes. Vous
pouvez écrire un déclencheur Apex et invoquer le code de votre déclencheur pour
les événements qu'il spécifie, avant ou après une opération donnée pour un type
sObject spécifique. Vous pouvez également écrire une classe Apex et planifier
son exécution à intervalles prédéfinis, ou exécuter des extraits de code dans un
bloc anonyme. Pour terminer, vous pouvez utiliser les outils Ajax pour invoquer
des méthodes de services Web mises en oeuvre dans Apex.
Ce chapitre inclut les sections suivantes :
•
•
•
•
Déclencheurs
Planificateur Apex (pour les classes Apex uniquement)
Blocs anonymes
Outils AJAX
Invocation de code Apex
salesforce | Déclencheurs | 96
Déclencheurs
Un code Apex peut être invoqué en utilisant des déclencheurs. Un déclencheur est un code Apex qui est exécuté avant ou après
les types d'opération suivants :
•
•
•
•
•
•
insérer
mettre à jour
supprimer
fusionner
mettre à jour/insérer
annuler la suppression
Par exemple, un déclencheur peut être exécuté avant l'insertion d'enregistrements d'un objet dans la base de données, après la
suppression d'enregistrements ou même après la restauration d'un enregistrement à partir de la Corbeille.
Vous pouvez définir des déclencheurs pour n'importe quel objet standard de niveau supérieur, tel que Contact ou Compte,
pas pour des objets standard enfant, tels que Rôle du contact.
•
•
Pour des commentaires de requête, cliquez sur Votre nom > Configuration > Personnaliser > Requêtes > Commentaires
sur la requête > Déclencheurs.
Pour des e-mails, cliquez sur Votre nom > Configuration > Personnaliser > Requêtes > E-mails > Déclencheurs.
Il existe deux types de déclencheur :
•
•
Les déclencheurs Before peuvent être utilisés pour mettre à jour ou valider des valeurs d'enregistrement avant leur
enregistrement dans la base de données.
Les déclencheurs After peuvent être utilisés pour accéder à des valeurs de champ définies par la base de données (par exemple
le champ Id ou lastUpdated d'un enregistrement), et pour affecter les modifications dans d'autres enregistrements, par
exemple la consignation dans un tableau d'audit ou le déclenchement d'événements asynchrones avec une file d'attente.
Les déclencheurs peuvent également modifier d'autres enregistrements du même type que ceux qui ont initialement activé le
déclencheur. Par exemple, si un déclencheur est activé après une mise à jour du contact A, il peut également modifier les contacts
B, C et D. Puisque les déclencheurs peuvent entraîner la modification d'autres enregistrements, et que ces modifications peuvent
activer d'autres déclencheurs, le moteur d'exécution Apex considère toutes ces opérations comme une seule unité de travail et
limite les opérations qui peuvent être exécutées afin d'empêcher une récursion infinie. Reportez-vous à Compréhension des
limitations et des gouverneurs d'exécution à la page 273.
De plus, si vous mettez à jour ou supprimez un enregistrement dans son déclencheur Before, ou supprimez un enregistrement
dans son déclencheur After, vous obtenez erreur d'exécution. Cela inclut les opérations directes et indirectes. Par exemple, si
vous mettez à jour le compte A, et que le déclencheur before update du compte A insère le contact B, et le déclencheur after
insert du contact B interroge le compte A et le met à jour en utilisant l'instruction DML update ou la méthode database, vous
mettez indirectement à jour le compte A dans son déclencheur before, et vous obtenez une erreur d'exécution.
Considérations sur la mise en oeuvre
Avant de créer des déclencheurs, tenez compte des points suivants :
•
•
Les déclencheurs upsert sont activés avant et après les déclencheurs insert ou avant et après les déclencheurs update
selon les cas.
Les déclencheurs merge sont activés avant et après les déclencheurs delete pour les enregistrements perdus et les
déclencheurs before update pour l'enregistrement gagnant uniquement. Reportez-vous à Déclencheurs et instructions
Merge à la page 106.
Invocation de code Apex
salesforce | Déclencheurs en masse | 97
Les déclencheurs exécutés après l'annulation de la suppression d'un enregistrement fonctionnent uniquement avec des
objets spécifiques. Reportez-vous à Déclencheurs et enregistrements restaurés à la page 107.
Historique des champs n'est pas enregistré avant la fin d'un déclencheur. Si vous interrogez l'historique des champs dans
un déclencheur, aucun historique ne correspond à la transaction actuelle.
Pour un code Apex enregistré en utilisant l'API version 20.0 ou antérieure de Salesforce.com, si un appel API active un
déclencheur, le lot de 200 enregistrements à traiter est divisé en lots de 100 enregistrements. Pour un code Apex enregistré
en utilisant l'API versions 21.0 et supérieures de Salesforce.com, les lots d'API ne sont pas divisés. Notez que les valeurs
de variable statique sont réinitialisées entre les lots, contrairement aux limitations du gouverneur. N'utilisez pas des variables
statiques pour suivre les informations d'état entre les lots.
•
•
•
Déclencheurs en masse
Tous des déclencheurs sont par défaut des déclencheurs en masse qui peuvent traiter plusieurs enregistrements à la fois. Vous
devez toujours planifier le traitement de plusieurs enregistrements à la fois.
Remarque: Un objet Event défini comme récurrent n'est pas traité en masse pour les déclencheurs insert, delete
ou update.
Les déclencheurs en masse peuvent traiter des mises à jour d'enregistrements uniques et des opérations en masse telles que :
Importation de données
Appels API en masse Force.com
Actions en masse, telles que des modifications et des suppressions de propriétaires d'enregistrement
Méthodes et déclencheurs Apex récursifs qui invoquent des traitements DML en masse
•
•
•
•
Syntaxe de déclencheur
Pour définir un déclencheur, utilisez la syntaxe suivante :
trigger triggerName on ObjectName (trigger_events) {
code_block
}
où trigger_events peut être une liste de valeurs séparées par une virgule comportant un ou plusieurs des événements suivants
:
•
•
•
•
•
•
•
before insert
before update
before delete
after insert
after update
after delete
after undelete
Remarque:
•
Vous pouvez utiliser le mot clé webService uniquement dans un déclencheur au sein d'une méthode définie
comme asynchrone, c.-à-d. définie avec le mot clé @future.
Invocation de code Apex
•
salesforce | Variables de contexte de déclencheur | 98
Un déclencheur appelé par une action insert, delete ou update pour une tâche ou un événement récurrent
entraîne une erreur d'exécution si le déclencheur est appelé en masse à partir de l'API Force.com.
Par exemple, le code suivant définit un déclencheur pour les événements before insert et before update dans l'objet
Account :
trigger myAccountTrigger on Account (before insert, before update) {
// Your code here
}
Le bloc de code d'un déclencheur ne peut pas contenir le mot clé static. Les déclencheurs peuvent contenir uniquement
des mots clés applicables à une classe interne. De plus, il n'est pas nécessaire d'appliquer manuellement les modifications de
base de données effectuées par un déclencheur. Si votre déclencheur Apex réussit, toute modification apportée à la base de
données s'applique automatiquement. Si votre déclencheur Apex échoue, les modifications apportées à la base de données sont
annulées.
Variables de contexte de déclencheur
Tous les déclencheurs définissent des variables implicites qui permettent aux développeurs d'accéder au contexte d'exécution.
Ces variables sont contenues dans la classe System.Trigger :
Variable
Utilisation
isExecuting
Renvoie true si le contexte actuel du code Apex est un déclencheur, pas une page Visualforce,
un service Web ou un appel d'API executeanonymous().
isInsert
Renvoie true si ce déclencheur a été activé suite à une opération insert, à partir de l'interface
utilisateur de Salesforce, un code Apex ou l'API.
isUpdate
Renvoie true si ce déclencheur a été activé suite à une opération update, à partir de l'interface
utilisateur de Salesforce, un code Apex ou l'API.
isDelete
Renvoie true si ce déclencheur a été activé suite à une opération delete, à partir de l'interface
utilisateur de Salesforce, un code Apex ou l'API.
isBefore
Renvoie true si ce déclencheur a été activé avant la sauvegarde d'un enregistrement.
isAfter
Renvoie true si ce déclencheur a été activé après la sauvegarde de tous les enregistrements.
isUndelete
Renvoie true si ce déclencheur a été activé après la restauration de l'enregistrement à partir
de la Corbeille (c.-à-d. après une opération undelete à partir de l'interface utilisateur de
Salesforce, un code Apex ou l'API).
new
Renvoie une liste de toutes les nouvelles versions des enregistrements sObject.
Notez que cette liste de sObject est disponible uniquement dans les déclencheurs insert et
update, et que les enregistrements peuvent être modifiés uniquement dans les déclencheurs
before.
Invocation de code Apex
salesforce | Variables de contexte de déclencheur | 99
Variable
Utilisation
newMap
Un mappage d'ID avec les nouvelles versions des enregistrements sObject.
Notez que ce mappage est disponible uniquement dans les déclencheurs before update,
after insert et after update.
Renvoie une liste des anciennes versions des enregistrements sObject.
old
Notez que cette liste de sObject est disponible uniquement dans les déclencheurs update et
delete.
oldMap
Un mappage d'ID avec les anciennes versions des enregistrements sObject.
Notez que ce mappage est disponible uniquement dans les déclencheurs update et delete.
Le nombre total d'enregistrements dans une invocation de déclencheur, anciens et nouveaux.
size
Remarque: Si un enregistrement qui active un déclencheur inclut une valeur de champ non valide (par exemple une
formule qui divise par zéro), cette valeur est définie sur null dans les variables de contexte de déclencheur new,
newMap, old et oldMap.
Par exemple, dans ce simple déclencheur, Trigger.new est une liste de sObjects et peut être répétée dans une boucle for,
ou utilisée en tant que variable de liaison dans la clause IN d'une requête SOQL :
Trigger t on Account (after insert) {
for (Account a : Trigger.new) {
// Iterate over each sObject
}
// This single query finds every contact that is associated with any of the
// triggering accounts. Note that although Trigger.new is a collection of
// records, when used as a bind variable in a SOQL query, Apex automatically
// transforms the list of records into a list of corresponding Ids.
Contact[] cons = [SELECT LastName FROM Contact
WHERE AccountId IN :Trigger.new];
}
Ce déclencheur utilise les variables de contexte booléennes Trigger.isBefore et Trigger.isDelete pour définir un
code qui s'exécute uniquement dans des conditions de déclencheurs spécifiques :
trigger myAccountTrigger on Account(before delete, before insert, before update,
after delete, after insert, after update) {
if (Trigger.isBefore) {
Invocation de code Apex
salesforce | Variables de contexte de déclencheur | 100
if (Trigger.isDelete) {
// In a before delete trigger, the trigger accesses the records that will be
// deleted with the Trigger.old list.
for (Account a : Trigger.old) {
if (a.name != 'okToDelete') {
a.addError('You can\'t delete this record!');
}
}
} else {
// In before insert or before update triggers, the trigger accesses the new records
// with the Trigger.new list.
for (Account a : Trigger.new) {
if (a.name == 'bad') {
a.name.addError('Bad name');
}
}
if (Trigger.isInsert) {
for (Account a : Trigger.new) {
System.assertEquals('xxx', a.accountNumber);
System.assertEquals('industry', a.industry);
System.assertEquals(100, a.numberofemployees);
System.assertEquals(100.0, a.annualrevenue);
a.accountNumber = 'yyy';
}
// If the trigger is not a before trigger, it must be an after trigger.
} else {
if (Trigger.isInsert) {
List<Contact> contacts = new List<Contact>();
for (Account a : Trigger.new) {
if(a.Name == 'makeContact') {
contacts.add(new Contact (LastName = a.Name,
Invocation de code Apex
salesforce | Considérations sur les variables de contexte | 101
AccountId = a.Id));
}
}
insert contacts;
}
}
}}}
Considérations sur les variables de contexte
Tenez compte des considérations suivantes sur les variables de contexte de déclencheur :
•
•
•
•
Les variables trigger.new et trigger.old ne peuvent pas être utilisées dans des opérations DML Apex.
Vous pouvez utiliser un objet pour modifier ses propres valeurs de champs à l'aide de la variable trigger.new, mais
uniquement dans des déclencheurs before. Dans tous les déclencheurs after, la variable trigger.new n'est pas enregistrée,
par conséquent une exception d'exécution est levée.
La variable trigger.old est toujours en lecture seule.
Vous ne pouvez pas supprimer la variable trigger.new.
Le tableau suivant présente des considérations sur certaines actions dans différents événements de déclencheur :
Événement de déclencheur
Peut modifier des champs en Peut mettre à jour l'objet
utilisant trigger.new
d'origine en utilisant une
opération DML update
Peut supprimer l'objet
d'origine en utilisant une
opération DML delete
before insert
Autorisé.
Non applicable. L'objet
d'origine n'a pas été créé, rien
ne peut le référencer, par
conséquent, rien ne peut le
mettre à jour.
after insert
Non autorisé. Une erreur
Autorisé.
d'exécution est générée, car la
variable trigger.new est
déjà enregistrée.
Autorisé, mais pas nécessaire.
L'objet est supprimé
immédiatement après son
insertion.
before update
Autorisé.
Non autorisé. Une erreur
d'exécution est générée.
Non autorisé. Une erreur
d'exécution est générée.
after update
Non autorisé. Une erreur
d'exécution est générée, car la
variable trigger.new est
déjà enregistrée.
Autorisé. Bien qu'un code
incorrect puisse entraîner une
récursion infinie, l'erreur serait
détectée par les limitations du
gouverneur.
Autorisé. Les mises à jour sont
enregistrées avant la
suppression de l'objet, par
conséquent si la suppression
de l'objet est annulée, les mises
à jour sont visibles.
Non applicable. L'objet
d'origine n'a pas été créé, rien
ne peut le référencer, par
conséquent, rien ne peut le
mettre à jour.
Invocation de code Apex
salesforce | Idiomes de déclencheur en masse courants | 102
Événement de déclencheur
Peut modifier des champs en Peut mettre à jour l'objet
utilisant trigger.new
d'origine en utilisant une
opération DML update
Peut supprimer l'objet
d'origine en utilisant une
opération DML delete
before delete
Non autorisé. Une erreur
d'exécution est générée. La
variable trigger.new n'est
pas disponible dans les
déclencheurs before delete.
after delete
Non autorisé. Une erreur
Non applicable. L'objet a déjà Non applicable. L'objet a déjà
d'exécution est générée. La
été supprimé.
été supprimé.
variable trigger.new n'est
pas disponible dans les
déclencheurs after delete.
after undelete
Non autorisé. Une erreur
Autorisé.
d'exécution est générée. La
variable trigger.old n'est
pas disponible dans les
déclencheurs undelete.
Autorisé. Les mises à jour sont Non autorisé. Une erreur
enregistrées avant la
d'exécution est générée. La
suppression de l'objet, par
suppression est déjà en cours.
conséquent si la suppression
de l'objet est annulée, les mises
à jour sont visibles.
Autorisé, mais pas nécessaire.
L'objet est supprimé
immédiatement après son
insertion.
Idiomes de déclencheur en masse courants
Bien que les déclencheurs en masse permettent aux développeurs à traiter davantage d'enregistrements sans dépasser les
limitations du gouverneur en termes d'exécution, ils peuvent être plus difficiles à comprendre et à coder, car ils nécessitent le
traitement de lots de plusieurs enregistrements à la fois. Les sections suivantes présentent des exemples d'idiomes à utiliser
fréquemment en écrivant en masse.
Utilisation de mappages et d'ensembles dans des déclencheurs en masse
Les structures de données d'ensembles et de mappages sont essentielles pour réussir le codage de déclencheurs en masse. Les
ensembles permettent d'isoler des enregistrements distincts, alors que les mappages permettent de contenir les résultats de
requêtes organisés par ID d'enregistrement.
Par exemple, le déclencheur en masse de l'exemple d'application de devis ci-dessous commence par ajouter chaque entrée de
catalogue de prix associée à des enregistrements OpportunityLineItem dans Trigger.new à un ensemble, pour s'assurer que
l'ensemble contient uniquement des éléments distincts. Il interroge ensuite les PricebookEntries pour obtenir leurs couleurs
produit associées, et place les résultats dans un mappage. Une fois le mappage créé, le déclencheur parcourt les
OpportunityLineItems dans Trigger.new et utilise le mappage pour attribuer les couleurs appropriées.
// When a new line item is added to an opportunity, this trigger copies the value of the
// associated product's color to the new record.
trigger oppLineTrigger on OpportunityLineItem (before insert) {
// For every OpportunityLineItem record, add its associated pricebook entry
Invocation de code Apex
salesforce | Idiomes de déclencheur en masse courants | 103
// to a set so there are no duplicates.
Set<Id> pbeIds = new Set<Id>();
for (OpportunityLineItem oli : Trigger.new)
pbeIds.add(oli.pricebookentryid);
// Query the PricebookEntries for their associated product color and place the results
// in a map.
Map<Id, PricebookEntry> entries = new Map<Id, PricebookEntry>(
[select product2.color__c from pricebookentry
where id in :pbeIds]);
// Now use the map to set the appropriate color on every OpportunityLineItem processed
// by the trigger.
for (OpportunityLineItem oli : Trigger.new)
oli.color__c = entries.get(oli.pricebookEntryId).product2.color__c;
}
Corrélation d'enregistrements avec des résultats de requête dans des déclencheurs en masse
Utilisez des mappages ID vers sObject Trigger.newMap et Trigger.oldMap pour corréler les enregistrements avec les
résultats de requête. Par exemple, le déclencheur de l'exemple d'application de devis ci-dessous utilise Trigger.oldMap pour
créer un ensemble d'ID uniques (Trigger.oldMap.keySet()). L'ensemble est ensuite utilisé dans une requête pour créer
une liste des devis associés aux opportunités en cours de traitement par le déclencheur. Pour chaque devis renvoyé par la requête,
l'opportunité associée est récupérée à partir de Trigger.oldMap et sa suppression est empêchée :
trigger oppTrigger on Opportunity (before delete) {
for (Quote__c q : [SELECT opportunity__c FROM quote__c
WHERE opportunity__c IN :Trigger.oldMap.keySet()]) {
Trigger.oldMap.get(q.opportunity__c).addError('Cannot delete
opportunity with a quote');
}
}
Utilisation de déclencheurs pour insérer ou mettre à jour des enregistrements avec des champs uniques
Suite à un événement insert ou upsert, si un enregistrement duplique la valeur d'un champ unique dans un autre
enregistrement de ce lot, le message d'erreur sur l'enregistrement dupliqué inclut l'ID du premier enregistrement. Cependant,
le message d'erreur peut être erroné d'ici la fin de la requête.
Invocation de code Apex
salesforce | Définition de déclencheurs | 104
Lorsque des déclencheurs existent, la logique retry dans des opérations en masse entraîne l'exécution d'un cycle restaurer/réessayer.
Ce cycle retry attribue de nouvelles clés aux nouveaux enregistrements. Par exemple, si deux enregistrements sont insérés avec
la même valeur pour un champ unique, et que vous avez un événement insert défini pour un déclencheur, le deuxième
enregistrement dupliqué échoue, et l'ID du premier enregistrement est indiqué. Cependant, lorsque le système restaure les
modifications et réintroduit le premier enregistrement, un nouvel ID est attribué à l'enregistrement. Ainsi, le message d'erreur
généré par le deuxième enregistrement n'est plus valide.
Définition de déclencheurs
Le code d'un déclencheur est stocké sous forme de métadonnées sous l'objet auquel il est associé. Pour définir un déclencheur dans
Salesforce :
1. Pour un objet standard, cliquez sur Votre nom > Configuration > Personnaliser, cliquez sur le nom de l'objet, puis sur
Déclencheurs.
Pour un objet personnalisé, cliquez sur Votre nom > Configuration > Créer > Objets, puis cliquez sur le nom de l'objet.
Pour des membres de campagne, cliquez sur Votre nom > Configuration > Personnaliser > Campagnes > Membre de
campagne > Déclencheurs.
Pour des commentaires de requête, cliquez sur Votre nom > Configuration > Personnaliser > Requêtes > Commentaires
sur la requête > Déclencheurs.
Pour des e-mails, cliquez sur Votre nom > Configuration > Personnaliser > Requêtes > E-mails > Déclencheurs.
Pour des objets standard Pièce jointe, Contenu de document et Note, vous ne pouvez pas créer de déclencheur dans
l'interface utilisateur de Salesforce. Pour ces objets, créez un déclencheur en utilisant les outils de développement tels que
la Console du développeur ou l'IDE Force.com. Vous pouvez également utiliser l'API métadonnées.
2. Dans la liste associée Déclencheurs, cliquez sur Nouveau.
3. Cliquez sur Paramètres de version pour spécifier la version l'Apex et l'API utilisée dans ce déclencheur. Si votre organisation
a des packages gérés installés depuis AppExchange, vous pouvez également spécifier la version de chaque package géré à
utiliser avec ce déclencheur. Utilisez les valeurs par défaut pour toutes les versions. Elles associent le déclencheur à la version
la plus récente du code Apex et de l'API, ainsi que de chaque package géré. Vous pouvez spécifier une version antérieure
d'un package géré si vous souhaitez accéder à des composants ou des fonctionnalités qui diffèrent de la version la plus
récente du package.
4. Cliquez sur Déclencheur Apex, puis sélectionnez la case Est actif si le déclencheur doit être compilé et activé. N'activez
pas cette case si vous souhaitez seulement stocker le code dans les métadonnées de votre organisation. Cette case est activée
par défaut.
5. Dans la zone de texte Corps, saisissez le code Apex du déclencheur. Un seul déclencheur peut contenir jusqu'à 1 million
de caractères.
Pour définir un déclencheur, utilisez la syntaxe suivante :
trigger triggerName on ObjectName (trigger_events) {
code_block
}
où trigger_events peut être une liste de valeurs séparées par une virgule comportant un ou plusieurs des événements
suivants :
•
before insert
Invocation de code Apex
•
•
•
•
•
•
salesforce | Définition de déclencheurs | 105
before update
before delete
after insert
after update
after delete
after undelete
Remarque:
•
•
Vous pouvez utiliser le mot clé webService uniquement dans un déclencheur au sein d'une méthode définie
comme asynchrone, c.-à-d. définie avec le mot clé @future.
Un déclencheur appelé par une action insert, delete ou update pour une tâche ou un événement récurrent
entraîne une erreur d'exécution si le déclencheur est appelé en masse à partir de l'API Force.com.
6. Cliquez sur Enregistrer.
Remarque: Les déclencheurs sont stockés avec un indicateur isValid défini sur true si les métadonnées dépendantes
n'ont pas changé depuis la dernière compilation du déclencheur. Si des modifications sont apportées aux noms ou
aux champs d'objet utilisés dans le déclencheur, même si elles sont mineures (par exemple, dans la description d'un
champ ou d'un objet), l'indicateur isValid est défini sur false jusqu'à ce que le compilateur Apex réexécute le
code. La recompilation est exécutée à l'exécution suivante du déclencheur ou lorsqu'un utilisateur réenregistre le
déclencheur dans les métadonnées.
Si un champ référence un enregistrement supprimé, Salesforce efface la valeur du champ de référence par défaut.
Alternativement, vous pouvez empêcher la suppression d'enregistrements s'ils font partie d'une relation de référence.
L'éditeur de déclencheur Apex
Lors d'une modification dans Visualforce ou Apex, dans le pied de page du mode de développement Visualforce ou via
Configuration, un éditeur est disponible avec les fonctionnalités suivantes :
Mise en évidence de la syntaxe
L'éditeur applique automatiquement la mise évidence de la syntaxe pour les mots clés, et l'ensemble des fonctions et
opérateurs.
Rechercher ( )
Permet de rechercher du texte dans la page, la classe ou le déclencheur actuel. Pour utiliser la recherche, saisissez une
chaîne dans la zone de texte Rechercher, puis cliquez sur Rechercher suivant.
• Pour remplacer une chaîne de recherche trouvée, saisissez la nouvelle chaîne dans la zone de texte Remplacer, puis
cliquez sur remplacer pour remplacer uniquement cette instance, ou sur Remplacer tout pour remplacer cette instance
et toutes les autres instances de la chaîne de recherche dans la page, la classe ou le déclencheur.
• Pour rendre l'opération de recherche sensible à la casse, sélectionnez l'option Respecter la casse.
• Pour utiliser une expression régulière comme chaîne de recherche, sélectionnez l'option Expressions régulières. Les
expressions régulières suivent les règles d'expression standard de JavaScript. Une recherche utilisant des expressions
régulières peut trouver des chaînes qui occupent plusieurs lignes.
Si vous utilisez l'opération de remplacement avec une chaîne trouvée par une expression régulière, l'opération de
remplacement peut aussi relier des variables de groupe d'expressions régulières ($1, $2, etc.) à partir de la chaîne de
recherche trouvée. Par exemple, pour remplacer une balise <h1> par <h2> et conserver intacts tous les attributs de
la <h1> d'origine, recherchez <h1(\s+)(.*)> et remplacez-la par <h2$1$2>.
Invocation de code Apex
salesforce | Déclencheurs et instructions Merge | 106
Accéder à la ligne ( )
Ce bouton permet de mettre en évidence un numéro de ligne spécifié. Si la ligne n'est pas affichée, l'éditeur navigue
jusqu'à la ligne.
Annuler ( ) et Répéter ( )
Utilisez Annuler pour inverser une action de modification et Répéter pour recréer une action de modification précédemment
annulée.
Taille de la police
Sélectionnez une taille de police dans la liste déroulante pour contrôler la taille des caractères affichés dans l'éditeur.
Position de ligne et de colonne
La position de ligne et de colonne du curseur est affichée dans la barre d'état en bas de l'éditeur. Vous pouvez l'utiliser
avec la fonction Accéder à la ligne (
) pour accélérer la navigation dans l'éditeur.
Nombre de lignes et de caractères
Le nombre total de lignes et de caractères est affiché dans la barre d'état en bas de l'éditeur.
Déclencheurs et instructions Merge
Les événements de fusion n'activent par leurs propres événements de déclencheur. À la place, ils déclenchent des événements
de suppression et de mise à jour, comme suit :
Suppression des enregistrements perdus
Une opération de fusion unique déclenche un événement de suppression unique pour tous les enregistrements supprimés
dans la fusion. Pour déterminer les enregistrements supprimés suite à une opération de fusion, utilisez le champ
MasterRecordId dans Trigger.old. Lorsqu'un enregistrement est supprimé après avoir perdu dans une opération
de fusion, son champ MasterRecordId est défini sur l'ID de l'enregistrement gagnant. Le champ MasterRecordId
est défini uniquement dans les événements de déclencheur after delete. Si votre application nécessite un traitement
spécial pour les enregistrements supprimés suite à une fusion, vous devez utiliser l'événement de déclencheur after
delete.
Mise à jour de l'enregistrement gagnant
Une opération de fusion unique déclenche un événement de mise à jour unique seulement pour l'enregistrement gagnant.
Tout enregistrement enfant associé à un nouveau parent suite à l'opération de fusion n'active pas de déclencheur.
Par exemple, si deux contacts sont fusionnés, seuls les déclencheurs delete contact et update contact sont activés. Aucun
déclencheur n'est activé pour les enregistrements associés au contact, tels que les comptes ou les opportunités.
Lors d'une fusion, la séquence des événements est la suivante :
1. Le déclencheur before delete est activé.
2. Le système supprime les enregistrements nécessaires pour la fusion, attribue de nouveaux enregistrements parents aux
enregistrements enfants, puis définit le champ MasterRecordId dans les enregistrements supprimés.
3. Le déclencheur after delete est activé.
4. Le système effectue les mises à jour spécifiques requises pour l'enregistrement principal. Les déclencheurs update normaux
s'appliquent.
Invocation de code Apex
salesforce | Déclencheurs et enregistrements restaurés | 107
Déclencheurs et enregistrements restaurés
Le déclencheur after undelete fonctionne uniquement avec des enregistrements restaurés, c.-à-d. qui ont été supprimés
puis restaurés à partir de la Corbeille via l'instruction DML undelete. Ils sont également appelés enregistrements undeleted.
Les événements de déclencheur after undelete sont exécutés uniquement sur des objets de niveau supérieur. Par exemple,
si vous supprimez un compte, une opportunité peut également être supprimée. Lorsque vous restaurez le compte à partir de
la Corbeille, l'opportunité est également restaurée. Si un événement de déclencheur after undelete est associé au compte
et à l'opportunité, seul l'événement de déclencheur after undelete du compte est exécuté.
L'événement de déclencheur after undelete est activé uniquement pour les objets suivants :
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Compte
Ressource
Campagne
Requête
Contact
Document de contact
Contrat
Objets personnalisés
Événement
Piste
Opportunité
Produit
Solution
Tâche
Déclencheurs et séquence d'exécution
Lorsque vous sauvegardez un enregistrement avec une instruction insert, update ou upsert, Salesforce exécute les
événements suivants dans l'ordre.
Remarque: Avant que Salesforce n'exécute ces événements sur le serveur, le navigateur exécute une validation JavaScript
si l'enregistrement contient des champs de liste de sélection dépendante. La validation limite chaque champ de la
liste à ses valeurs disponibles. Aucune validation n'est exécutée côté client.
Sur le serveur, Salesforce effectue les opérations suivantes :
1. Chargement de l'enregistrement d'origine à partir de la base de données ou initialisation de l'enregistrement pour une
instruction upsert.
2. Chargement des nouvelles valeurs de champ de l'enregistrement à partir de la requête et remplacement des anciennes
valeurs.
Si la requête provient d'une page de modification de l'interface utilisateur standard, Salesforce exécute une validation
système pour vérifier les points suivants dans l'enregistrement :
•
•
•
Conformité avec les règles spécifiques à la présentation
Présence des valeurs requises au niveau de la présentation et au niveau de la définition du champ
Validité des formats de champ
Invocation de code Apex
•
salesforce | Déclencheurs et séquence d'exécution | 108
Longueur de champ maximale
Salesforce n'effectue pas de validation système à cette étape lorsque la requête provient d'autres sources, notamment d'une
application Apex ou d'un appel API SOAP.
3. Exécute tous les déclencheurs before.
4. Réexécute la plupart des étapes de validation système, notamment pour vérifier que tous les champs obligatoires contiennent
une valeur non null, et exécute toute règle de validation définie par utilisateur. La seule validation système que Salesforce
n'exécute pas une deuxième fois (lorsque la requête provient d'une page de modification de l'interface utilisateur standard)
est l'application des règles spécifiques à la présentation.
5. Sauvegarde l'enregistrement dans la base de données, mais sans l'appliquer.
6. Exécute tous les déclencheurs after.
7. Exécute les règles d'attribution.
8. Exécute les règles de réponse automatique.
9. Exécute les règles de workflow.
10. Si des mises à jour de champ de workflow existent, met de nouveau à jour l'enregistrement.
11. Si l'enregistrement a été actualisé avec des mises à jour de champ de workflow, active une nouvelle fois (une nouvelle fois
seulement) les déclencheurs before et after, en plus des validations standard. Les règles de validation personnalisées
ne sont pas réexécutées.
Remarque: Les déclencheurs before et after sont activés une nouvelle fois uniquement si des éléments doivent
être mis à jour. Si les champs ont déjà été définis sur une valeur, les déclencheurs ne sont pas activés de nouveau.
12. Exécute les règles d'escalade.
13. Si l'enregistrement contient un champ récapitulatif de cumul ou fait partie d'un workflow inter-objets, il effectue des calculs
et met à jour le champ récapitulatif de cumul dans l'enregistrement parent. L'enregistrement parent passe par la procédure
de sauvegarde.
14. Si l'enregistrement parent est mis à jour, et qu'un enregistrement grand-parent contient un champ récapitulatif de cumul
ou fait partie d'un workflow inter-objets, il effectue des calculs et met à jour le champ récapitulatif de cumul dans
l'enregistrement parent. L'enregistrement grand-parent passe par la procédure de sauvegarde.
15. Exécute l'évaluation Partage basé sur des critères.
16. Applique toutes les opérations DML à la base de données.
17. Exécute une logique post-application, par exemple envoi d'e-mails.
Remarque: Durant un enregistrement récursif, Salesforce ignore les étapes 7 à 14.
Considérations supplémentaires
Notez les points suivants lors de l'utilisation de déclencheurs :
•
•
Si l'option Activer la validation et les déclencheurs à partir de la conversion de piste est
sélectionnée, que la conversion de piste crée une opportunité et que cette opportunité a des déclencheurs Apex before
associés, les déclencheurs sont exécutés immédiatement après la création de l'opportunité et avant la création du rôle de
contact de l'opportunité. Pour plus d'informations, reportez-vous à « Personnalisation des paramètres de piste » dans l'aide
en ligne de Salesforce.
Si vous utilisez des déclencheurs before pour définir les valeurs Stage et Forecast Category d'un enregistrement
d'opportunité, le comportement est le suivant :
Invocation de code Apex
salesforce | Opérations n'invoquant pas de déclencheurs | 109
◊ Si vous définissez les valeurs Stage et Forecast Category, l'enregistrement d'opportunité contient ces valeurs
exactes.
◊ Si vous définissez la valeur Stage, mais pas Forecast Category, la valeur Forecast Category de l'enregistrement
d'opportunité applique par défaut la valeur associée à Stage dans le déclencheur.
◊ Si vous réinitialisez la valeur Stage sur une valeur spécifiée dans un appel API ou entrante provenant de l'interface
utilisateur, la valeur Forecast Category doit également provenir de l'appel API ou de l'interface utilisateur. Si
aucune valeur n'est spécifiée pour Forecast Category et que la valeur entrante Stage est différente de la valeur
Stage du déclencheur, Forecast Category applique par défaut la valeur associée à Stage dans le déclencheur. Si
la valeur Stage du déclencheur et la valeur Stage entrante sont identiques, Forecast Category n'est pas appliquée
par défaut.
•
Si vous clonez une opportunité avec des produits, les événements suivants se produisent dans l'ordre :
1. L'opportunité parent est enregistrée conformément à la liste des événements indiqués ci-dessus.
2. Les produits d'opportunité sont enregistrés conformément à la liste des événements indiqués ci-dessus.
Remarque: Si des erreurs se produisent dans un produit d'opportunité, vous devez renvoyer l'opportunité et
corriger les erreurs avant le clonage.
Si des produits d'opportunité contiennent des champs personnalisés uniques, vous devez les renseigner avec des
valeurs nulles avant de cloner l'opportunité.
•
Trigger.old contient une version des objets antérieure à la mise à jour spécifique qui a activé le déclencheur. Il existe
cependant une exception : Lorsqu'un enregistrement est mis à jour, déclenchant ainsi la mise à jour d'un champ de règle
de workflow, dans le dernier déclencheur update, Trigger.old ne contient pas la version de l'objet immédiatement
antérieur à la mise à jour du workflow, mais l'objet antérieur à la mise à jour initiale effectuée. Par exemple, supposons
qu'un enregistrement existant contient un champ numérique avec une valeur initiale de 1. Un utilisateur met à jour ce
champ sur 10, une mise à jour de champ de workflow est exécutée et incrémente la valeur à 11. Dans le déclencheur update
qui est exécuté après la mise à jour du champ de workflow, la valeur du champ de l'objet obtenue par Trigger.old
correspond à la valeur d'origine 1, plutôt que 10, comme ce serait normalement le cas.
Opérations n'invoquant pas de déclencheurs
Les déclencheurs sont invoqués uniquement pour les opérations DML (langage de manipulation de données) qui sont initiées
ou traitées par le serveur d'applications Java. Par conséquent, actuellement certaines opérations en masse système n'invoquent
pas de déclencheurs. Voici quelques exemples :
•
•
•
•
•
•
•
•
•
•
•
•
Opérations de suppression en cascade. Les enregistrements qui n'ont pas initié une suppression delete n'entraînent pas
d'évaluation de déclencheur.
Mise à jour en cascade d'enregistrements enfants associés à un nouveau parent suite à une opération de fusion
Modifications en masse de statuts de campagne
Transferts en masse de services
Mises à jour en masse d'adresses
Transferts en masse de requêtes d'approbation
Actions en masse de messagerie
Modification des types de données de champ personnalisé
Renommage ou remplacement de listes de sélection
Gestion de catalogues
Modification du service par défaut d'un utilisateur avec l'option de transfert de service activée
Modifications des objets suivants :
Invocation de code Apex
salesforce | Considérations sur les entités et les champs dans
les déclencheurs | 110
◊ BrandTemplate
◊ MassEmailTemplate
◊ Folder
•
Les déclencheurs update account ne sont pas activés avant ou après la modification d'un type d'enregistrement compte
professionnel en compte personnel (ou compte personnel en compte professionnel).
Remarque: Les opérations d'insertion, de mise à jour et de suppression sur des comptes personnels activent des
déclencheurs de compte, pas des déclencheurs de contact.
Les déclencheurs before associés aux opérations suivantes sont activés uniquement lors d'une conversion de piste si la validation
et les déclencheurs sont activés pour la conversion de piste dans l'organisation :
•
•
insert de comptes, contacts et opportunités
update de comptes et contacts
Les déclencheurs d'opportunité ne sont pas activés lorsque le propriétaire du compte change suite au changement du propriétaire
de l'opportunité associée.
Lorsque vous modifiez un produit d'opportunité dans une opportunité, ou lorsqu'une planification de produit d'opportunité
change un produit d'opportunité, même si le produit d'opportunité change l'opportunité, les déclencheurs before et after
et les règles de validation ne sont pas activés pour l'opportunité. Cependant, les champs récapitulatifs de cumul sont mis à jour
et les règles de workflow associées à l'opportunité sont exécutées.
Les méthodes PageReference getContent et getContentAsPDF ne sont pas autorisées dans des déclencheurs.
Notez les points suivants concernant l'objet ContentVersion :
•
Les opérations de pack de contenu qui impliquent l'objet ContentVersion, y compris slides et slide autorevision, n'invoquent
pas de déclencheurs.
Remarque: Un pack de contenu est révisé lors de la révision l'une de ses diapositives.
•
•
Les valeurs des champs TagCsv et VersionData sont disponibles dans les déclencheurs uniquement si la requête de
création ou de mise à jour d'enregistrements ContentVersion provient de l'API.
Vous ne pouvez pas utiliser les déclencheurs before ou after delete avec l'objet ContentVersion.
Considérations sur les entités et les champs dans les déclencheurs
Entité QuestionDataCategorySelection non disponible dans les déclencheurs After Insert
Le déclencheur after insert, qui est activé après l'insertion d'un ou de plusieurs enregistrements Question, n'a pas accès
aux enregistrements QuestionDataCategorySelection associé aux Questions insérées. Par exemple, la requête suivante
ne renvoie aucun résultat dans un déclencheur after insert :
QuestionDataCategorySelection[] dcList =
[select Id,DataCategoryName from QuestionDataCategorySelection where ParentId IN :questions];
Invocation de code Apex
salesforce | Considérations sur les entités et les champs dans
les déclencheurs | 111
Champs non mis à jour dans les déclencheurs Before
Certaines valeurs sont définies pendant l'opération de sauvegarde système qui est exécutée après l'activation des déclencheurs
before. Par conséquent, ces champs ne peuvent pas être modifiés ni détectés avec précision dans un déclencheur before
insert ou before update. Voici quelques exemples :
•
•
•
•
•
•
•
•
•
•
•
•
Task.isClosed
Opportunity.amount*
Opportunity.ForecastCategory
Opportunity.isWon
Opportunity.isClosed
Contract.activatedDate
Contract.activatedById
Case.isClosed
Solution.isReviewed
Id (pour tous les enregistrements)**
createdDate (pour tous les enregistrements)**
lastUpdated (pour tous les enregistrements)
* Lorsque Opportunity ne contient pas de lineitems, Amount peut être modifié par un déclencheur before.
** Id et createdDate peuvent être détectés dans des déclencheurs before update, mais pas modifiés.
Entités non prises en charge dans les déclencheurs Update
Certains objets ne peuvent pas être mis à jour et, par conséquent, ne doivent pas avoir de déclencheurs before update et
after update.
•
•
FeedItem
FeedComment
Entités non prises en charge dans les déclencheurs After Undelete
Certains objets ne peuvent pas être restaurés et, par conséquent, ne doivent pas avoir de déclencheurs after undelete.
•
•
•
•
CollaborationGroup
CollaborationGroupMember
FeedItem
FeedComment
Considérations supplémentaires sur les objets Chatter
Notez les points suivants sur les déclencheurs FeedItem et FeedComment :
•
•
•
Seuls les FeedItems de Type TextPost, LinkPost et ContentPost peuvent être insérés et, par conséquent, invoquer
le déclencheur before ou after insert. Les mises à jour de statut d'utilisateur n'entraînent pas l'activation des
déclencheurs FeedItem.
Bien que les objets FeedPost soient pris en charge par l'API versions 18.0, 19.0 et 20.0, n'utilisez pas les déclencheurs insert
ou delete enregistrés dans des versions antérieures à 21.0.
Pour FeedItem, les champs suivants ne sont pas disponibles dans le déclencheur before insert :
◊ ContentSize
◊ ContentType
De plus, le champ ContentData n'est disponible dans aucun déclencheur.
Invocation de code Apex
salesforce | Exceptions de déclencheur | 112
Pour les déclencheurs before insert et after insert FeedComment, les champs de ContentVersion associés à
FeedComment (obtenu via FeedComment.RelatedRecordId) ne sont pas disponibles.
Le code Apex utilise une sécurité supplémentaire lors de l'exécution dans un contexte Chatter. Pour publier dans un groupe
privé, l'utilisateur qui exécute le code doit être membre de ce groupe. Si l'utilisateur n'est pas membre, vous pouvez définir
le champ CreatedById en tant que membre du groupe dans l'enregistrement FeedItem.
•
•
Notez les points suivants pour les objets CollaborationGroup et CollaborationGroupMember :
Lors de la mise à jour de CollaborationGroupMember, CollaborationGroup est également mis à jour automatiquement
pour s'assurer que le nombre de membres est correct. Ainsi, lorsque les déclencheurs update ou delete
CollaborationGroupMember sont exécutés, les déclencheurs update CollaborationGroup sont également exécutés.
•
Exceptions de déclencheur
Des déclencheurs peuvent être utilisés pour empêcher l'exécution d'opérations DML en appelant la méthode addError()
dans un enregistrement ou un champ. Lors d'une utilisation sur des enregistrements Trigger.new dans des déclencheurs
insert et update, et sur des enregistrements Trigger.old dans des déclencheurs delete, le message d'erreur personnalisé
s'affiche dans l'interface de l'application et est consigné.
Remarque: Pour l'utilisateur, le délai de réponse est réduit si les erreurs sont ajoutées aux déclencheurs before.
Un sous-ensemble d'enregistrements en cours de traitement peut être marqué avec la méthode addError() :
Si le déclencheur a été engendré par une instruction DML dans Apex, toute erreur entraîne l'annulation de l'opération
complète. Cependant, le moteur d'exécution traite chaque enregistrement dans l'opération afin de compiler une liste
d'erreurs exhaustive.
Si le déclencheur a été engendré par un appel DML en masse dans l'API Force.com, le moteur d'exécution laisse de côté
les enregistrements incorrects et tente d'effectuer une sauvegarde partielle des enregistrements qui n'ont généré aucune
erreur. Reportez-vous à Gestion des exceptions DML en masse à la page 353.
•
•
Si un déclencheur génère une exception non gérée, tous les enregistrements sont marqués avec une erreur et aucun traitement
n'est effectué.
Meilleures pratiques pour les déclencheurs et les requêtes en masse
En développement, il est inexact de considérer que les invocations de déclencheurs ne contiennent jamais plus d'un
enregistrement. Les déclencheurs Apex sont optimisés pour fonctionner en masse ce qui, par définition, nécessite que les
développeurs écrivent la logique prenant en charge les opérations en masse.
Voici un exemple d'un modèle de programmation défectueux. Il suppose qu'un seul enregistrement est extrait pendant une
invocation de déclencheur. Bien qu'il puisse prendre en charge la plupart des événements d'interface utilisateur, il ne prend
pas en charge les opérations en masse invoquées via l'API SOAP ou Visualforce.
trigger MileageTrigger on Mileage__c (before insert, before update) {
User c = [SELECT Id FROM User WHERE mileageid__c = Trigger.new[0].id];
}
Invocation de code Apex
salesforce | Planificateur Apex | 113
Voici un autre exemple d'un modèle de programmation défectueux. Il suppose que moins de 100 enregistrements sont extraits
pendant une invocation de déclencheur. Si plus de 20 enregistrements sont extraits dans cette requête, le déclencheur dépasse
la limite de requêtes SOQL de instructions 100 SELECT :
trigger MileageTrigger on Mileage__c (before insert, before update) {
for(mileage__c m : Trigger.new){
User c = [SELECT Id FROM user WHERE mileageid__c = m.Id];
}
}
Pour plus d'informations sur les limitations du gouverneur, reportez-vous à Compréhension des limitations et des gouverneurs
d'exécution à la page 273.
Cet exemple montre le modèle correct pour prendre en charge la nature en masse des déclencheurs, tout en respectant les
limitations du gouverneur :
Trigger MileageTrigger on Mileage__c (before insert, before update) {
Set<ID> ids = Trigger.new.keySet();
List<User> c = [SELECT Id FROM user WHERE mileageid__c in :ids];
}
Ce modèle respecte la nature en masse du déclencheur en transmettant la collection Trigger.new à un ensemble, puis en
utilisant l'ensemble dans une requête SOQL unique. Ce modèle capture tous les enregistrements entrants dans la requête, tout
en limitant le nombre de requêtes SOQL.
Meilleures pratiques pour la conception de programmes en masse
Les meilleurs pratiques de conception de ce modèle sont les suivantes :
•
•
Limiter le nombre d'opérations DML (langage de manipulation de données) en ajoutant des enregistrements à des collections
et en effectuant les opérations DML sur ces collections.
Limiter le nombre d'instructions SOQL en retraitant les enregistrements et en générant des ensembles, qui peuvent être
placés dans une seule instruction SOQL utilisée avec la clause IN.
Voir aussi :
Quelles sont les limitations du langage Apex ?
Planificateur Apex
Pour invoquer l'exécution de classes Apex à des heures spécifiques, commencez par mettre en oeuvre l'interface Schedulable
pour la classe, puis spécifiez la planification en utilisant la page Planifier Apex dans l'interface utilisateur de Salesforce, ou la
méthode System.schedule.
Invocation de code Apex
salesforce | Planificateur Apex | 114
Pour plus d'informations sur la page Planifier Apex, reportez-vous à « Planification de classes Apex » dans l'aide en ligne de
Salesforce.
Important: Salesforce ajoute le processus à la file d'attente uniquement à l'heure prévue. L'exécution réelle peut être
retardée en fonction de la disponibilité du service.
Vous pouvez avoir 25 classes planifiées à la fois. Vous pouvez déterminer le nombre actuel en affichant la page Tâches
planifiées dans Salesforce ou en programmant l'API SOAP pour interroger l'objet CronTrigger.
Soyez très prudent(e) si vous envisagez de planifier une classe à partir d'un déclencheur. Assurez-vous que le déclencheur
n'ajoute pas davantage de classes planifiées que les 25 autorisées. En particulier, considérez les mises à jour en masse
d'API, les assistants d'importation, les modifications d'enregistrement en masse via l'interface utilisateur et toutes les
situations dans lesquelles plusieurs enregistrements peuvent être mis à jour à la fois.
Vous ne pouvez pas mettre à jour une classe Apex s'il existe une ou plusieurs tâches planifiées actives pour cette classe.
Mise en oeuvre de l'interface Schedulable
Pour planifier l'exécution d'une classe Apex à intervalles réguliers, commencez par écrire une classe Apex qui met en oeuvre
l'interface Schedulable fournie par Salesforce.
Le planificateur s'exécute en tant que système : toutes les classes sont exécutées, que l'utilisateur dispose ou non de l'autorisation
d'exécution de la classe. Pour plus d'informations sur la définition d'autorisations de classe, reportez-vous à « Présentation de
la sécurité de la classe Apex » dans l'aide en ligne de Salesforce.
Pour surveiller ou arrêter l'exécution d'une tâche Apex planifiée en utilisant l'interface utilisateur de Salesforce, cliquez sur
Votre nom > Configuration > Surveillance > Tâches planifiées. Pour plus d'informations, reportez-vous à « Surveillance
des tâches prévues » dans l'aide en ligne de Salesforce.
L'interface Schedulable inclut une méthode qui doit être mise en oeuvre, execute.
global void execute(SchedulableContext sc){}
La méthode mise en oeuvre doit être déclarée global ou public.
Utilisez cette méthode pour instancier la classe que vous souhaitez planifier.
Conseil: Bien qu'il soit possible d'effectuer un traitement supplémentaire dans la méthode execute, nous
recommandons d'exécuter tout le traitement dans une classe séparée.
L'exemple ci-dessous met en oeuvre l'interface Schedulable pour une classe appelée mergeNumbers :
global class scheduledMerge implements Schedulable{
global void execute(SchedulableContext SC) {
mergeNumbers M = new mergeNumbers();
}
}
L'exemple suivant utilise la méthode System.Schedule pour mettre en oeuvre la classe ci-dessus.
scheduledMerge m = new scheduledMerge();
Invocation de code Apex
salesforce | Planificateur Apex | 115
String sch = '20 30 8 10 2 ?';
system.schedule('Merge Job', sch, m);
Vous pouvez également utiliser l'interface Schedulable avec des classes Apex par lot. L'exemple suivant met en oeuvre
l'interface Schedulable pour une classe Apex appelée batchable :
global class scheduledBatchable implements Schedulable{
global void execute(SchedulableContext sc) {
batchable b = new batchable();
database.executebatch(b);
}
}
Utilisez l'objet SchedulableContext poursuivre la tâche lorsqu'elle est planifiée. La méthode SchedulableContext getTriggerID
renvoie l'ID de l'objet CronTrigger associé à cette tâche planifiée en tant que chaîne. Utilisez cette méthode pour suivre la
progression de la tâche planifiée.
Pour arrêter l'exécution d'une tâche qui a été planifiée, utilisez la méthode System.abortJob avec l'ID renvoyé par la
méthode getTriggerID.
Test du planificateur Apex
L'exemple ci-dessous montre comment tester à l'aide du planificateur Apex.
La méthode System.schedule lance un processus asynchrone. Cela signifie que lorsque vous testez un code Apex planifié,
vous devez vous assurer que la tâche planifiée est terminée avant de tester les résultats. Utilisez les méthodes de Test startTest
et stopTest sur la méthode System.schedule pour vous assurer qu'elle est terminée avant de poursuivre votre test. Tous
les appels asynchrones effectués après la méthode startTest sont collectés par le système. Lors de l'exécution de stopTest,
tous les processus asynchrones sont exécutés de façon synchrone. Si vous n'incluez pas la méthode System.schedule dans
les méthodes startTest et stopTest, la tâche planifiée est exécutée à la fin de votre méthode de test pour le code Apex
enregistré à l'aide de l'API Salesforce.com versions 25.0 et supérieures, mais pas dans les versions antérieures.
Voici la classe à tester :
global class TestScheduledApexFromTestMethod implements Schedulable {
// This test runs a scheduled job at midnight Sept. 3rd. 2022
public static String CRON_EXP = '0 0 0 3 9 ? 2022';
global void execute(SchedulableContext ctx) {
CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime
FROM CronTrigger WHERE Id = :ctx.getTriggerId()];
Invocation de code Apex
salesforce | Planificateur Apex | 116
System.assertEquals(CRON_EXP, ct.CronExpression);
System.assertEquals(0, ct.TimesTriggered);
System.assertEquals('2022-09-03 00:00:00', String.valueOf(ct.NextFireTime));
Account a = [SELECT Id, Name FROM Account WHERE Name =
'testScheduledApexFromTestMethod'];
a.name = 'testScheduledApexFromTestMethodUpdated';
update a;
}
}
Le code suivant teste la classe ci-dessus :
@istest
class TestClass {
static testmethod void test() {
Test.startTest();
Account a = new Account();
a.Name = 'testScheduledApexFromTestMethod';
insert a;
// Schedule the test job
String jobId = System.schedule('testBasicScheduledApex',
TestScheduledApexFromTestMethod.CRON_EXP,
new TestScheduledApexFromTestMethod());
// Get the information from the CronTrigger API object
CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered,
NextFireTime
FROM CronTrigger WHERE id = :jobId];
Invocation de code Apex
salesforce | Planificateur Apex | 117
// Verify the expressions are the same
System.assertEquals(TestScheduledApexFromTestMethod.CRON_EXP,
ct.CronExpression);
// Verify the job has not run
System.assertEquals(0, ct.TimesTriggered);
// Verify the next time the job will run
System.assertEquals('2022-09-03 00:00:00',
String.valueOf(ct.NextFireTime));
System.assertNotEquals('testScheduledApexFromTestMethodUpdated',
[SELECT id, name FROM account WHERE id = :a.id].name);
Test.stopTest();
System.assertEquals('testScheduledApexFromTestMethodUpdated',
[SELECT Id, Name FROM Account WHERE Id = :a.Id].Name);
}
}
Utilisation de la méthode System.Schedule
Après avoir mis en oeuvre une classe avec l'interface Schedulable, utilisez la méthode System.Schedule pour l'exécuter.
Le planificateur s'exécute en tant que système : toutes les classes sont exécutées, que l'utilisateur dispose ou non de l'autorisation
d'exécution de la classe.
Remarque: Soyez très prudent(e) si vous envisagez de planifier une classe à partir d'un déclencheur. Assurez-vous
que le déclencheur n'ajoute pas davantage de classes planifiées que les 25 autorisées. En particulier, considérez les
mises à jour en masse d'API, les assistants d'importation, les modifications d'enregistrement en masse via l'interface
utilisateur et toutes les situations dans lesquelles plusieurs enregistrements peuvent être mis à jour à la fois.
La méthode System.Schedule utilise trois arguments : un nom pour la tâche, une expression utilisée pour représenter l'heure
et la date d'exécution planifiée de la tâche, ainsi que le nom de la classe La syntaxe de cette expression est la suivante :
Seconds Minutes Hours Day_of_month Month Day_of_week optional_year
Remarque: Salesforce ajoute le processus à la file d'attente uniquement à l'heure prévue. L'exécution réelle peut être
retardée en fonction de la disponibilité du service.
La méthode System.Schedule utilise le fuseau horaire de l'utilisateur comme base pour toutes les planifications.
Invocation de code Apex
salesforce | Planificateur Apex | 118
Les valeurs de l'expression sont les suivantes :
Nom
Valeurs
Caractères spéciaux
Seconds
0 à 59
Aucun
Minutes
0 à 59
Aucun
Hours
0 à 23
, - * /
Day_of_month
1 à 31
, - * ? / L W
Month
1 à 12 ou comme suit :
• JAN
• FEB
• MAR
• APR
• MAY
• JUN
• JUL
• AUG
• SEP
• OCT
• NOV
• DEC
, - * /
Day_of_week
1 à 7 ou comme suit :
• SUN
• MON
• TUE
• WED
• THU
• FRI
• SAT
, - * ? / L #
optional_year
null ou 1970 à 2099
, - * /
Les caractères spéciaux sont définis comme suit :
Caractère spécial
Description
,
Délimite les valeurs. Par exemple, utilisez JAN, MAR, APR pour spécifier
plusieurs mois.
-
Spécifie une plage. Par exemple, utilisez JAN-MAR pour spécifier plusieurs mois.
*
Spécifie toutes les valeurs. Par exemple, si Month est spécifié en tant que *, la
tâche est planifiée tous les mois.
?
Spécifie aucune valeur précise. Disponible uniquement pour Day_of_month et
Day_of_week, et généralement utilisé afin de spécifier une valeur pour l'un et
pas pour l'autre.
Invocation de code Apex
salesforce | Planificateur Apex | 119
Caractère spécial
Description
/
Spécifie des incréments. Le chiffre qui précède la barre oblique spécifie le début
de l'intervalle et le chiffre qui suit la barre oblique indique la valeur de l'intervalle.
Par exemple, si vous spécifiez 1/5 pour Day_of_month, la classe Apex est
exécutée le cinquième jour de chaque mois, à compter du premier du mois.
L
Spécifie la fin d'une plage (dernier). Disponible uniquement pour Day_of_month
et Day_of_week. Utilisé avec Day of month, L indique toujours le dernier
jour du mois, par exemple le 31 janvier, le 29 février pour les années bissextiles,
etc. Utilisé seul avec Day_of_week, signifie toujours 7 ou SAT (si samedi est le
dernier jour de la semaine). Utilisé avec une valeur Day_of_week, signifie le
dernier jour de ce type dans le mois. Par exemple, si vous spécifiez 2L, vous
désignez le dernier lundi du mois. N'utilisez pas une plage de valeurs avec L, car
vous risquez d'obtenir des valeurs inattendues.
W
Spécifie le jour de la semaine le plus proche (lundi à vendredi) d'un jour donné.
Disponible uniquement pour Day_of_month. Par exemple, si vous spécifiez
20W et que le 20 est un samedi, la classe est exécutée le 19. Si vous spécifiez 1W
et que le 1er est un samedi, la classe n'est pas exécutée le mois précédent, mais
le 3, c.-à-d. le lundi suivant.
Conseil: Utilisez L et W ensemble pour spécifier le dernier jour de la
semaine du mois.
Spécifie le énième jour du mois, sous le format weekday#day_of_month.
Disponible uniquement pour Day_of_week. Le chiffre qui précède # spécifie
le jour de la semaine (SUN-SAT, si dimanche est le premier jour de la semaine).
Le nombre qui suit # spécifie le jour du mois. Par exemple, 2#2 signifie que la
classe est exécutée de deuxième lundi de chaque mois.
#
Le tableau suivant présente des exemples d'utilisation de l'expression.
Expression
Description
0 0 13 * * ?
La classe est exécutée tous les jours à 13 heures.
0 0 22 ? * 6L
La classe est exécutée le dernier vendredi de chaque mois à 22
heures.
0 0 10 ? * MON-FRI
La classe est exécutée du lundi au vendredi à 10 heures.
0 0 20 * * ? 2013
La classe est exécutée tous les jours à 8 heures pendant l'année
2013.
Dans l'exemple suivant, la classe proschedule met en oeuvre l'interface Schedulable. L'exécution de la classe est planifiée
à 8 heures le 13 février
proschedule p = new proschedule();
String sch = '0 0 8 13 2 ?';
system.schedule('One Time Pro', sch, p);
Invocation de code Apex
salesforce | Blocs anonymes | 120
Meilleures pratiques et limitations du planificateur Apex
•
•
•
•
•
•
Salesforce ajoute le processus à la file d'attente uniquement à l'heure prévue. L'exécution réelle peut être retardée en fonction
de la disponibilité du service.
Soyez très prudent(e) si vous envisagez de planifier une classe à partir d'un déclencheur. Assurez-vous que le déclencheur
n'ajoute pas davantage de classes planifiées que les 25 autorisées. En particulier, considérez les mises à jour en masse d'API,
les assistants d'importation, les modifications d'enregistrement en masse via l'interface utilisateur et toutes les situations
dans lesquelles plusieurs enregistrements peuvent être mis à jour à la fois.
Bien qu'il soit possible d'effectuer un traitement supplémentaire dans la méthode execute, nous recommandons d'exécuter
tout le traitement dans une classe séparée.
Vous pouvez avoir 25 classes planifiées à la fois. Vous pouvez déterminer le nombre actuel en affichant la page Tâches
planifiées dans Salesforce ou en programmant l'API SOAP pour interroger l'objet CronTrigger.
Vous ne pouvez pas utiliser les méthodes getContent et getContentAsPDF PageReference dans un code Apex
planifié.
Les appels de services Web synchrones ne sont pas pris en charge dans un code Apex planifié. Pour pouvoir effectuer des
appels, créez en appel asynchrone en le plaçant dans une méthode annotée avec @future(callout=true), puis appelez
cette méthode à partir d'un code Apex planifié. Cependant, si votre code Apex planifié exécute une tâche par lot, les appels
sont pris en charge par la classe par lot. Reportez-vous à Utilisation d'un code Apex par lot.
Blocs anonymes
Un bloc anonyme est un code Apex qui n'est pas stocké dans les métadonnées, mais qui peut être compilé et exécuté en utilisant
l'un des éléments suivants :
•
•
•
Console du développeur
IDE Force.com
L'appel de l'API SOAP executeAnonymous :
ExecuteAnonymousResult executeAnonymous(String code)
Vous pouvez utiliser des blocs anonymes pour évaluer rapidement et sur le champ un code Apex, par exemple dans la Console
du développeur ou l'IDE Force.com, ou pour écrire un code qui change dynamiquement à l'exécution. Par exemple, vous
pouvez écrire une application Web cliente qui récupère la saisie d'un utilisateur, par exemple un nom ou une adresse, et utilise
un bloc anonyme de code Apex pour insérer un contact avec ce nom et cette adresse dans la base de données.
Notez les points suivants sur le contenu d'un bloc anonyme (pour executeAnonymous, la chaîne code) :
•
•
•
•
•
•
Il peut inclure des méthodes et des exceptions définies par l'utilisateur.
Les méthodes définies par l'utilisateur ne peuvent pas inclure le mot clé static.
Il n'est pas nécessaire d'appliquer manuellement des modifications dans la base de données.
Si votre déclencheur Apex réussit, toute modification apportée à la base de données s'applique automatiquement. Si votre
déclencheur Apex échoue, les modifications apportées à la base de données sont annulées.
Contrairement aux classes et aux déclencheurs, les blocs anonymes s'exécutent sous l'utilisateur actuel et peuvent échouer
lors de la compilation si le code viole les autorisations au niveau du champ et de l'objet de l'utilisateur.
Il n'a pas d'autre portée que locale. Par exemple, bien qu'il soit illégal d'utiliser le modificateur d'accès global, il n'a aucune
signification. La portée de la méthode est limitée au bloc anonyme.
Invocation de code Apex
salesforce | Apex dans AJAX | 121
Bien qu'une méthode définie par l'utilisateur puisse se référencer elle-même ou référencer des méthodes ultérieures sans
déclaration forward (anticipée), les variables ne peuvent pas être référencées avant leur déclaration. Dans l'exemple suivant, le
nombre entier int doit être déclaré, alors que myProcedure1 ne l'est pas :
Integer int1 = 0;
void myProcedure1() {
myProcedure2();
}
void myProcedure2() {
int1++;
}
myProcedure1();
Le résultat renvoyé pour des blocs anonymes comprend :
•
•
•
Des informations de statut pour les phases de compilation et d'exécution de l'appel, qui incluent les erreurs générées.
Le contenu du journal de débogage, qui inclut la sortie de tous les appels à la méthode System.debug (reportez-vous à
Compréhension du journal de débogage à la page 256)
La trace de pile Apex de toutes les exceptions d'exécution de code non détectées, qui inclut la classe, la méthode et le
numéro de ligne de chaque élément de pile d'appel.
Pour plus d'informations sur executeAnonymous(), reportez-vous à API SOAP et en-têtes SOAP pour Apex. Reportez-vous
également à Utilisation de journaux dans la Console du développeur et à IDE Force.com.
Apex dans AJAX
Les outils AJAX comprennent une prise en charge intégrée de l'invocation de code Apex via des blocs anonymes ou des
méthodes webService publiques. Pour cela, insérez les lignes suivantes dans votre code AJAX :
<script src="/soap/ajax/15.0/connection.js" type="text/javascript"></script>
<script src="/soap/ajax/15.0/apex.js" type="text/javascript"></script>
Remarque: Pour des boutons AJAX, utilisez les formes alternatives.
Pour invoquer un code Apex, utilisez l'une des deux méthodes suivantes :
•
Exécuter anonymement via sforce.apex.executeAnonymous (script). Cette méthode renvoie un résultat similaire
au type de résultat de l'API, mais en tant que structure JavaScript.
Invocation de code Apex
•
salesforce | Apex dans AJAX | 122
Utiliser un WSDL de classe. Par exemple, vous pouvez appeler la classe Apex suivante :
global class myClass {
webService static Id makeContact(String lastName, Account a) {
Contact c = new Contact(LastName = lastName, AccountId = a.Id);
return c.id;
}
}
En utilisant le code JavaScript suivant :
var account = sforce.sObject("Account");
var id = sforce.apex.execute("myClass","makeContact",
{lastName:"Smith",
a:account});
La méthode execute prend des types de données primitifs, des sObjects et des listes de primitifs ou de sObjects.
Pour appeler une méthode webService sans paramètre, utilisez {} comme troisième paramètre pour
sforce.apex.execute. Par exemple, pour appeler la classe Apex suivante :
global class myClass{
webService static String getContextUserName() {
return UserInfo.getFirstName();
}
}
Utilisez le code JavaScript suivant :
var contextUser = sforce.apex.execute("myClass", "getContextUserName", {});
Remarque: Si un espace de noms a été défini pour votre organisation, vous devez l'inclure dans le code JavaScript
lorsque vous invoquez la classe. Par exemple, pour appeler la classe ci-dessus, le code JavaScript doit être réécrit
comme suit :
var contextUser = sforce.apex.execute("myNamespace.myClass", "getContextUserName",
{});
Pour vérifier si votre organisation a un espace de noms, connectez-vous à votre organisation Salesforce, puis accédez
à Votre nom > Configuration > Créer > Packages. Si un espace de noms est défini, il est indiqué sous Paramètres
du développeur.
Les deux exemples produisent des valeurs JavaScript natives qui représentent le type de renvoi des méthodes.
Invocation de code Apex
salesforce | Apex dans AJAX | 123
Utilisez la ligne suivante pour afficher une fenêtre contextuelle contenant les informations de débogage.
sforce.debug.trace=true;
Chapitre 4
Classes, objets et interfaces
Sujets :
•
•
•
•
•
•
•
•
•
•
•
Compréhension des classes
Interfaces et extension de classes
Mots clés
Annotations
Classes et conversion
Différences entre les classes Apex et
les classes Java
Création d'une définition de classe
Sécurité des classes
Application des autorisations d'objet
et de champ
Préfixe d'espace de noms
Paramètres de version
Une classe est un modèle ou plan directeur à partir duquel les objets Apex sont
créés. Les classes sont formées d'autres classes, de méthodes définies par
l'utilisateur, de variables, de types d'exception et d'un code d'initialisation statique.
Elles sont stockées dans l'application sous Votre nom > Configuration >
Développer > Classes Apex.
Une fois enregistrées, les méthodes de classe ou les variables peuvent être appelées
par un autre code Apex, ou via l'API SOAP (ou outils AJAX) pour les méthodes
désignées par le mot clé webService.
Dans la plupart des cas, les concepts de classe présentés ici sont basés sur leurs
semblables dans Java et sont faciles à comprendre pour les personnes qui
connaissent Java.
•
•
•
•
•
•
•
Compréhension des classes : informations supplémentaires sur la création de
classes dans Apex
Interfaces et extension de classes : informations sur les interfaces
Mot clés et Annotations : modificateurs supplémentaires pour des classes,
des méthodes ou des variables
Classes et conversions : attribution d'une classe d'un type de données à un
autre
Différences entre les classes Apex et les classes Java : en quoi Apex et Java
diffèrent
Création d'une définition de classe et Sécurité des classes : création d'une
classe dans l'interface utilisateur de Salesforce et autoriser les utilisateurs à
accéder aux classes
Préfixe d'espace de noms et Paramètres de version : utilisation d'un préfixe
d'espace de noms et de classes Apex de version
Classes, objets et interfaces
salesforce | Compréhension des classes | 125
Compréhension des classes
Comme dans Java, vous pouvez créer des classes dans le langage Apex. Une classe est un modèle ou plan directeur à partir
duquel les objets sont créés. Un object est une instance d'une classe. Par exemple, la classe PurchaseOrder décrit un bon de
commande complet ainsi que toutes les actions possibles avec un bon de commande. Une instance de la classe PurchaseOrder
est un bon de commande spécifique que vous envoyez ou recevez.
Tous les objets ont un état et un comportement, c.-à-d. des informations qu'un objet connaît sur lui-même et des actions qu'il
peut exécuter. L'état d'un objet BonCommande (qu'il connaît) inclut l'utilisateur qui l'a envoyé, la date et l'heure de création
et s'il est marqué comme important. Le comportement d'un objet BonCommande (ce qu'il peut exécuter) inclut le contrôle
d'inventaire, l'expédition d'un produit ou la notification un client.
Une classe peut contenir des variables et des méthodes. Les variables sont utilisées pour spécifier l'état d'un objet, tel que le
Name ou le Type de l'objet. Ces variables sont associées à une classe dont ils sont membres. Par conséquent, ils sont
communément référencés en tant que variables de membre. Les méthodes sont utilisées pour contrôler le comportement, tel
que getOtherQuotes ou copyLineItems.
Une interface est semblable à une classe dans laquelle aucune méthode n'a été mise en oeuvre. Les signatures des méthodes
sont présentes, mais le corps de chaque méthode est vide. Pour utiliser une interface, une autre classe doit la mettre en oeuvre
en fournissant un corps pour toutes les méthodes incluses dans l'interface.
Pour des informations générales sur les classes, les objets et les interfaces, reportez-vous à
http://java.sun.com/docs/books/tutorial/java/concepts/index.html
Définition de classes Apex
Dans le langage Apex, vous pouvez définir des classes de niveau supérieur (également appelées classes externes), ainsi que des
classes internes, c.-à-d. une classe définie dans une autre classe. Vous pouvez avoir des classes internes sur un seul niveau. Par
exemple :
public class myOuterClass {
// Additional myOuterClass code here
class myInnerClass {
// myInnerClass code here
}
}
Pour définir une classe, spécifiez les éléments suivants :
1. Modificateurs d'accès :
•
•
Vous devez utiliser l'un des modificateurs d'accès (tels que public ou global) dans la déclaration en tant que classe
de niveau supérieur.
Il n'est pas nécessaire d'utiliser un modificateur d'accès dans la déclaration d'une classe interne.
2. Des modificateurs de définition facultatifs (tels que virtual, abstract, etc.).
3. Obligatoire : Le mot clé class suivi du nom de la classe.
4. Des extensions et/ou des mises en oeuvre facultatives.
Classes, objets et interfaces
salesforce | Définition de classes Apex | 126
Utilisez la syntaxe suivante pour définir des classes :
private | public | global
[virtual | abstract | with sharing | without sharing | (none)]
class ClassName [implements InterfaceNameList | (none)] [extends ClassName | (none)]
{
// The body of the class
}
•
•
•
•
•
•
Le modificateur d'accès private déclare si cette classe est connue uniquement localement, c.-à-d. par cette section du
code seulement. Il correspond à l'accès par défaut pour les classes internes. Par conséquent, si vous ne spécifiez aucun
modificateur d'accès pour une classe interne, il est considéré comme private. Ce mot clé peut être utilisé uniquement
avec des classes internes.
Le modificateur d'accès public déclare si cette classe est visible dans votre application ou espace de noms.
Le modificateur d'accès global déclare si cette classe est connue partout par l'ensemble du code Apex. Toutes les classes
qui contiennent des méthodes définies avec le mot clé webService doivent être déclarées global. Si une méthode ou
une classe interne est déclarée global, la classe externe de niveau supérieur doit également être définie comme global.
Les mots clés with sharing et without sharing spécifient le mode de partage de cette classe. Pour plus d'informations,
reportez-vous à Utilisation des mots clés with sharing ou without sharing à la page 156.
Le modificateur de définition virtual déclare si cette classe autorise l'extension et les remplacements. Vous ne pouvez
pas remplacer une méthode par le mot clé override si la classe n'a pas été définie comme virtual.
Le modificateur de définition abstract déclare si cette classe contient des méthodes abstraites, c.-à-d. des méthodes
dont seule la signature est déclarée et sans corps défini.
Remarque:
•
•
•
Vous ne pouvez pas ajouter une méthode abstraite à une classe globale une fois la classe chargée dans une version
de package Géré-Publié.
Si la classe du package Géré-Publié est virtuelle, la méthode que vous pouvez lui ajouter doit également être
virtuelle et avoir une mise en oeuvre.
Vous ne pouvez pas remplacer une méthode virtuelle publique ou protégée d'une classe globale dans un package
géré-installé.
Pour plus d'informations sur les packages gérés, reportez-vous à Développement de code Apex dans des packages
gérés à la page 280.
Une classe peut mettre en oeuvre plusieurs interfaces, mais uniquement étendre une classe existante. Cette restriction signifie
que le langage Apex ne prend pas en charge l'héritage multiple. Les noms d'interface dans les listes sont séparés par des virgules.
Pour plus d'informations sur les interfaces, reportez-vous à Interfaces et extension de classes à la page 147.
Pour plus d'informations sur les modificateurs d'accès de méthode et de variable, reportez-vous à Modificateurs d'accès à la
page 138.
Classes, objets et interfaces
salesforce | Exemple de classe étendue | 127
Exemple de classe étendue
L'exemple ci-dessous présente une classe étendue, avec toutes les fonctionnalités des classes Apex. Les mots clés et les concepts
présentés dans l'exemple sont expliqués en détail dans ce chapitre.
// Top-level (outer) class must be public or global (usually public unless they contain
// a Web Service, then they must be global)
public class OuterClass {
// Static final variable (constant) – outer class level only
private static final Integer MY_INT;
// Non-final static variable - use this to communicate state across triggers
// within a single request)
public static String sharedState;
// Static method - outer class level only
public static Integer getInt() { return MY_INT; }
// Static initialization (can be included where the variable is defined)
static {
MY_INT = 2;
}
// Member variable for outer class
private final String m;
// Instance initialization block - can be done where the variable is declared,
// or in a constructor
{
m = 'a';
}
// Because no constructor is explicitly defined in this outer class, an implicit,
// no-argument, public constructor exists
Classes, objets et interfaces
salesforce | Exemple de classe étendue | 128
// Inner interface
public virtual interface MyInterface {
// No access modifier is necessary for interface methods - these are always
// public or global depending on the interface visibility
void myMethod();
}
// Interface extension
interface MySecondInterface extends MyInterface {
Integer method2(Integer i);
}
// Inner class - because it is virtual it can be extended.
// This class implements an interface that, in turn, extends another interface.
// Consequently the class must implement all methods.
public virtual class InnerClass implements MySecondInterface {
// Inner member variables
private final String s;
private final String s2;
// Inner instance initialization block (this code could be located above)
{
this.s = 'x';
}
// Inline initialization (happens after the block above executes)
private final Integer i = s.length();
// Explicit no argument constructor
InnerClass() {
Classes, objets et interfaces
salesforce | Exemple de classe étendue | 129
// This invokes another constructor that is defined later
this('none');
}
// Constructor that assigns a final variable value
public InnerClass(String s2) {
this.s2 = s2;
}
// Instance method that implements a method from MyInterface.
// Because it is declared virtual it can be overridden by a subclass.
public virtual void myMethod() { /* does nothing */ }
// Implementation of the second interface method above.
// This method references member variables (with and without the "this" prefix)
public Integer method2(Integer i) { return this.i + s.length(); }
}
// Abstract class (that subclasses the class above). No constructor is needed since
// parent class has a no-argument constructor
public abstract class AbstractChildClass extends InnerClass {
// Override the parent class method with this signature.
// Must use the override keyword
public override void myMethod() { /* do something else */ }
// Same name as parent class method, but different signature.
// This is a different method (displaying polymorphism) so it does not need
// to use the override keyword
protected void method2() {}
// Abstract method - subclasses of this class must implement this method
abstract Integer abstractMethod();
}
Classes, objets et interfaces
salesforce | Exemple de classe étendue | 130
// Complete the abstract class by implementing its abstract method
public class ConcreteChildClass extends AbstractChildClass {
// Here we expand the visibility of the parent method - note that visibility
// cannot be restricted by a sub-class
public override Integer abstractMethod() { return 5; }
}
// A second sub-class of the original InnerClass
public class AnotherChildClass extends InnerClass {
AnotherChildClass(String s) {
// Explicitly invoke a different super constructor than one with no arguments
super(s);
}
}
// Exception inner class
public virtual class MyException extends Exception {
// Exception class member variable
public Double d;
// Exception class constructor
MyException(Double d) {
this.d = d;
}
// Exception class method, marked as protected
protected void doIt() {}
}
// Exception classes can be abstract and implement interfaces
public abstract class MySecondException extends Exception implements MyInterface {
}
Classes, objets et interfaces
salesforce | Exemple de classe étendue | 131
}
Cet exemple de code illustre :
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
La définition d'une classe de niveau supérieur (également appelée classe externe)
Des variables statiques et des méthodes statiques dans la classe de niveau supérieur, ainsi que des blocs de code d'initialisation
statiques
Des variables et des méthodes de membre pour la classe de niveau supérieur
Des classes sans constructeur défini par l'utilisateur ; elles ont un constructeur implicite, sans argument
Une définition d'interface dans la classe de niveau supérieur
Une interface qui étend une autre interface
Des définitions de classe interne (d'un niveau) avec une classe de niveau supérieur
Une classe qui met en oeuvre une interface (et par conséquent sa sous-interface associée) en implémentant des versions
publiques de méthodes de signature
Une définition et une invocation de constructeur de classe interne
Une variable de membre de classe interne et une référence à cette classe en utilisant le mot clé this (sans argument)
Un constructeur de classe interne qui utilise le mot clé this (sans argument) pour invoquer un constructeur différent
Un code d'initialisation hors des constructeurs ; les deux variables where sont définies, ainsi que des blocs anonymes entre
accolades ({}). Notez qu'ils exécutent chaque construction dans l'ordre dans lequel ils s'affichent dans le fichier, comme
avec Java.
Extension de classe et une classe abstraite
Des méthodes qui remplacent des méthodes de classe de base (qui doivent être déclarées sur virtual)
Le mot clé override pour des méthodes qui remplacent des méthodes de sous-classe
Des méthodes abstraites et leur mise en oeuvre par des sous-classes concrètes
Le modificateur d'accès protected
Des exceptions en temps qu'objets de première classe, avec des membres, des méthodes et des constructeurs
Cet exemple montre comment la classe ci-dessus peut être appelée par un autre code Apex :
// Construct an instance of an inner concrete class, with a user-defined constructor
OuterClass.InnerClass ic = new OuterClass.InnerClass('x');
// Call user-defined methods in the class
System.assertEquals(2, ic.method2(1));
// Define a variable with an interface data type, and assign it a value that is of
// a type that implements that interface
OuterClass.MyInterface mi = ic;
// Use instanceof and casting as usual
OuterClass.InnerClass ic2 = mi instanceof OuterClass.InnerClass ?
Classes, objets et interfaces
salesforce | Déclaration de variables de classe | 132
(OuterClass.InnerClass)mi : null;
System.assert(ic2 != null);
// Construct the outer type
OuterClass o = new OuterClass();
System.assertEquals(2, OuterClass.getInt());
// Construct instances of abstract class children
System.assertEquals(5, new OuterClass.ConcreteChildClass().abstractMethod());
// Illegal - cannot construct an abstract class
// new OuterClass.AbstractChildClass();
// Illegal – cannot access a static method through an instance
// o.getInt();
// Illegal - cannot call protected method externally
// new OuterClass.ConcreteChildClass().method2();
Cet exemple de code illustre :
•
•
•
•
La construction de la classe externe
La construction d'une classe interne et la déclaration d'un type d'interface interne
Une variable déclarée en tant que type d'interface peut se voir attribuer une instance d'une classe qui met en oeuvre cette
interface
La conversion d'une variable d'interface en un type de classe qui met en oeuvre cette interface (après vérification en utilisant
l'opérateur instanceof)
Déclaration de variables de classe
Pour déclarer une variable, spécifiez les éléments suivants :
•
•
•
•
Facultatif : Des modificateurs, tels que public ou final, ainsi que static.
Obligatoire : Le type de données de la variable, tel que String ou Boolean.
Obligatoire : Le nom de la variable.
Facultatif : La valeur de la variable.
Classes, objets et interfaces
salesforce | Définition de méthodes de classe | 133
Utilisez la syntaxe suivante lors de la définition d'une variable :
[public | private | protected | global | final] [static] data_type variable_name
[= value]
Par exemple :
private static final Integer MY_INT;
private final Integer i = 1;
Définition de méthodes de classe
Pour définir une méthode, spécifiez les éléments suivants :
Facultatif : Des modificateurs, tels que public ou protected.
Obligatoire : Le type de données de la valeur renvoyé par la méthode, tel que String ou Integer. Utilisez void si la méthode
ne renvoie aucune valeur.
Obligatoire : Une liste de paramètres d'entrée pour la méthode, séparés par des virgules, chacun précédé de son type de
données, et entre parenthèses (). En l'absence de paramètre, utilisez un ensemble de parenthèses vides. Une méthode ne
peut inclure que 32 paramètres d'entrée.
Obligatoire : Le corps de la méthode, entre accolades {}. Tout le code de la méthode, y compris les déclarations de variables
locales, est inclus ici.
•
•
•
•
Utilisez la syntaxe suivante lors de la définition d'une méthode :
(public | private | protected | global ) [override] [static] data_type method_name
(input parameters)
{
// The body of the method
}
Remarque: Vous pouvez utiliser override uniquement pour remplacer des méthodes dans des classes qui ont été
définies comme virtual.
Par exemple :
public static Integer getInt() {
return MY_INT;
}
Comme dans Java, les méthodes qui renvoient des valeurs peuvent également être exécutées en tant qu'instruction si leurs
résultats ne sont pas attribués à une autre variable.
Notez les points suivants pour les méthodes définies par les utilisateurs :
Classes, objets et interfaces
•
•
•
•
•
salesforce | Définition de méthodes de classe | 134
Elles peuvent être utilisées partout où les méthodes système sont utilisées.
Elles peuvent être récursives.
Elles peuvent entraîner des effets secondaires, tels que des instructions DML insert qui initialisent des ID d'enregistrements
sObject. Reportez-vous à Opérations DML (langage de manipulation de données) Apex à la page 327.
Elles peuvent se référencer elles-mêmes ou référencer des méthodes définies ultérieurement dans la même classe ou un
bloc anonyme. Le code Apex analyse les méthodes en deux phases, par conséquent les méthodes anticipées ne sont pas
requises.
Elles peuvent être polymorphiques. Par exemple une méthode nommée foo peut être mise en oeuvre de deux façons, une
avec un seul paramètre Integer et une autre avec deux paramètres Integer. Selon que la méthode est appelée avec un ou
deux paramètres Integer, l'analyseur Apex sélectionne la mise en oeuvre appropriée à exécuter. Si l'analyseur ne trouve pas
de correspondance exacte, il recherche une correspondance approximative en utilisant des règles de coercition de type. Pour
plus d'informations sur la conversion des données, reportez-vous à Compréhension des règles de conversion à la page 55.
Remarque: Si l'analyseur trouve plusieurs correspondances approximatives, une erreur d'analyse est générée.
•
Lors de l'utilisation de méthodes void avec des effets secondaires, les méthodes définies par l'utilisateur sont généralement
exécutées en tant qu'instructions de procédure autonomes dans un code Apex. Par exemple :
System.debug('Here is a note for the log.');
•
Elles peuvent inclure des instructions dans lesquelles les valeurs renvoyées sont exécutées en tant qu'instruction si leurs
résultats ne sont pas attribués à une autre variable. Ce comportement est identique dans Java.
Transmission d'arguments de méthode par valeur
Dans le langage Apex, tous les arguments de type de données primitifs, tels que Nombre entier ou Chaîne, sont transmis en
méthodes par valeur. Cela signifie que toute modification apportée aux arguments existe uniquement dans la portée de la
méthode. Lorsque la méthode retourne, les modifications de l'argument sont perdues.
Les arguments de type de données non primitifs, tels que sObjects, sont également transmis en méthodes par valeur. Cela
signifie que lorsque la méthode retourne, l'argument passé référence toujours le même objet qu'avant l'appel de la méthode et
ne peut pas être modifié pour pointer vers un autre objet. Cependant, les valeurs des champs de l'objet peuvent être modifiées
dans la méthode.
Dans les exemples suivants, des arguments de type de données primitif et non primitif sont transmis dans des méthodes.
Exemple : Transmission d'arguments de type de données primitif
Cet exemple montre comment un argument primitif de type String est transmis par valeur à une autre méthode. Dans cet
exemple, la méthode debugStatusMessage crée une variable String, msg et lui attribue une valeur. Elle transmet ensuite
cette variable en tant qu'argument à une autre méthode, qui modifie la valeur String. Cependant, comme String est un type
primitif, il est transmis par valeur. Lors du renvoi de la méthode, la valeur de la variable d'origine msg est inchangée. Une
instruction d'assertion vérifie que la valeur de msg correspond toujours à l'ancienne valeur.
public class PassPrimitiveTypeExample {
public static void debugStatusMessage() {
String msg = 'Original value';
processString(msg);
// The value of the msg variable didn't
Classes, objets et interfaces
salesforce | Définition de méthodes de classe | 135
// change; it is still the old value.
System.assertEquals(msg, 'Original value');
}
public static void processString(String s) {
s = 'Modified value';
}
}
Exemple : Transmission d'arguments de type de données non primitif
Cet exemple montre comment un argument List est transmis par valeur à une autre méthode et peut être modifié. Il indique
également que l'argument List ne peut pas être modifié pour pointer vers un autre objet List. Pour commencer, la méthode
createTemperatureHistory crée une variable, fillMe, qui est une liste de nombres entiers, et la transmet à une méthode.
La méthode appelée renseigne cette liste avec des Integer qui représentent des valeurs de température arrondies. Lors du renvoi
de la méthode, une assertion vérifie que le contenu de la variable List d'origine a changé et qu'elle contient maintenant cinq
valeurs. Ensuite, l'exemple crée une deuxième variable List, createMe, et la transmet à une autre méthode. La méthode
appelée attribue l'argument transmis à une nouvelle liste qui contient de nouvelles valeurs Integer. Lors du renvoi de la méthode,
la variable createMe d'origine ne pointe pas vers la nouvelle liste, mais pointe toujours vers la liste d'origine, qui est vide. Une
assertion vérifie que createMe ne contient aucune valeur.
public class PassNonPrimitiveTypeExample {
public static void createTemperatureHistory() {
List<Integer> fillMe = new List<Integer>();
reference(fillMe);
// The list is modified and contains five items
// as expected.
System.assertEquals(fillMe.size(),5);
List<Integer> createMe = new List<Integer>();
referenceNew(createMe);
// The list is not modified because it still points
// to the original list, not the new list
// that the method created.
System.assertEquals(createMe.size(),0);
}
public static void reference(List<Integer> m) {
Classes, objets et interfaces
salesforce | Utilisation de constructeurs | 136
// Add rounded temperatures for the last five days.
m.add(70);
m.add(68);
m.add(75);
m.add(80);
m.add(82);
}
public static void referenceNew(List<Integer> m) {
// Assign argument to a new List of
// five temperature values.
m = new List<Integer>{55, 59, 62, 60, 63};
}
}
Utilisation de constructeurs
Un constructeur est un code invoqué lors de la création d'un objet à partir du plan directeur de la classe. Il n'est pas nécessaire
d'écrire un constructeur pour chaque classe. Si une classe n'a pas de constructeur défini par l'utilisateur, un constructeur public,
implicite et sans argument est utilisé.
La syntaxe d'un constructeur est similaire à une méthode, mais elle est différente de la définition d'une méthode, car elle n'a
jamais de type de renvoi explicite et n'est pas héritée par l'objet créé à partir d'elle.
Après avoir écrit le constructeur pour une classe, vous devez utiliser le mot clé new pour instancier un objet à partir de cette
classe en utilisant ce constructeur. Par exemple, en utilisant la classe suivante :
public class TestObject {
// The no argument constructor
public TestObject() {
// more code here
}
}
Un nouvel objet de ce type peut être instancié avec le code suivant :
TestObject myTest = new TestObject();
Classes, objets et interfaces
salesforce | Utilisation de constructeurs | 137
Si vous écrivez un constructeur qui prend des arguments, vous pouvez ensuite l'utiliser pour créer un objet utilisant ces arguments.
Si vous créez un constructeur qui prend des arguments, mais souhaitez toutefois utiliser un constructeur sans argument, vous
devez en inclure un dans votre code. Une fois un constructeur créé pour une classe, vous n'avez plus accès au constructeur
public sans argument par défaut. Vous ne devez créer le vôtre.
Dans le langage Apex, un constructeur peut être surchargé, c.-à-d. que plusieurs constructeurs peuvent exister pour une classe,
chacun avec des paramètres différents. L'exemple suivant illustre une classe avec deux constructeurs : un sans argument et un
autre qui prend un simple argument Integer. Il illustre également comment un constructeur appelle l'autre constructeur en
utilisant la syntaxe this(...), également appelée chaînage des constructeurs.
public class TestObject2 {
private static final Integer DEFAULT_SIZE = 10;
Integer size;
//Constructor with no arguments
public TestObject2() {
this(DEFAULT_SIZE); // Using this(...) calls the one argument constructor
}
// Constructor with one argument
public TestObject2(Integer ObjectSize) {
size = ObjectSize;
}
}
Les nouveaux objets de ce type peuvent être instanciés avec le code suivant :
TestObject2 myObject1 = new TestObject2(42);
TestObject2 myObject2 = new TestObject2();
Chaque constructeur que vous créez pour une classe doit avoir une liste d'arguments différente. Dans l'exemple suivant, tous
les constructeurs sont possibles :
public class Leads {
// First a no-argument constructor
public Leads () {}
Classes, objets et interfaces
salesforce | Modificateurs d'accès | 138
// A constructor with one argument
public Leads (Boolean call) {}
// A constructor with two arguments
public Leads (String email, Boolean call) {}
// Though this constructor has the same arguments as the
// one above, they are in a different order, so this is legal
public Leads (Boolean call, String email) {}
}
Lorsque vous définissez une nouvelle classe, vous définissez un nouveau type de données. Vous pouvez utiliser un nom de
classe partout où vous pouvez utiliser des noms de type de données, tels que String, Boolean ou Account. Si vous définissez
une variable dont le type est une classe, tout objet que vous lui attribuez doit être une instance de cette classe ou sous-classe.
Modificateurs d'accès
Le langage Apex permet d'utiliser les modificateurs d'accès private, protected, public et global lors de la définition
de méthodes et de variables.
Des déclencheurs et des blocs anonymes peuvent également utiliser ces modificateurs d'accès, mais ils ne sont pas aussi utiles
dans des parties de code Apex plus petites. Par exemple, la déclaration d'une méthode en tant que global dans un bloc
anonyme ne vous permet pas de l'appeler de l'extérieur de ce code.
Pour plus d'informations sur les modificateurs d'accès de classe, reportez-vous à Définition de classes Apex à la page 125.
Remarque: Les méthodes d'interface n'ont pas de modificateur d'accès. Elles sont toujours globales. Pour plus
d'informations, reportez-vous à Interfaces et extension de classes à la page 147.
Par défaut, une méthode ou une variable est visible uniquement par le code Apex dans la classe de définition. Vous devez
explicitement spécifier une méthode ou une variable en tant que publique afin qu'elle soit disponible pour d'autres classes dans
le même espace de noms d'application (reportez-vous à Préfixe d'espace de noms). Vous pouvez modifier le niveau de visibilité
en utilisant les modificateurs d'accès suivants :
private
Correspond au modificateur par défaut, ce qui signifie que la méthode ou variable est accessible uniquement dans la
classe Apex dans laquelle elle est définie. Si vous ne spécifiez pas de modificateur d'accès, la méthode ou la variable est
private.
protected
Ce modificateur signifie que la méthode ou la variable est visible de toutes les classes internes dans la classe Apex de
définition. Vous pouvez utiliser ce modificateur d'accès uniquement pour des méthodes d'instance et des variables de
membre. Notez qu'il est plus permissif que le paramètre (privé) par défaut, semblable à Java.
Classes, objets et interfaces
salesforce | Statique et instance | 139
public
Ce modificateur signifie que la méthode ou la variable peut être utilisée par n'importe quel code Apex dans cette application
ou cet espace de noms.
Remarque: Dans le langage Apex, le modificateur d'accès public est différent de celui dans Java. Il est destiné
à décourager la liaison d'applications, afin de conserver le code de chaque application séparé. Dans le langage
Apex, si vous souhaitez rendre un élément public comme dans Java, utilisez le modificateur d'accès global.
global
Ce modificateur signifie que la méthode ou la variable peut être utilisée par n'importe quel code Apex qui a accès à la
classe, pas seulement par le code Apex dans la même application. Ce modificateur d'accès doit être utilisé pour n'importe
quelle méthode qui doit être référencée hors de l'application, dans l'API SOAP ou par un autre code Apex. Si vous
déclarez une méthode ou une variable comme global, vous devez également déclarer la classe qui le contient comme
global.
Remarque: Nous recommandons de n'utiliser le modificateur d'accès global que rarement, ou jamais. Les
dépendances inter-applications sont difficiles à gérer.
Pour utiliser le modificateur d'accès private, protected, public ou global, appliquez la syntaxe suivante :
[(none)|private|protected|public|global] declaration
Par exemple :
private string s1 = '1';
public string gets1() {
return this.s1;
}
Statique et instance
Dans le langage Apex, vous pouvez avoir des méthodes, des variables et un code d'initialisation statiques. Les classes Apex ne
peuvent pas être statiques. Vous pouvez également avoir des méthodes, des membres de variables et un code d'initialisation
d'instance (sans modificateur), les variables locales :
•
•
•
Les méthodes, les variables ou le code d'initialisation statiques sont associés à une classe et sont autorisés dans des classes
externes. Lorsque vous déclarez une méthode ou une variable en tant que static, elle est initialisée une seule fois au
chargement de la classe. Les variables statiques ne sont pas transmises avec l'état de la vue pour une page Visualforce.
Les méthodes, les variables de membre et le code d'initialisation d'instance sont associés à un objet particulier et n'ont pas
de modificateur de définition. Lorsque vous déclarez des méthodes, des variables de membre ou un code d'initialisation
d'instance, une instance de cet élément est créée avec chaque objet instancié à partir de la classe.
Les variables locales sont associées au bloc de code dans lequel elles sont déclarées. Toutes les variables locales doivent être
initialisées avant leur utilisation.
Classes, objets et interfaces
salesforce | Statique et instance | 140
L'exemple suivant présente une variable locale dont la portée est la durée du bloc de code if :
Boolean myCondition = true;
if (myCondition) {
integer localVariable = 10;
}
Utilisation de méthodes et de variables statiques
Vous pouvez utiliser des méthodes et des variables statiques uniquement avec des classes externes. Les classes internes n'ont
pas de méthodes ou de variables statiques. Une méthode ou une variable statique ne nécessite pas une instance de la classe
pour être exécutée.
Toutes les variables de membre statiques dans une classe sont initialisées avant la création de n'importe quel objet de la classe.
Cela inclut tous les blocs de code d'initialisation statiques. Elles sont toutes exécutées dans l'ordre dans lequel elles s'affichent
dans la classe.
Les méthodes statiques sont généralement utilisées en tant que méthodes utilitaires et ne dépendent jamais d'une valeur de
variable de membre d'instance particulière. Une méthode statique est associée uniquement à une classe. Par conséquent, elle
ne peut accéder à aucune valeur de variable de membre d'instance de cette classe.
Les variables statiques sont statiques uniquement dans la portée de la requête. Elles ne sont pas statiques dans l'ensemble du
serveur ni dans l'organisation entière.
Utilisez des variables statiques pour stocker les informations qui sont partagées aux confins de la classe. Toutes les instances
de la même classe partagent une copie unique de variables statiques. Par exemple, tous les déclencheurs qui sont engendrés
par la même requête peuvent communiquer ensemble en affichant et en mettant à jour des variables statiques dans une classe
associée. Un déclencheur récursif peut utiliser la valeur d'une variable de classe afin de déterminer quand il doit quitter la
récursion.
Prenons la classe suivante :
public class p {
public static boolean firstRun = true;
}
Un déclencheur qui utilise cette classe peut ensuite échouer de façon sélective à sa première exécution :
trigger t1 on Account (before delete, after delete, after undelete) {
if(Trigger.isBefore){
if(Trigger.isDelete){
if(p.firstRun){
Trigger.old[0].addError('Before Account Delete Error');
p.firstRun=false;
}
Classes, objets et interfaces
salesforce | Statique et instance | 141
}
}
}
Les variables statiques de classe ne peuvent pas être accédées via une instance de cette classe. Par conséquent, si la classe C a
une variable statique S et que x est une instance de C, x.S n'est pas une expression légale.
Cela est vrai pour les méthodes d'instance : si M() est une méthode statique, x.M() n'est pas légal. À la place, votre code doit
se référer à ces identificateurs statiques en utilisant la classe : C.S et C.M().
Si une variable locale porte le même nom que la classe, ces méthodes et variables statiques sont masquées.
Les classes internes se comportent comme des classes internes Java statiques, mais ne nécessitent pas le mot clé static. Les
classes internes peuvent avoir des variables de membre d'instance comme des classes externes, mais il n'existe aucun pointeur
implicite vers une instance de la classe externe (utilisant le mot clé this).
Remarque: Pour un code Apex enregistré en utilisant l'API version 20.0 ou antérieure de Salesforce.com, si un appel
API active un déclencheur, le lot de 200 enregistrements à traiter est divisé en lots de 100 enregistrements. Pour un
code Apex enregistré en utilisant l'API versions 21.0 et supérieures de Salesforce.com, les lots d'API ne sont pas
divisés. Notez que les valeurs de variable statique sont réinitialisées entre les lots, contrairement aux limitations du
gouverneur. N'utilisez pas des variables statiques pour suivre les informations d'état entre les lots.
Utilisation de méthodes et de variables d'instance
Les méthodes et les variables de membre d'instance sont utilisées par une instance d'une classe, c.-à-d. par un objet. Les
variables de membre d'instance sont déclarées dans une classe, mais pas dans une méthode. Généralement, les méthodes
d'instance utilisent des variables de membre d'instance pour affecter le comportement de la méthode.
Supposons que vous souhaitez une classe qui collecte deux points dimensionnels pour les tracer sur un graphique. Elle est
illustrée dans la classe squelette ci-dessous, qui utilise des variables de membre pour contenir la liste des points et une classe
interne afin de gérer la liste de points bidimensionnelle.
public class Plotter {
// This inner class manages the points
class Point {
Double x;
Double y;
Point(Double x, Double y) {
this.x = x;
this.y = y;
}
Double getXCoordinate() {
Classes, objets et interfaces
salesforce | Statique et instance | 142
return x;
}
Double getYCoordinate() {
return y;
}
}
List<Point> points = new List<Point>();
public void plot(Double x, Double y) {
points.add(new Point(x, y));
}
// The following method takes the list of points and does something with them
public void render() {
}
}
Utilisation d'un code d'initialisation
Un code d'initialisation d'instance est un bloc de code sous le format suivant qui est défini dans une classe :
{
//code body
}
Le code d'initialisation d'instance est une classe exécutée chaque fois qu'un objet est instancié à partir de cette classe. Ces blocs
de code sont exécutés avant le constructeur.
Si vous ne souhaitez pas écrire votre propre constructeur pour une classe, vous pouvez utiliser un bloc de code d'initialisation
d'instance afin d'initialiser des variables d'instance. Dans la plupart des cas, vous devez cependant appliquer à la variable une
valeur par défaut ou utiliser le corps d'un constructeur pour effectuer l'initialisation et ne pas utiliser le code d'initialisation
d'instance.
Classes, objets et interfaces
salesforce | Statique et instance | 143
Un code d'initialisation statique est un bloc de code précédé du mot clé static:
static {
//code body
}
Semblable à un autre code statique, un bloc de code d'initialisation statique est initialisé une seule fois lors de la première
utilisation de la classe.
Une classe peut inclure n'importe quel nombre de blocs de code d'initialisation d'instance ou statique. Il peuvent figurer
n'importe où dans le corps du code. Les blocs de code sont exécutés dans l'ordre dans lequel ils s'affichent dans le fichier, de
la même façon que dans Java.
Vous pouvez utiliser un code d'initialisation statique pour initialiser des variables finales statiques et déclarer toute information
statique, notamment un mappage de valeurs. Par exemple :
public class MyClass {
class RGB {
Integer red;
Integer green;
Integer blue;
RGB(Integer red, Integer green, Integer blue) {
this.red = red;
this.green = green;
this.blue = blue;
}
}
static Map<String, RGB> colorMap = new Map<String, RGB>();
static {
colorMap.put('red', new RGB(255, 0, 0));
colorMap.put('cyan', new RGB(0, 255, 255));
Classes, objets et interfaces
salesforce | Propriétés Apex | 144
colorMap.put('magenta', new RGB(255, 0, 255));
}
}
Propriétés Apex
Une propriété Apex est semblable à une variable. Vous pouvez toutefois effectuer des opérations supplémentaires dans votre
code sur une valeur de propriété avant qu'elle soit accédée ou renvoyée. Les propriétés peuvent être utilisées de différentes
façons : elles peuvent valider des données avant d'effectuer une modification, entraîner une action lors de la modification de
données (par exemple modifier la valeur d'autres variables de membre) ou exposer des données récupérées à partir d'autres
sources (par exemple une autre classe).
Les définitions de propriété comprennent un ou deux blocs de code représentant un accesseur get et un accesseur set :
Le code d'un accesseur get est exécuté lors de la lecture de la propriété.
Le code d'un accesseur set est exécuté lors de l'attribution d'une nouvelle valeur à la propriété.
•
•
Une propriété contenant uniquement un accesseur get est considérée en lecture seule. Une propriété contenant uniquement
un accesseur set est considérée en écriture seule. Une propriété avec les deux accesseurs est en lecture-écriture.
Pour déclarer une propriété, utilisez la syntaxe suivante dans le corps d'une classe :
Public class BasicClass {
// Property declaration
access_modifier return_type property_name {
get {
//Get accessor code block
}
set {
//Set accessor code block
}
}
}
Où :
•
•
•
access_modifier correspond au modificateur d'accès de la propriété. Tous les modificateurs applicables à des variables
peuvent également être appliqués à des propriétés. Ils comprennent : public, private, global, protected, static,
virtual, abstract, override et transient. Pour plus d'informations sur les modificateurs d'accès, reportez-vous
à Modificateurs d'accès à la page 138.
return_type correspond au type de la propriété, tel que Integer, Double, sObject, etc. Pour plus d'informations,
reportez-vous à Types de données à la page 29.
property_name correspond au nom de la propriété.
Classes, objets et interfaces
salesforce | Propriétés Apex | 145
Par exemple, la classe suivante définit une propriété nommée prop. La propriété est publique. Elle renvoie un type de données
Integer.
public class BasicProperty {
public integer prop {
get { return prop; }
set { prop = value; }
}
}
Le segment de code suivant appelle la classe ci-dessus, en exerçant les accesseurs get et set :
BasicProperty bp = new BasicProperty();
bp.prop = 5;
// Calls set accessor
System.assert(bp.prop == 5);
// Calls get accessor
Notez les points suivants :
•
•
•
•
•
•
•
•
Le corps de l'accesseur get est semblable à celui d'une méthode. Il doit renvoyer une valeur de type de propriété. L'exécution
de l'accesseur get est semblable à la lecture de la valeur de la variable.
L'accesseur get doit se terminer par une instruction de renvoi.
Il est préférable que votre accesseur get ne modifie pas l'état de l'objet sur lequel il est défini.
L'accesseur set est semblable à une méthode dont le type de renvoi est void.
Lorsque vous attribuez une valeur à la propriété, l'accesseur set est invoqué avec un argument qui fournit la nouvelle valeur.
Lorsque l'accesseur set est invoqué, le système transmet un argument implicite au setter, appelé value, du même type de
données que la propriété.
Les propriétés ne peuvent pas être définies sur interface.
Les propriétés Apex sont basées sur leurs semblables dans le langage C#, avec les différences suivantes :
◊ Les propriétés fournissent directement un stockage des valeurs. Il n'est pas nécessaire de créer des membres de support
pour stocker les valeurs.
◊ Il est possible de créer des propriétés automatiques dans le langage Apex. Pour plus d'informations, reportez-vous à
Utilisation de propriétés automatiques à la page 145.
Utilisation de propriétés automatiques
Aucun code supplémentaire n'est requis pour les propriétés dans leurs blocs de code d'accesseur get ou set. Vous pouvez à la
place laisser les blocs de code d'accesseur get ou set vides afin de définir une propriété automatique. Les propriétés automatiques
permettent d'écrire un code plus compact, moins difficile à déboguer et à gérer. Elles peuvent être déclarées en lecture seule,
en lecture-écriture ou en écriture seule. L'exemple suivant créé trois propriétés automatiques :
public class AutomaticProperty {
public integer MyReadOnlyProp { get; }
public double MyReadWriteProp { get; set; }
Classes, objets et interfaces
salesforce | Propriétés Apex | 146
public string MyWriteOnlyProp { set; }
}
Le segment de code suivant exerce ces propriétés :
AutomaticProperty ap = new AutomaticProperty();
ap.MyReadOnlyProp = 5;
// This produces a compile error: not writable
ap.MyReadWriteProp = 5;
// No error
System.assert(MyWriteOnlyProp == 5);
// This produces a compile error: not readable
Utilisation de propriétés statiques
Lorsqu'une propriété est déclarée static, les méthodes d'accesseur de la propriété sont exécutées dans un contexte statique.
Cela signifie que les accesseurs n'ont pas accès aux variables de membre non statiques définies dans la classe. L'exemple suivant
crée une classe avec des propriétés statiques et d'instance :
public class StaticProperty {
public static integer StaticMember;
public integer NonStaticMember;
public static integer MyGoodStaticProp {
get{return MyGoodStaticProp;}
}
// The following produces a system error
// public static integer MyBadStaticProp { return NonStaticMember; }
public integer MyGoodNonStaticProp {
get{return NonStaticMember;}
}
}
Le segment de code suivant appelle les propriétés statiques et d'instance :
StaticProperty sp = new StaticProperty();
// The following produces a system error: a static variable cannot be
// accessed through an object instance
// sp.MyGoodStaticProp = 5;
// The following does not produce an error
Classes, objets et interfaces
salesforce | Interfaces et extension de classes | 147
StaticProperty.MyGoodStaticProp = 5;
Utilisation de modificateurs d'accès dans des accesseurs de propriété
Les accesseurs de propriété peuvent être définis avec leurs propres modificateurs d'accès. Si un accesseur inclut son propre
modificateur d'accès, il remplace celui de la propriété. Le modificateur d'accès d'un accesseur individuel doit être plus restrictif
que celui de la propriété. Par exemple, si la propriété est définie comme public, l'accesseur individuel ne peut pas être défini
comme global. La définition de classe suivante présente des exemples supplémentaires :
global virtual class PropertyVisibility {
// X is private for read and public for write
public integer X { private get; set; }
// Y can be globally read but only written within a class
global integer Y { get; public set; }
// Z can be read within the class but only subclasses can set it
public integer Z { get; protected set; }
}
Interfaces et extension de classes
Une interface est semblable à une classe dans laquelle aucune méthode n'a été mise en oeuvre. Les signatures des méthodes
sont présentes, mais le corps de chaque méthode est vide. Pour utiliser une interface, une autre classe doit la mettre en oeuvre
en fournissant un corps pour toutes les méthodes incluses dans l'interface.
Les interfaces peuvent fournir une couche d'abstraction à votre code. Elles séparent les mises en oeuvre spécifiques d'une
méthode de la déclaration de cette méthode. Vous pouvez ainsi avoir plusieurs mises en oeuvre d'une méthode basées sur votre
application spécifique.
La définition d'une interface est semblable à la définition d'une nouvelle classe. Par exemple, une société peut avoir deux types
de bon de commande, un type provenant des clients et un autre provenant des employés. Les deux correspondent à un type
de bon de commande. Supposons que vous avez besoin d'une méthode pour accorder une remise. Le montant de la remise
peut dépendre du type du bon de commande.
Vous pouvez modéliser le concept général d'un bon de commande dans une interface, et avoir des mises en oeuvre spécifiques
pour les clients et pour les employés. L'exemple suivant s'intéresse uniquement à l'aspect de remise d'un bon de commande.
public class PurchaseOrders {
// An interface that defines what a purchase order looks like in general
public interface PurchaseOrder {
// All other functionality excluded
Double discount();
Classes, objets et interfaces
salesforce | Interfaces et extension de classes | 148
}
// One implementation of the interface for customers
public virtual class CustomerPurchaseOrder implements PurchaseOrder {
public virtual Double discount() {
return .05;
// Flat 5% discount
}
}
// Employee purchase order extends Customer purchase order, but with a
// different discount
public class EmployeePurchaseOrder extends CustomerPurchaseOrder{
public
override Double discount() {
return .10;
// It’s worth it being an employee! 10% discount
}
}
}
Notez les points suivants relatifs à l'exemple ci-dessus :
•
•
•
L'interface PurchaseOrder est définie comme prototype général. Les méthodes définies dans une interface n'ont pas de
modificateur d'accès et contiennent uniquement leur signature.
La classe CustomerPurchaseOrder met en oeuvre cette interface. Elle doit par conséquent fournir une définition pour
la méthode discount. Comme dans le langage Java, toute classe qui met en oeuvre une interface doit définir toutes les
méthodes contenues dans l'interface.
La version employé du bon de commande élargit la version client. Une classe étend une autre classe en utilisant le mot clé
extends. Une classe ne peut étendre qu'une seule autre classe, mais elle peut mettre en oeuvre plusieurs interfaces.
Lorsque vous définissez une nouvelle interface, vous définissez un nouveau type de données. Vous pouvez utiliser un nom
d'interface partout où vous pouvez utiliser un autre nom de type de données. Si vous définissez une variable dont le type est
une interface, tout objet que vous lui attribuez doit être une instance de cette classe qui met en oeuvre l'interface, ou un type
de données sous-interface.
Une interface peut étendre une autre interface. Comme pour les classes, lorsqu'une interface étend une autre interface, toutes
les méthodes et les propriétés de l'interface étendue sont disponibles pour l'interface qui étend.
Reportez-vous également à Classes et conversion à la page 170.
Remarque: Vous ne pouvez pas ajouter une méthode globale une fois la classe chargée dans une version de package
Géré-Publié.
Classes, objets et interfaces
salesforce | Itérateurs personnalisés | 149
Itérateurs personnalisés
Un itérateur traverse chaque élément d'une collection. Par exemple, dans une boucle while dans Apex, vous définissez une
condition pour la boucle existante et vous devez fournir le moyen de traverser la collection, c.-à-d. un itérateur. Dans l'exemple
suivant, count est incrémenté de 1 à chaque exécution de la boucle (count++) :
while (count < 11) {
System.debug(count);
count++;
}
En utilisant l'interface Iterator, vous pouvez créer un ensemble d'instructions personnalisées permettant de traverser une
liste via une boucle. Cela est utile pour des données existantes dans des sources extérieures à Salesforce, dont vous définissez
généralement la portée en utilisant une instruction SELECT. Des opérateurs peuvent également être utilisés si vous avez plusieurs
instructions SELECT.
Utilisation d'itérateurs personnalisés
Pour utiliser des itérateurs, vous devez créer une classe Apex qui met en oeuvre l'interface Iterator.
L'interface Iterator inclut les méthodes d'instance suivantes :
Nom
Arguments
Renvoie
Description
hasNext
Boolean
Renvoie true si la collection traversée inclut un autre
élément, sinon renvoie false.
next
N'importe quel type Renvoie l'élément suivant dans la collection.
Toutes les méthodes dans l'interface Iterator doivent être déclarées comme global ou public.
Vous pouvez utiliser un itérateur personnalisé uniquement dans boucle while. Par exemple :
IterableString x = new IterableString('This is a really cool test.');
while(x.hasNext()){
system.debug(x.next());
}
Actuellement, les itérateurs ne sont pas pris en charge dans les boucles for.
Utilisation d'itérateurs personnalisés avec Iterable
Si vous ne souhaitez pas utiliser un itérateur personnalisé avec une liste, mais créer votre propre structure de données, vous
pouvez utiliser l'interface Iterable pour générer la structure.
L'interface Iterator inclut la méthode suivante :
Classes, objets et interfaces
Nom
salesforce | Itérateurs personnalisés | 150
Arguments
iterator
Renvoie
Description
Classe d'itérateur
Renvoie une référence à l'itérateur pour cette interface.
La méthode iterator doit être déclarée global ou public. Elle crée une référence à l'itérateur que vous pouvez ensuite
utiliser pour traverser la structure de données.
Dans l'exemple suivant, un itérateur personnalisé itère via une collection :
global class CustomIterable
implements Iterator<Account>{
List<Account> accs {get; set;}
Integer i {get; set;}
public CustomIterable(){
accs =
[SELECT Id, Name,
NumberOfEmployees
FROM Account
WHERE Name = 'false'];
i = 0;
}
global boolean hasNext(){
if(i >= accs.size()) {
return false;
} else {
return true;
}
}
global Account next(){
// 8 is an arbitrary
// constant in this example
// that represents the
// maximum size of the list.
Classes, objets et interfaces
salesforce | Itérateurs personnalisés | 151
if(i == 8){return null;}
i++;
return accs[i-1];
}
}
Le code ci-dessus est appelé par :
global class foo implements iterable<Account>{
global Iterator<Account> Iterator(){
return new CustomIterable();
}
}
Le code ci-dessous est une tâche par lot qui utilise un itérateur :
global class batchClass implements Database.batchable<Account>{
global Iterable<Account> start(Database.batchableContext info){
return new foo();
}
global void execute(Database.batchableContext info, List<Account> scope){
List<Account> accsToUpdate = new List<Account>();
for(Account a : scope){
a.Name = 'true';
a.NumberOfEmployees = 69;
accsToUpdate.add(a);
}
update accsToUpdate;
}
global void finish(Database.batchableContext info){
}
}
Classes, objets et interfaces
salesforce | Mots clés | 152
Mots clés
Le langage Apex inclut les mots clés suivants :
•
•
•
•
•
•
final
instanceof
super
this
transient
with sharing et without sharing
Utilisation du mot clé final
Vous pouvez utiliser le mot clé final pour modifier des variables.
Une valeur peut être attribuée une seule fois à des variables finales, dans leur déclaration ou dans le code d'initialisation.
Vous devez attribuer une valeur dans l'un de ces emplacements.
Les variables finales statiques peuvent être modifiées dans le code d'initialisation statique ou dans leur définition.
Les variables finales de membre peuvent être modifiées dans des blocs de code d'initialisation, des constructeurs ou avec
d'autres déclarations de variables.
Pour définir une constante, marquez une variable comme static et final (reportez-vous à Constantes à la page 58).
Les variables statiques non finales sont utilisées pour communiquer l'état au niveau de la classe (tel que l'état entre des
déclencheurs). Toutefois, elles ne sont pas partagées entre les requêtes.
Les méthodes et les classes sont finales par défaut. Vous ne pouvez pas utiliser le mot clé final dans la déclaration d'une
classe ou d'une méthode. Cela signifie qu'elles ne peuvent pas être remplacées. Si vous souhaitez remplacer une méthode
ou une classe, utilisez le mot clé virtual.
•
•
•
•
•
•
Utilisation du mot clé instanceof
Si vous souhaitez vérifier à l'exécution si un objet est une instance d'une classe particulière, utilisez le mot clé instanceof.
Le mot clé instanceof peut être utilisé uniquement pour vérifier si le type de cible dans l'expression, à droite du mot clé,
est une alternative viable pour le type d'expression déclaré, à gauche.
Vous pouvez ajouter la vérification ci-dessous à la classe Report dans classes et exemple de conversion avant de reconvertir
l'élément en objet CustomReport.
If (Reports.get(0) instanceof CustomReport) {
// Can safely cast it back to a custom report object
CustomReport c = (CustomReport) Reports.get(0);
} Else {
// Do something with the non-custom-report.
}
Classes, objets et interfaces
salesforce | Utilisation du mot clé super | 153
Utilisation du mot clé super
Le mot clé super peut être utilisé par des classes qui sont étendues par des classes virtuelles ou abstraites. En utilisant super,
vous pouvez remplacer des constructeurs et des méthodes de la classe parente.
Par exemple, si vous avez la classe virtuelle suivante :
public virtual class SuperClass {
public String mySalutation;
public String myFirstName;
public String myLastName;
public SuperClass() {
mySalutation = 'Mr.';
myFirstName = 'Carl';
myLastName = 'Vonderburg';
}
public SuperClass(String salutation, String firstName, String lastName) {
mySalutation = salutation;
myFirstName = firstName;
myLastName = lastName;
}
public virtual void printName() {
System.debug('My name is ' + mySalutation + myLastName);
}
public virtual String getFirstName() {
return myFirstName;
}
}
Classes, objets et interfaces
salesforce | Utilisation du mot clé this | 154
Vous pouvez créer la classe suivante qui étend Superclass et remplace sa méthode printName :
public class Subclass extends Superclass {
public override void printName() {
super.printName();
System.debug('But you can call me ' + super.getFirstName());
}
}
La sortie attendue lors de l'appel de Subclass.printName est My name is Mr. Vonderburg. But you can
call me Carl.
Vous pouvez également utiliser super pour appeler des constructeurs. Ajoutez le constructeur suivant à SubClass :
public Subclass() {
super('Madam', 'Brenda', 'Clapentrap');
}
La sortie attendue de Subclass.printName est maintenant My name is Madam Clapentrap. But you can
call me Brenda.
Meilleures pratiques d'utilisation du mot clé super
Seules les classes étendues à partir de classes virtual ou abstract peuvent utiliser super.
Vous pouvez utiliser super uniquement dans des méthodes désignées par le mot-clé override.
•
•
Utilisation du mot clé this
Il existe deux façons d'utiliser le mot clé this.
Vous pouvez utiliser le mot clé this en notation pointée, sans parenthèse, pour représenter l'instance actuelle de la classe dans
laquelle il s'affiche. Utilisez ce format du mot clé this pour accéder à des variables et des méthodes d'instance. Par exemple
:
public class myTestThis {
string s;
{
this.s = 'TestString';
}
}
Dans l'exemple ci-dessus, la classe myTestThis déclare une variable d'instance s. Le code d'initialisation renseigne la variable
en utilisant le mot clé this.
Classes, objets et interfaces
salesforce | Utilisation du mot clé transient | 155
Vous pouvez également utiliser le mot clé this pour effectuer un chaînage de constructeurs, c.-à-d. appeler un autre constructeur
dans un constructeur. Sous ce format, utilisez le mot clé this entre parenthèses. Par exemple :
public class testThis {
// First constructor for the class. It requires a string parameter.
public testThis(string s2) {
}
// Second constructor for the class. It does not require a parameter.
// This constructor calls the first constructor using the this keyword.
public testThis() {
this('None');
}
}
Lorsque vous utilisez le mot clé this dans un constructeur pour effectuer un chaînage de constructeurs, il doit correspondre
à la première instruction dans le constructeur.
Utilisation du mot clé transient
Utilisez le mot clé transient pour déclarer des variables d'instance qui ne peuvent pas être enregistrées, et qui ne doivent
pas être transmises dans l'état de la vue pour une page Visualforce. Par exemple :
Transient Integer currentTotal;
Vous pouvez également utiliser le mot clé transient dans des classes Apex qui peuvent être sérialisées, à savoir dans des
contrôleurs, des extensions de contrôleur ou des classes qui mettent en oeuvre l'interface Batchable ou Schedulable. De
plus, vous pouvez utiliser transient dans des classes qui définissent des types de champ déclarés dans les classes sérialisables.
La déclaration de variables comme transient réduit la taille de l'état de la vue. Un cas d'utilisation courant du mot clé
transient est un champ dans une page Visualforce requis uniquement pour la durée d'une requête de page, mais qui ne doit
pas faire partie de l'état de la vue de la page et dont le calcul répété pendant une requête utiliserait trop de ressources système.
Certains objets Apex sont automatiquement considérés comme transient, c.-à-d. que leurs valeurs ne sont pas enregistrées
dans l'état de la vue de la page. Ces objets incluent :
•
•
•
•
•
PageReferences
Classes XmlStream
Collections automatiquement marquées comme transient uniquement si le type d'objet qu'elles contiennent est
automatiquement marqué comme transient, par exemple une collection de points d'enregistrement
La plupart des objets générés par des méthodes système, tels que Schema.getGlobalDescribe
Instances de classe JSONParser Pour plus d'informations, reportez-vous à Prise en charge JSON à la page 490.
Les variables statiques ne sont pas non plus transmises via l'état de la vue.
Classes, objets et interfaces
salesforce | Utilisation des mots clés with sharing ou without
sharing | 156
L'exemple suivant contient une page Visualforce et un contrôleur personnalisé. Un clic sur le bouton Actualiser de la page
entraîne la mise à jour de la date transient, car elle est recrée à chaque actualisation de la page. La date non transient conserve
sa valeur d'origine, qui a été désérialisée de l'état de la vue et reste par conséquent inchangée.
<apex:page controller="ExampleController">
T1: {!t1} <br/>
T2: {!t2} <br/>
<apex:form>
<apex:commandLink value="refresh"/>
</apex:form>
</apex:page>
public class ExampleController {
DateTime t1;
transient DateTime t2;
public String getT1() {
if (t1 == null) t1 = System.now();
return '' + t1;
}
public String getT2() {
if (t2 == null) t2 = System.now();
return '' + t2;
}
}
Utilisation des mots clés with sharing ou without sharing
Le code Apex est généralement exécuté dans le contexte système, c.-à-d. que les autorisations de l'utilisateur actuel, la sécurité
au niveau du champ et les règles de partage ne sont pas prises en compte pendant son exécution.
Remarque: La seule exception à cette règle est un code Apex qui est exécuté avec l'appel executeAnonymous.
executeAnonymous est toujours exécuté en utilisant les autorisations complètes de l'utilisateur actuel. Pour plus
d'informations sur executeAnonymous, reportez-vous à Blocs anonymes à la page 120.
Classes, objets et interfaces
salesforce | Utilisation des mots clés with sharing ou without
sharing | 157
Puisque ces règles ne s'appliquent pas, les développeurs qui utilisent le langage Apex doivent s'assurer de ne pas exposer
accidentellement des données sensibles qui sont habituellement masquées par des autorisations utilisateur, une sécurité au
niveau du champ ou des paramètres par défaut à l'échelle de l'organisation. Ils doivent se montrer particulièrement prudents
avec les services Web, qui peuvent être restreints par des autorisations, mais être exécutés dans un contexte système une fois
initié.
La plupart du temps, le contexte système fournit le comportement approprié pour les opérations au niveau du système, telles
que les déclencheurs et les services Web qui doivent accéder à toutes les données d'une organisation. Cependant, vous pouvez
également spécifier que des classes Apex particulières doivent faire respecter les règles de partage applicables à l'utilisateur
actuel (pour plus d'informations sur les règles de partage, reportez-vous à l'aide en ligne de Salesforce.com).
Remarque: L'application de règles de partage en utilisant le mot clé with sharing n'impose pas les autorisations
et la sécurité au niveau du champ de l'utilisateur. Le code Apex a toujours accès à l'ensemble des champs et des objets
d'une organisation, pour s'assurer que l'exécution du code n'échoue pas en raison de champs ou d'objets masqués pour
un utilisateur.
Utilisez les mots clés with sharing lors de la déclaration d'une classe, pour imposer les règles de partage applicables à
l'utilisateur actuel. Par exemple :
public with sharing class sharingClass {
// Code here
}
Utilisez les mots clés without sharing lors de la déclaration d'une classe, pour s'assurer que les règles de partage de
l'utilisateur actuel ne sont pas appliquées. Par exemple :
public without sharing class noSharing {
// Code here
}
Si une classe n'est pas déclarée « with » ou « without sharing », les règles de partage actuelles restent en vigueur. Cela signifie
que si la classe est appelée par une classe qui impose le partage, le partage s'applique pour la classe appelée.
Les classes internes et les classes externes peuvent être déclarées with sharing. Le paramètre de partage s'applique à
l'ensemble du code inclus dans la classe, y compris le code d'initialisation, les constructeurs et les méthodes. Les classes héritent
de ce paramètre d'une classe parente, lorsqu'une classe étend ou met en oeuvre une autre classe, mais les classes internes
n'héritent pas du paramètre de partage de leur classe conteneur.
Par exemple :
public with sharing class CWith {
// All code in this class operates with enforced sharing rules.
Classes, objets et interfaces
salesforce | Utilisation des mots clés with sharing ou without
sharing | 158
Account a = [SELECT . . . ];
public static void m() { . . . }
static {
. . .
}
{
. . .
}
public c() {
. . .
}
}
public without sharing class CWithout {
// All code in this class ignores sharing rules and operates
// as if the context user has the Modify All Data permission.
Account a = [SELECT . . . ];
. . .
public static void m() {
. . .
// This call into CWith operates with enforced sharing rules
// for the context user. When the call finishes, the code execution
// returns to without sharing mode.
CWith.m();
}
Classes, objets et interfaces
salesforce | Annotations | 159
public class CInner {
// All code in this class executes with the same sharing context
// as the code that calls it.
// Inner classes are separate from outer classes.
. . .
// Again, this call into CWith operates with enforced sharing rules
// for the context user, regardless of the class that initially called this inner class.
// When the call finishes, the code execution returns to the sharing mode that was used
to call this inner class.
CWith.m();
}
public class CInnerWithOut exends CWithout {
// All code in this class ignores sharing rules because
// this class extends a parent class that ignores sharing rules.
}
}
ATTENTION: Rien ne garantit qu'une classe déclarée with sharing n'appelle pas un code qui fonctionne sans
partage (without sharing). La sécurité au niveau de la classe reste nécessaire. De plus, toutes les requêtes SOQL
ou SOSL qui utilisent PriceBook2 ignorent le mot clé with sharing. Tous les enregistrements PriceBook sont
renvoyés, quelles que soient les règles de partage appliquées.
L'application des règles de partage de l'utilisateur actuel peut affecter :
•
•
Les requêtes SOQL et SOSL. Une requête peut renvoyer un nombre de lignes inférieur que si elle fonctionnait dans le
contexte système.
Les opérations DML. Une opération peut échouer si l'utilisateur actuel ne dispose pas des autorisations appropriées. Par
exemple, lorsque l'utilisateur spécifie une valeur de clé étrangère qui existe dans l'organisation, mais à laquelle l'utilisateur
actuel n'a pas accès.
Annotations
Une annotation Apex modifie la façon d'utiliser une méthode ou une classe, de la même façon que les annotations dans Java.
Classes, objets et interfaces
salesforce | Annotation Deprecated | 160
Les annotations sont définies avec le symbole @ initial suivi du mot clé approprié. Pour ajouter une annotation à une méthode,
spécifiez-la immédiatement avant la définition de la méthode ou de la classe. Par exemple :
global class MyClass {
@future
Public static void myMethod(String a)
{
//long-running Apex code
}
}
Le langage Apex prend en charge les annotations suivantes :
•
•
•
•
•
•
@Deprecated
@Future
@IsTest
@ReadOnly
@RemoteAction
Les annotations REST Apex :
◊
◊
◊
◊
◊
@RestResource(urlMapping='/yourUrl')
@HttpDelete
@HttpGet
@HttpPost
@HttpPut
Annotation Deprecated
Utilisez l'annotation deprecated pour identifier des méthodes, des classes, des exceptions, des énumérations, des interfaces
ou des variables qui ne peuvent plus être référencées dans les versions successives du package géré dans lequel elles résident.
Elles sont utiles pour refactoriser un code dans des packages gérés dont les exigences évoluent. Les nouveaux abonnés ne
peuvent pas afficher les éléments dépréciés, tandis que les éléments continuent à fonctionner pour les abonnés et intégrations
d'API existants.
L'extrait de code ci-dessous présente une méthode dépréciée. La même syntaxe peut être utilisée pour des classes, des exceptions,
des énumérations, des interfaces ou des variables dépréciées.
@deprecated
// This method is deprecated. Use myOptimizedMethod(String a, String b) instead.
global void myMethod(String a) {
}
Classes, objets et interfaces
salesforce | Annotation Future | 161
Notez les règles suivantes lors de la dépréciation d'identificateurs Apex :
Les packages non gérés ne peuvent pas contenir un code qui utilise le mot clé deprecated.
Lorsqu'un élément Apex est déprécié, tous les modificateurs d'accès global qui référencent l'identificateur déprécié doivent
également être dépréciés. Toute méthode globale qui utilise le type déprécié dans sa signature (dans un argument d'entrée
ou dans le type de renvoi de la méthode) doit également être dépréciée. Un élément déprécié, tel qu'une méthode ou une
classe, peut toujours être référencé en interne par le développeur du package.
Les méthodes et les variables webService ne peuvent pas être dépréciées.
Vous pouvez déprécier une enum, mais pas des valeurs enum individuelles.
Vous pouvez déprécier une interface, mais pas des méthodes individuelles dans une interface
Vous pouvez déprécier une classe abstraite, mais pas des méthodes abstraites individuelles dans une classe abstraite.
Vous ne pouvez pas supprimer l'annotation deprecated pour annuler la dépréciation d'un élément dans Apex après avoir
publié la version d'un package dans lequel cet élément est déprécié dans le code Apex.
•
•
•
•
•
•
•
Pour plus d'informations sur les versions de packages, reportez-vous à Développement de code Apex dans des packages gérés
à la page 280.
Annotation Future
Utilisez l'annotation future pour identifier les méthodes qui sont exécutées de façon asynchrone. Lorsque vous spécifiez
future, la méthode est exécutée lorsque Salesforce a des ressources disponibles.
Par exemple, vous pouvez utiliser l'annotation future lors d'un appel de service Web asynchrone vers un service externe. Sans
l'annotation, l'appel de service Web est effectué à partir du même fil qui exécute le code Apex, et aucun traitement supplémentaire
n'est effectué jusqu'à la fin de l'appel (traitement synchrone).
Les méthodes avec l'annotation future doivent être des méthodes statiques et peuvent renvoyer uniquement un type void.
Pour effectuer une méthode dans une classe exécutée de façon asynchrone, définissez la méthode avec l'annotation future.
Par exemple :
global class MyFutureClass {
@future
static void myMethod(String a, Integer i) {
System.debug('Method called with: ' + a + ' and ' + i);
//do callout, other long running code
}
}
L'extrait suivant montre comment spécifier qu'une méthode exécute un appel :
@future (callout=true)
public static void doCalloutFromFuture() {
//Add code to perform callout
Classes, objets et interfaces
salesforce | Annotations IsTest | 162
}
Vous pouvez spécifier (callout=false) pour empêcher une méthode d'effectuer des appels.
Pour tester des méthodes définies avec l'annotation future, appelez la classe contenant la méthode dans un bloc de code
startTest, stopTest. Tous les appels asynchrones effectués après la méthode startTest sont collectés par le système.
Lors de l'exécution de stopTest, tous les processus asynchrones sont exécutés de façon synchrone.
Les méthodes avec l'annotation future présentent les limitations suivantes :
•
10 appels de méthode au maximum peuvent être effectués par invocation Apex
Remarque: Les appels asynchrones, tels que @future ou executeBatch, appelés dans un bloc startTest,
stopTest, ne sont pas pris en compte dans les limitations du nombre de tâches en file d'attente.
•
•
•
•
Salesforce impose également une limite sur le nombre d'invocations de méthode future : 200 appels de méthode par
licence utilisateur Salesforce complète, licence utilisateur Salesforce Platform ou licence utilisateur Force.com App
Subscription, par 24 heures. Cette limitation s'applique à l'échelle de l'organisation. Les licences utilisateur Chatter Only,
Utilisateurs clients de Chatter, Customer Portal User et Partner portal ne sont pas incluses dans le calcul de cette limitation.
Par exemple, supposons que votre organisation possède trois licences Salesforce complètes, deux licences Salesforce Platform
et 100 licences Customer Portal User. Votre organisation entière est limitée à 1000 appels de méthode par 24 heures,
calculés par la formule 200 * (3+2), pas 200 * (3+2+100).
Les paramètres spécifiés doivent être des types de données primitifs, des tableaux de types de données primitifs ou des
collections de types de données primitifs.
Les méthodes avec l'annotation future ne peuvent pas prendre des sObjects ou des objets en tant qu'arguments.
Les méthodes avec l'annotation future ne peuvent pas être utilisées dans des contrôleurs Visualforce, ni dans des méthodes
getMethodName ou setMethodName, ni dans le constructeur.
Notez que toute méthode qui utilise l'annotation future requiert une attention particulière, car elle n'est pas nécessairement
exécutée dans l'ordre dans lequel elle est appelée.
Vous ne pouvez pas appeler une méthode annotée avec future à partir d'une méthode qui contient également l'annotation
future. Vous ne pouvez pas non plus appeler un déclencheur à partir d'une méthode annotée qui appelle une autre méthode
annotée.
Les méthodes getContent et getContentAsPDF PageReference ne peuvent pas être utilisées dans des méthodes avec
l'annotation future.
Pour plus d'informations sur les appels, reportez-vous à Invocation d'appels en utilisant le langage Apex à la page 306.
Voir aussi :
Compréhension des limitations et des gouverneurs d'exécution
Annotations IsTest
Utilisez l'annotation isTest pour définir des classes ou des méthodes individuelles qui contiennent uniquement le code utilisé
pour tester votre application. L'annotation isTest est semblable à la création de méthodes déclarées testMethod.
Classes, objets et interfaces
salesforce | Annotations IsTest | 163
Remarque: Les classes définies avec l'annotation isTest ne sont pas prises en compte dans les limitations de votre
organisation de 3 Mo pour l'ensemble du code Apex. Les méthodes de test individuelles dans une classe non annotées
avec isTest sont prises en compte dans la limitation de la taille du code de votre organisation. Reportez-vous à
Compréhension des limitations et des gouverneurs d'exécution à la page 273.
À compter du code Apex enregistré en utilisant l'API Salesforce.com version 24.0, les méthodes de test n'ont plus accès par
défaut aux données préexistantes dans l'organisation. Néanmoins, le code de test enregistré en utilisant l'API Salesforce.com
version 23.0 ou antérieure garde accès à toutes les données de l'organisation et son accès aux données reste inchangé.
Reportez-vous à Isolation des données test de celles de l'organisation dans les tests unitaires à la page 187.
Les classes et les méthodes définies comme isTest peuvent être private ou public. Les classes définies comme isTest
doivent être de niveau supérieur.
L'exemple suivant présente une classe de test privé qui contient deux méthodes de test.
@isTest
private class MyTestClass {
// Methods for testing
@isTest static void test1() {
// Implement test code
}
@isTest static void test2() {
// Implement test code
}
}
L'exemple suivant présente une classe de test public qui contient deux méthodes utilitaires pour la création de données test :
@isTest
public class TestUtil {
public static void createTestAccounts() {
// Create some test accounts
}
public static void createTestContacts() {
// Create some test contacts
Classes, objets et interfaces
salesforce | Annotations IsTest | 164
}
}
Les classes définies comme isTest ne peuvent pas être des interfaces ou des énumérations.
Les méthodes d'une classe de test public peuvent être appelées uniquement à partir d'un test exécuté, c.-à-d. une méthode de
test ou un code invoqué par une méthode de test, et ne peuvent pas être appelées par une requête non test. De plus, les méthodes
de classe de test peuvent être invoquées en utilisant l'interface utilisateur ou l'API Salesforce. Pour plus d'informations,
reportez-vous à Exécution de méthodes de test unitaire.
Annotation IsTest(SeeAllData=true)
Pour un code Apex enregistré en utilisant l'API Salesforce.com versions 24.0 et supérieures, utilisez l'annotation
isTest(SeeAllData=true) pour accorder aux classes de test et aux méthodes de test individuelles l'accès à toutes les
données de l'organisation, y compris aux données préexistantes que le test n'a pas créées. À compter du code Apex enregistré
en utilisant l'API Salesforce.com version 24.0, les méthodes de test n'ont plus accès par défaut aux données préexistantes dans
l'organisation. Néanmoins, le code de test enregistré en utilisant l'API Salesforce.com version 23.0 ou antérieure garde accès
à toutes les données de l'organisation et son accès aux données reste inchangé. Reportez-vous à Isolation des données test de
celles de l'organisation dans les tests unitaires à la page 187.
Considérations sur l'annotation IsTest(SeeAllData=true)
•
•
Si une classe de test est définie avec l'annotation isTest(SeeAllData=true), cette annotation s'applique à toutes
ses méthodes de test, qu'elles soient définies avec l'annotation @isTest ou le mot clé testmethod.
L'annotation isTest(SeeAllData=true) est utilisée pour ouvrir l'accès aux données lorsqu'elle s'applique au
niveau de la classe ou de la méthode. Cependant, l'utilisation de isTest(SeeAllData=false) dans une méthode
ne limite pas l'accès aux données de l'organisation pour cette méthode si la classe qu'elle contient a déjà été définie
avec l'annotation isTest(SeeAllData=true). Dans ce cas, la méthode garde accès à l'ensemble des données de
l'organisation.
Cette exemple montre comment définir une classe de test avec l'annotation isTest(SeeAllData=true). Toutes les
méthodes de test de cette classe ont accès à l'ensemble des données de l'organisation.
// All test methods in this class can access all data.
@isTest(SeeAllData=true)
public class TestDataAccessClass {
// This test accesses an existing account.
// It also creates and accesses a new test account.
static testmethod void myTestMethod1() {
// Query an existing account in the organization.
Account a = [SELECT Id, Name FROM Account WHERE Name='Acme' LIMIT 1];
System.assert(a != null);
// Create a test account based on the queried account.
Classes, objets et interfaces
salesforce | Annotations IsTest | 165
Account testAccount = a.clone();
testAccount.Name = 'Acme Test';
insert testAccount;
// Query the test account that was inserted.
Account testAccount2 = [SELECT Id, Name FROM Account
WHERE Name='Acme Test' LIMIT 1];
System.assert(testAccount2 != null);
}
// Like the previous method, this test method can also access all data
// because the containing class is annotated with @isTest(SeeAllData=true).
@isTest static void myTestMethod2() {
// Can access all data in the organization.
}
}
Ce deuxième exemple montre comment appliquer l'annotation isTest(SeeAllData=true) dans une méthode de test. La
classe qui contient cette méthode de test n'est pas définie avec cette annotation. Par conséquent, vous devez appliquer cette
annotation dans la méthode de test afin d'accorder l'accès à toutes les données pour la méthode. La deuxième méthode de test
ne contient pas cette annotation. Par conséquent, elle peut accéder uniquement aux données qu'elle créée, en plus des objets
utilisés pour gérer votre organisation, tels que les utilisateurs.
// This class contains test methods with different data access levels.
@isTest
private class ClassWithDifferentDataAccess {
// Test method that has access to all data.
@isTest(SeeAllData=true)
static void testWithAllDataAccess() {
// Can query all data in the organization.
}
// Test method that has access to only the data it creates
Classes, objets et interfaces
salesforce | Annotations IsTest | 166
// and organization setup and metadata objects.
@isTest static void testWithOwnDataAccess() {
// This method can still access the User object.
// This query returns the first user object.
User u = [SELECT UserName,Email FROM User LIMIT 1];
System.debug('UserName: ' + u.UserName);
System.debug('Email: ' + u.Email);
// Can access the test account that is created here.
Account a = new Account(Name='Test Account');
insert a;
// Access the account that was just created.
Account insertedAcct = [SELECT Id,Name FROM Account
WHERE Name='Test Account'];
System.assert(insertedAcct != null);
}
}
Annotation IsTest(OnInstall=true)
Utilisez l'annotation IsTest(OnInstall=true) pour spécifier les tests Apex qui sont exécutés durant l'installation d'un
package. Cette annotation est utilisée pour des tests dans des packages gérés ou non gérés. Seules les méthodes de test avec
cette annotation, ou les méthodes qui font partie d'une classe de test contenant cette annotation, sont exécutées durant
l'installation d'un package. Les tests annotés pour être exécutés lors de l'installation d'un package doivent passer pour la réussite
de l'installation du package. Il n'est plus possible de contourner un test échoué durant l'installation d'un package. Une méthode
ou une classe de test qui ne contient pas cette annotation, ou qui est annotée avec isTest(OnInstall=false) ou isTest,
n'est pas exécutée durant l'installation.
Cet exemple montre comment annoter une méthode de test qui est exécutée lors de l'installation d'un package. Dans cet
exemple, la méthode test1 est exécutée, contrairement à test2 et à test3.
public class OnInstallClass {
// Implement logic for the class.
public void method1(){
// Some code
}
// This test method will be executed
// during the installation of the package.
@isTest(OnInstall=true)
Classes, objets et interfaces
salesforce | Annotation ReadOnly | 167
static void test1() {
// Some test code
}
// Tests excluded from running during the
// the installation of a package.
@isTest
static void test2() {
// Some test code
}
static testmethod void test3() {
// Some test code
}
}
Annotation ReadOnly
L'annotation @ReadOnly permet d'effectuer des requêtes sans restriction avec la base de données Force.com. D'autres limites
restent applicables. Il est important de noter que cette annotation, bien qu'elle supprime la limite en nombre de lignes renvoyées
pour une requête, empêche d'effectuer les opérations suivantes dans la requête : des opérations DML, des appels à
System.schedule, des appels aux méthodes annotées avec @future et l'envoi d'e-mails.
L'annotation @ReadOnly est disponible pour les services Web et l'interface Schedulable. Pour utiliser l'annotation
@ReadOnly, la requête de niveau supérieur doit être dans l'exécution de la planification ou dans l'invocation du service Web.
Par exemple, si une page Visualforce appelle à un service Web qui contient l'annotation @ReadOnly, la requête échoue, car
Visualforce est la requête de niveau supérieur, pas le service Web.
Les pages Visualforce peuvent appeler des méthodes de contrôleur avec l'annotation @ReadOnly, et ces méthodes sont exécutées
avec les mêmes restrictions assouplies. Pour augmenter d'autres limites spécifiques à Visualforce, notamment la taille d'une
collection qui peut être utilisée par un composant d'itération tel que <apex:pageBlockTable>, vous pouvez définir l'attribut
readonly de la balise <apex:page> sur true. Pour plus d'informations, reportez-vous à Working with Large Sets of Data
dans le guide Visualforce Developer's Guide.
Annotation RemoteAction
L'annotation RemoteAction fournit la prise en charge des méthodes Apex utilisées dans Visualforce pour être appelées via
JavaScript. Ce processus est souvent appelé JavaScript remoting.
Classes, objets et interfaces
salesforce | Annotations REST Apex | 168
Remarque: Les méthodes avec l'annotation RemoteAction doivent être static et global ou public.
Pour utiliser JavaScript remoting dans une page Visualforce, ajoutez la requête en tant qu'invocation JavaScript sous le format
suivant :
[namespace.]controller.method(
[parameters...,]
callbackFunction,
[configuration]
);
•
•
•
•
•
•
namespace correspond à l'espace de noms de la classe de contrôleur. Il est requis si votre organisation à un espace de noms
défini ou si la classe provient d'un package installé.
controller est le nom de votre contrôleur Apex.
method est le nom de la méthode Apex que vous appelez.
parameters est la liste de paramètres, séparés par des virgules, que prend votre méthode.
callbackFunction est le nom de la fonction JavaScript qui va gérer la réponse du contrôleur. Vous pouvez également
déclarer en ligne une fonction anonyme. callbackFunction reçoit le statut de l'appel de la méthode et le résultat sous
forme de paramètres.
configuration configure le traitement de l'appel et de la réponse distants. Il permet de spécifier l'échappement ou non
de la réponse de la méthode Apex. La valeur par défaut est {escape: true}.
Dans votre contrôleur, votre déclaration de méthode Apex est précédée de l'annotation @RemoteAction, comme suit :
@RemoteAction
global static String getItemId(String objectName) { ... }
Votre méthode peut prendre des primitifs, collections, typés et sObjects génériques Apex, et des classes et des interfaces Apex
définies par l'utilisateur en tant qu'arguments. Les sObjects génériques doivent avoir une valeur ID ou sobjectType pour
identifier le type actuel. Les paramètres d'interface doivent avoir un apexType pour identifier le type actuel. Votre méthode
peut renvoyer des primitifs, des sObjects, des collections, des classes Apex définies par l'utilisateur et des énumérations Apex,
SaveResult, UpsertResult, DeleteResult, SelectOption ou PageReference.
Pour plus d'informations, reportez-vous à JavaScript Remoting for Apex Controllers dans le guide Visualforce Developer's Guide.
Annotations REST Apex
Six nouvelles annotations ont été ajoutées, qui permettent d'exposer une classe Apex en tant que service Web RESTful.
•
•
•
•
@RestResource(urlMapping='/yourUrl')
@HttpDelete
@HttpGet
@HttpPost
Classes, objets et interfaces
•
salesforce | Annotations REST Apex | 169
@HttpPut
Voir aussi :
Exemple de code de base REST Apex
Annotation RestResource
L'annotation @RestResource est utilisée au niveau de la classe et permet d'exposer une classe Apex en tant que ressource
REST.
Notez les points suivants lors de l'utilisation de cette annotation :
•
•
•
•
Le mappage d'URL est relatif à https://instance.salesforce.com/services/apexrest/.
Un caractère générique (*) peut être utilisé.
Le mappage d'URL est sensible à la casse. Un mappage d'URL pour mon_url correspond uniquement à une ressource
REST contenant mon_url, pas Mon_Url.
Pour utiliser cette annotation, votre classe Apex doit être définie comme globale.
Directives URL
Les mappages de chemins d'URL sont les suivants :
•
•
Le chemin doit commencer par une barre oblique '/'
Si un astérisque '*' est utilisé, il doit être précédé et suivi d'une barre oblique '/', sauf si l'astérisque '*' est le dernier caractère,
auquel cas il doit être suivi d'une barre oblique '/'
Les règles de mappage d'URL sont les suivantes :
•
•
•
Une correspondance exacte gagne toujours.
Si aucune correspondance n'est trouvée, recherchez tous les modèles avec un caractère générique qui correspondent, puis
sélectionnez le plus long (en taille de chaîne).
Si aucune correspondance avec un caractère générique n'est trouvée, un code de statut de réponse HTTP 404 est renvoyé.
L'URL d'une classe d'espace de noms contient l'espace de noms. Par exemple, si votre classe est un espace de noms abc et
que la classe est mappée avec votre_url, l'URL de l'API est modifiée comme suit :
https://instance.salesforce.com/services/apexrest/abc/votre_url/. En cas de collision d'URL, la classe
d'espace de noms est toujours utilisée.
Annotation HttpDelete
L'annotation @HttpDelete est utilisée au niveau de la méthode et permet d'exposer une méthode Apex en tant que ressource
REST. Cette méthode est appelée lorsqu'une requête DELETE HTTP est envoyée, et supprime la ressource spécifiée.
Pour utiliser cette annotation, votre méthode Apex doit être définie comme statique globale.
Annotation HttpGet
L'annotation @HttpGet est utilisée au niveau de la méthode et permet d'exposer une méthode Apex en tant que ressource
REST. Cette méthode est appelée lorsqu'une requête GET HTTP est envoyée, et renvoie la ressource spécifiée.
Notez les points suivants lors de l'utilisation de cette annotation :
Classes, objets et interfaces
•
•
salesforce | Classes et conversion | 170
Pour utiliser cette annotation, votre méthode Apex doit être définie comme statique globale.
Les méthodes annotées avec @HttpGet sont également appelées si la requête HTTP utilise la méthode de requête HEAD.
Annotation HttpPatch
L'annotation @HttpPatch est utilisée au niveau de la méthode et permet d'exposer une méthode Apex en tant que ressource
REST. Cette méthode est appelée lorsqu'une requête PATCH HTTP est envoyée, et met à jour la ressource spécifiée.
Pour utiliser cette annotation, votre méthode Apex doit être définie comme statique globale.
Annotation HttpPost
L'annotation @HttpPost est utilisée au niveau de la méthode et permet d'exposer une méthode Apex en tant que ressource
REST. Cette méthode est appelée lorsqu'une requête POST HTTP est envoyée, et crée une ressource.
Pour utiliser cette annotation, votre méthode Apex doit être définie comme statique globale.
Annotation HttpPut
L'annotation @HttpPut est utilisée au niveau de la méthode et permet d'exposer une méthode Apex en tant que ressource
REST. Cette méthode est appelée lorsqu'une requête PUT HTTP est envoyée, et crée ou met à jour la ressource spécifiée.
Pour utiliser cette annotation, votre méthode Apex doit être définie comme statique globale.
Classes et conversion
Généralement, toutes les informations de type sont disponibles à l'exécution. Cela signifie que le langage Apex permet le
casting (conversion), c.-à-d. un type de données d'une classe peut être attribué à un type de données d'une autre classe, mais
uniquement si une classe est un enfant de l'autre classe. Utilisez le casting pour convertir un objet de type de données vers un
autre.
Dans l'exemple suivant, CustomReport étend la classe Report. Par conséquent, elle est un enfant de cette classe. Cela signifie
que vous pouvez utiliser le casting pour attribuer des objets avec le type de données parent (Report) à des objets avec le type
de données enfant (CustomReport).
Dans le bloc de code suivant, un objet de rapport personnalisé est tout d'abord ajouté à la liste des objets de rapport. L'objet
de rapport personnalisé est ensuite renvoyé en tant qu'objet de rapport, puis reconverti en objet de rapport personnalisé.
Public virtual class Report {
Public class CustomReport extends Report {
// Create a list of report objects
Report[] Reports = new Report[5];
// Create a custom report object
CustomReport a = new CustomReport();
Classes, objets et interfaces
salesforce | Classes et conversion | 171
// Because the custom report is a sub class of the Report class,
// you can add the custom report object a to the list of report objects
Reports.add(a);
// The following is not legal, because the compiler does not know that what you are
// returning is a custom report. You must use cast to tell it that you know what
// type you are returning
// CustomReport c = Reports.get(0);
// Instead, get the first item in the list by casting it back to a custom report object
CustomReport c = (CustomReport) Reports.get(0);
}
}
Classes, objets et interfaces
salesforce | Classes et collections | 172
Figure 4: Exemple de conversion
De plus, un type d'interface peut être converti en sous-interface ou en type de classe qui met en oeuvre cette interface.
Conseil: Pour vérifier si une classe est un type de classe spécifique, utilisez le mot clé instanceOf. Pour plus
d'informations, reportez-vous à Utilisation du mot clé instanceof à la page 152.
Classes et collections
Des listes et des mappages peuvent être utilisés avec des classes et des interfaces, de la même façon que des listes et des mappages
peuvent être utilisés avec des sObjects. Cela signifie, par exemple, que vous pouvez utiliser un type de données défini par
l'utilisateur uniquement pour la valeur d'un mappage, pas pour la clé. De la même façon, vous ne pouvez pas créer un ensemble
d'objets définis par l'utilisateur.
Si vous créez un mappage ou une liste d'interfaces, tout type enfant de l'interface peut être placé dans cette collection. Par
exemple, si la liste contient une interface i1, et que MyC met en oeuvre i1, alors MyC peut être placé dans la liste.
Conversion de collection
Puisque les collections dans le langage Apex ont un type déclaré à l'exécution, Apex permet la conversion de collection.
Classes, objets et interfaces
salesforce | Différences entre les classes Apex et les classes
Java | 173
Les collections peuvent être converties de la même façon que des tableaux peuvent être convertis dans Java. Par exemple, une
liste d'objets CustomerPurchaseOrder peut être attribuée à une liste d'objets PurchaseOrder si la classe
CustomerPurchaseOrder est un enfant de la classe PurchaseOrder.
public virtual class PurchaseOrder {
Public class CustomerPurchaseOrder extends PurchaseOrder {
}
{
List<PurchaseOrder> POs = new PurchaseOrder[] {};
List<CustomerPurchaseOrder> CPOs = new CustomerPurchaseOrder[]{};
POs = CPOs;}
}
Une fois la liste CustomerPurchaseOrder attribuée à la variable de la liste PurchaseOrder, elle peut être reconvertie en
liste d'objets CustomerPurchaseOrder, mais uniquement parce que cette instance avait été initialement instanciée en tant que
liste CustomerPurchaseOrder. Une liste d'objets PurchaseOrder instanciée ainsi ne peut pas être convertie en liste d'objets
CustomerPurchaseOrder, même si la liste d'objets PurchaseOrder contient uniquement des objets CustomerPurchaseOrder.
Si l'utilisateur d'une liste PurchaseOrder qui contient uniquement des objets CustomerPurchaseOrders essaie d'insérer une
sous-classe non CustomerPurchaseOrder de PurchaseOrder (telle que InternalPurchaseOrder), une exception
d'exécution est levée, car les collections Apex ont un type déclaré à l'exécution.
Remarque: Les mappages se comportent de la même façon que des listes avec le côté valeur du mappage : si le côté
valeur d'un mappage A peut être converti en côté de valeur d'un mappage B, et qu'ils ont le même type de clé, le
mappage A peut être converti en mappage B. Une erreur d'exécution se produit si la conversion n'est pas valide avec
le mappage spécifique à l'exécution.
Différences entre les classes Apex et les classes Java
La liste suivante présente les principales différences entre les classes Apex et les classes Java :
•
•
•
•
Les classes et les interfaces internes peuvent être déclarées à un seul niveau dans une classe externe.
Les méthodes et les variables statiques peuvent être déclarées uniquement dans une définition de classe de niveau supérieur,
pas dans une classe interne.
Les classes internes se comportent comme des classes internes Java statiques, mais ne nécessitent pas le mot clé static.
Les classes internes peuvent avoir des variables de membre d'instance comme des classes externes, mais il n'existe aucun
pointeur implicite vers une instance de la classe externe (utilisant le mot clé this).
Le type private correspond au modificateur d'accès par défaut, ce qui signifie que la méthode ou variable est accessible
uniquement dans la classe Apex dans laquelle elle est définie. Si vous ne spécifiez pas de modificateur d'accès, la méthode
ou la variable est private.
Classes, objets et interfaces
•
•
•
•
salesforce | Création d'une définition de classe | 174
La spécification d'aucun modificateur d'accès pour une méthode ou une variable et le modificateur d'accès private sont
synonymes.
Le modificateur d'accès public signifie que la méthode ou la variable peut être utilisée par n'importe quel code Apex dans
cette application ou cet espace de noms.
Le modificateur d'accès global signifie que la méthode ou la variable peut être utilisée par n'importe quel code Apex qui
a accès à la classe, pas seulement par le code Apex dans la même application. Ce modificateur d'accès doit être utilisé pour
n'importe quelle méthode qui doit être référencée hors de l'application, dans l'API SOAP ou par un autre code Apex. Si
vous déclarez une méthode ou une variable comme global, vous devez également déclarer la classe qui le contient comme
global.
Les méthodes et les classes sont finales par défaut.
◊ Le modificateur de définition virtual permet l'extension et les remplacements.
◊ Le mot clé override doit être utilisé explicitement dans les méthodes qui remplacent des méthodes de classe de base.
•
•
Les méthodes d'interfaces n'ont aucun modificateur, elles sont toujours globales.
Les classes d'exception doivent étendre leur exception ou une autre exception définie par l'utilisateur.
◊ Leur nom doit se terminer par le terme exception.
◊ Les classes d'exception ont quatre constructeurs implicites intégrés, mais vous pouvez en ajouter d'autres.
Pour plus d'informations, reportez-vous à Classe Exception à la page 585.
•
Les classes et les interfaces peuvent être définies dans des déclencheurs et des blocs anonymes, mais uniquement comme
locales.
Création d'une définition de classe
Pour créer une classe dans Salesforce :
1. Cliquez sur Votre nom > Configuration > Développer > Classes Apex.
2. Cliquez sur Nouveau.
3. Cliquez sur Paramètres de version pour spécifier la version de la classe Apex et l'API utilisée dans cette classe. Si votre
organisation a des packages gérés installés depuis AppExchange, vous pouvez également spécifier la version de chaque
package géré à utiliser avec cette classe. Utilisez les valeurs par défaut pour toutes les versions. Elles associent la classe à la
version la plus récente du code Apex et de l'API, ainsi que de chaque package géré. Vous pouvez spécifier une version
antérieure d'un package géré si vous souhaitez accéder à des composants ou des fonctionnalités qui diffèrent de la version
la plus récente du package. Vous pouvez spécifier une version antérieure d'Apex et de l'API pour conserver un comportement
spécifique.
4. Dans l'éditeur de classe, saisissez le code Apex de la classe. Un seule classe peut comporter jusqu'à 1 million de caractères
en longueur, sans inclure les commentaires, les méthodes de test ou les classes définies en utilisant @isTest.
5. Cliquez sur Enregistrer pour enregistrer vos modifications et revenir à l'écran de détails de la classe ou cliquez sur
Enregistrement rapide pour enregistrer vos modifications et continuer à modifier la classe. Votre classe Apex doit être
correctement compilée pour pouvoir l'enregistrer.
Les classes peuvent être automatiquement générées à partir d'un WSDL en cliquant sur Générer à partir du WSDL.
Reportez-vous à Services SOAP : Définition d'une classe à partir d'un document WSDL à la page 307.
Une fois enregistrées, les classes peuvent être appelées à partir de méthodes de classe ou de variables par un autre code Apex,
tel qu'un déclencheur.
Classes, objets et interfaces
salesforce | Création d'une définition de classe | 175
Remarque: Pour faciliter la rétrocompatibilité, les classes sont stockées avec les paramètres d'une version spécifique
d'Apex et d'API. Si la classe Apex référence des composants (par exemple un objet personnalisé) dans des packages
gérés installés, les paramètres de version de chaque package géré que la classe référence sont également enregistrés.
De plus, les classes sont stockées avec un indicateur isValid défini sur true si toutefois les métadonnées dépendantes
n'ont pas changé depuis la dernière compilation de la classe. Si des modifications sont apportées aux noms ou aux
champs d'objet utilisés dans la classe, même si elles sont mineures (par exemple dans la description d'un champ ou
d'un objet), ou si des modifications sont apportées à une classe qui appelle cette classe, l'indicateurisValid est défini
sur false. Lorsqu'un déclencheur ou un appel de service Web invoque la classe, le code est recompilé et l'utilisateur
est notifié des erreurs éventuelles. En l'absence d'erreur, l'indicateur isValid est réinitialisé sur true.
L'éditeur de classe Apex
Lors de la modification de Visualforce ou de code Apex, dans le pied de page du mode de développement Visualforce ou via
la Configuration, un éditeur est disponible avec les fonctionnalités suivantes :
Mise en évidence de la syntaxe
L'éditeur applique automatiquement la mise en évidence de la syntaxe pour les mots, et toutes les fonctions et opérateurs.
Recherche ( )
La recherche permet de retrouver un texte dans la page, la classe ou le déclencheur actuel. Pour utiliser la recherche,
saisissez une chaîne dans la zone de texte Rechercher, puis cliquez sur Rechercher suivant.
• Pour remplacer une chaîne de recherche trouvée, saisissez la nouvelle chaîne dans la zone de texte Remplacer, puis
cliquez sur Remplacer pour remplacer uniquement cette instance ou sur Remplacer tout pour remplacer cette instance
et toutes les autres instances de la chaîne de recherche présentes dans la page, la classe ou le déclencheur.
• Pour rendre l'opération de recherche sensible à la casse, sélectionnez l'option Respecter la casse.
• Pour utiliser une expression régulière comme chaîne de recherche, sélectionnez l'option Expressions régulières. Les
expressions régulières suivent les règles d'expression régulière de JavaScript. Une recherche qui utilise des expressions
régulières peut retrouver des chaînes de plusieurs lignes.
Si vous utilisez l'opération de remplacement avec une chaîne renvoyée par une expression régulière, l'opération de
remplacement peut également lier des variables de groupe d'expressions régulières ($1, $2, etc.) à partir de la chaîne
de recherche trouvée. Par exemple, pour remplacer une balise <h1> par <h2>, et laisser inchangés tous les attributs
de la <h1> d'origine, recherchez <h1(\s+)(.*)>, puis remplacez-la par <h2$1$2>.
Accéder à la ligne ( )
Ce bouton permet de mettre en évidence un numéro de ligne spécifié. Si la ligne n'est pas affichée, l'éditeur navigue
jusqu'à la ligne.
Annuler ( ) et Répéter ( )
Utilisez Annuler pour inverser une action de modification et Répéter pour recréer une action de modification précédemment
annulée.
Taille de la police
Sélectionnez une taille de police dans la liste déroulante pour contrôler la taille des caractères affichés dans l'éditeur.
Position de ligne et de colonne
La position de ligne et de colonne du curseur est affichée dans la barre d'état en bas de l'éditeur. Vous pouvez l'utiliser
avec la fonction Accéder à la ligne (
) pour accélérer la navigation dans l'éditeur.
Classes, objets et interfaces
salesforce | Conventions de nommage | 176
Nombre de lignes et de caractères
Le nombre total de lignes et de caractères est affiché dans la barre d'état en bas de l'éditeur.
Conventions de nommage
Nous recommandons les normes Java suivantes pour le nommage, c.-à-d. des classes qui commencent par une lettre majuscule,
des méthodes qui commencent par un verbe en lettres minuscules et des noms de variables explicites.
La définition d'une classe et d'une interface sous le même nom dans la même classe est illégale. La définition d'une classe
interne sous le même nom que sa classe externe est illégale. Cependant, les méthodes et les variables ont leur propre espace de
noms dans la classe. Par conséquent ces trois types de nom ne sont pas en conflit. Notamment, la définition d'une variable,
d'une méthode et d'une classe sous le même nom dans une classe est illégale.
Occultation de noms
Les variables de membre peuvent être occultées par des variables locales, notamment des arguments de fonction. Cela autorise
des méthodes et des constructeurs sous le format Java standard :
Public Class Shadow {
String s;
Shadow(String s) { this.s = s; } // Same name ok
setS(String s) { this.s = s; } // Same name ok
}
Des variables de membre dans une classe peuvent occulter des variables de membre portant le même nom dans une classe
parente. Cela peut être utile si les deux classes figurent dans des classes de niveau supérieur différentes et sont écrites par
différentes équipes. Par exemple, si une classe contient une référence à une classe C et souhaite accéder à une variable de
membre M dans une classe parente P (qui porte le même nom qu'une variable de membre dans C), la référence doit d'abord
être attribuée à une référence à P.
Des variables statiques peuvent être occultées à travers la hiérarchie des classes. Par conséquent, si P définit une variable S
statique, une sous-classe C peut également déclarer une variable S statique. Les références à S dans C font référence à cette
variable statique. Pour référencer la variable dans P, la syntaxe P.S doit être utilisée.
Les variables de classe statiques ne peuvent pas être référencées via une instance de classe. Elles doivent être référencées en
utilisant un nom de variable brut seul (dans un fichier de classe de niveau supérieur) ou avec le nom de la classe en préfixe. Par
exemple :
public class p1 {
public static final Integer CLASS_INT = 1;
public class c { };
}
p1.c c = new p1.c();
// This is illegal
// Integer i = c.CLASS_INT;
Classes, objets et interfaces
salesforce | Sécurité des classes | 177
// This is correct
Integer i = p1.CLASS_INT;
Sécurité des classes
Vous pouvez spécifier les utilisateurs autorisés à exécuter des méthodes dans une classe de niveau supérieur donnée, en fonction
de leur profil ou d'ensembles d'autorisations. Vous pouvez définir la sécurité uniquement dans des classes Apex, pas dans des
déclencheurs.
Pour définir la sécurité d'une classe Apex dans sa page de liste :
1. Cliquez sur Votre nom > Configuration > Développer > Classes Apex.
2. En regard du nom de la classe à restreindre, cliquez sur Sécurité.
3. Sélectionnez les profils que vous souhaitez activer dans la liste Profils disponibles, puis cliquez sur Ajouter, ou sélectionnez
les profils que vous souhaitez désactiver de la liste Profil activés, puis cliquez sur Retirer.
4. Cliquez sur Enregistrer.
Pour définir la sécurité d'une classe Apex dans sa page de détail :
1.
2.
3.
4.
Cliquez sur Votre nom > Configuration > Développer > Classes Apex.
Cliquez sur le nom de la classe que vous souhaitez restreindre.
Cliquez sur Sécurité.
Sélectionnez les profils que vous souhaitez activer dans la liste Profils disponibles, puis cliquez sur Ajouter, ou sélectionnez
les profils que vous souhaitez désactiver de la liste Profil activés, puis cliquez sur Retirer.
5. Cliquez sur Enregistrer.
Pour définir la sécurité d'une classe Apex à partir d'un ensemble d'autorisations :
1.
2.
3.
4.
5.
Cliquez sur Votre nom > Configuration > Gestion des utilisateurs > Ensembles d'autorisations.
Sélectionnez un ensemble d'autorisations.
Cliquez sur Accès à la classe Apex.
Cliquez sur Modifier.
Sélectionnez les classes Apex que vous souhaitez activer dans la liste Classes Apex disponibles, puis cliquez sur Ajouter,
ou sélectionnez les classes Apex que vous souhaitez désactiver dans la liste de Classes Apex activées, puis cliquez sur Retirer.
6. Cliquez sur Enregistrer.
Pour définir la sécurité d'une classe Apex à partir d'un profil :
1.
2.
3.
4.
Cliquez sur Votre nom > Configuration > Gérer les utilisateurs > Profils.
Sélectionnez un profil.
Dans la liste associée ou la page Accès aux classes Apex, cliquez sur Modifier.
Sélectionnez les classes Apex que vous souhaitez activer dans la liste Classes Apex disponibles, puis cliquez sur Ajouter,
ou sélectionnez les classes Apex que vous souhaitez désactiver dans la liste de Classes Apex activées, puis cliquez sur Retirer.
5. Cliquez sur Enregistrer.
Classes, objets et interfaces
salesforce | Application des autorisations d'objet et de
champ | 178
Application des autorisations d'objet et de champ
Le code Apex est généralement exécuté dans le contexte système, c.-à-d. que les autorisations de l'utilisateur actuel, la sécurité
au niveau du champ et les règles de partage ne sont pas prises en compte pendant son exécution. La seule exception à cette
règle est un code Apex qui est exécuté avec l'appel executeAnonymous. executeAnonymous est toujours exécuté en utilisant
les autorisations complètes de l'utilisateur actuel. Pour plus d'informations sur executeAnonymous, reportez-vous à Blocs
anonymes à la page 120.
Bien que le code Apex n'impose pas les autorisations au niveau de l'objet et au niveau du champ par défaut, vous pouvez les
appliquer dans votre code en appelant explicitement les méthodes sObject describe result (de Schema.DescribeSObjectResult)
et les méthodes field describe result (de Schema.DescribeFieldResult) qui vérifient les niveaux d'autorisation d'accès de
l'utilisateur. Vous pouvez ainsi vérifier si l'utilisateur actuel dispose des autorisations requises et, si ses autorisations sont
suffisantes, exécuter une opération DML spécifique ou une requête.
Par exemple, vous pouvez appeler la méthode isAccessible, isCreateable ou isUpdateable de
Schema.DescribeSObjectResult pour vérifier si l'utilisateur actuel dispose respectivement d'un accès en lecture, en
création ou en mise à jour à un sObject. De la même façon, Schema.DescribeFieldResult expose ces méthodes de
contrôle d'accès que vous pouvez appeler pour vérifier l'accès en lecture, en création ou en mise à jour à un champ de l'utilisateur
actuel. Vous pouvez en outre appeler la méthode isDeletable fournie par Schema.DescribeSObjectResult pour
vérifier si l'utilisateur actuel est autorisé à supprimer un sObject spécifique.
Les exemples suivants montrent comment appeler les méthodes de contrôle d'accès.
Pour vérifier l'autorisation de mise à jour au niveau du champ d'e-mail du contact avant de le mettre à jour :
if (Schema.sObjectType.Contact.fields.Email.isUpdateable()) {
// Update contact phone number
}
Pour vérifier l'autorisation de création au niveau du champ d'e-mail du contact avant de créer un contact :
if (Schema.sObjectType.Contact.fields.Email.isCreateable()) {
// Create new contact
}
Pour vérifier l'autorisation de lecture au niveau du champ d'e-mail du contact avant d'interroger ce champ :
if (Schema.sObjectType.Contact.fields.Email.isAccessible()) {
Contact c = [SELECT Email FROM Contact WHERE Id= :Id];
}
Pour vérifier l'autorisation au niveau de l'objet pour le contact avant de supprimer le contact :
if (Schema.sObjectType.Contact.isDeletable()) {
// Delete contact
}
Classes, objets et interfaces
salesforce | Préfixe d'espace de noms | 179
Les règles de partage sont différentes des autorisations au niveau de l'objet et au niveau du champ. Elles peuvent coexister. Si
des règles de partage sont définies dans Salesforce, vous pouvez les appliquer au niveau de la classe en déclarant la classe avec
le mot clé with sharing. Pour plus d'informations, reportez-vous à Utilisation des mots clés with sharing ou without
sharing. Si vous appelez les méthodes de contrôle d'accès sObject describe result et field describe result, l'autorisation de
vérification de l'objet et les autorisations au niveau du champ s'appliquent en plus des règles de partage en vigueur. Le niveau
d'accès est parfois accordé par une règle de partage qui peut entrer en conflit avec une autorisation au niveau de l'objet ou au
niveau du champ.
Préfixe d'espace de noms
L'application prend en charge l'utilisation de préfixes d'espace de noms. Les préfixes d'espace de noms sont utilisés dans des
packages Force.com AppExchange gérés afin de différencier les noms d'objet et de champ personnalisés de ceux utilisés par
d'autres organisations. Lorsqu'un développeur a enregistré un préfixe d'espace de noms unique global et l'a ajouté au registre
AppExchange, les références externes aux noms d'objet et de champ personnalisés dans les packages gérés du développeur se
présentent sous le format long suivant :
namespace_prefix__obj_or_field_name__c
Ces noms qualifiés complets peuvent être difficiles à mettre à jour lors de l'utilisation d'instructions SOQL, d'instructions
SOSL et de code Apex lorsqu'une classe est marquée « géré ». Par conséquent, Apex prend en charge un espace de noms par
défaut pour les noms de schéma. Lors de l'utilisation d'identificateurs, l'analyseur évalue l'espace de noms de l'objet actuel,
puis considère qu'il correspond à l'espace de noms de tous les autres objets et champs, sauf indication contraire. Par conséquent,
une classe stockée doit référencer directement les noms d'objet et de champ personnalisés (en utilisant
obj_or_field_name__c) pour les objets qui sont définis dans le même espace de noms d'application.
Conseil: Utilisez des préfixes d'espace de noms uniquement pour référencer des objets et des champs personnalisés
dans des packages gérés qui ont été installés dans votre organisation à partir d'AppExchange.
Utilisation d'espace de noms lors de l'invocation de méthodes
Pour invoquer une méthode qui est définie dans un package géré, le langage Apex autorise les identificateurs qualifiés complets
sous le format suivant :
namespace_prefix.class.method(args)
Utilisez l'espace de noms spécial System pour différencier les classes statiques intégrées de celles définies par l'utilisateur (par
exemple System.System.debug()).
Sans le préfixe d'espace de noms System, les noms de classes statiques système, tels queMath et System, risquent d'être
remplacés par des classes définies par l'utilisateur portant le même nom, comme indiqué ci-dessous.
Conseil: Utilisez des préfixes d'espace de noms uniquement pour invoquer des méthodes dans des packages gérés
qui ont été installés dans votre organisation à partir d'AppExchange.
Classes, objets et interfaces
salesforce | Précédence des noms d'espace de noms, de classe
et de variable | 180
Précédence des noms d'espace de noms, de classe et de variable
Les variables locales, les noms de classe et les espaces de noms peuvent utiliser les mêmes identifiants. Par conséquent, l'analyseur
Apex évalue les expressions sous le format name1.name2.[...].nameN, comme suit :
1. L'analyseur fait d'abord l'hypothèse que name1 est une variable locale avec name2 - nameN comme références de champ.
2. Si la première hypothèse n'est pas vraie, l'analyseur fait l'hypothèse que name1 est un nom de classe et que name2 est un
nom de variable statique avec name3 - nameN comme références de champ.
3. Si la deuxième hypothèse n'est pas vraie, l'analyseur fait l'hypothèse que name1 est un nom d'espace de noms, que name2
est un nom de classe, que name3 est un nom de variable statique et que name4 - nameN sont des références de champ.
4. Si la troisième hypothèse n'est pas vraie, l'analyseur renvoie une erreur.
Si l'expression se termine par un ensemble de parenthèses (par exemple name1.name2.[...].nameM.nameN()), l'analyseur
Apex évalue l'expression comme suit :
1. L'analyseur fait d'abord l'hypothèse que name1 est une variable locale avec name2 - nameN comme références de champ,
et nameN comme invocation de méthode.
2. Si la première hypothèse n'est pas vraie :
•
•
Si l'expression contient uniquement deux identifiants (name1.name2()), l'analyseur fait l'hypothèse que name1 est
un nom de classe et que name2 est une invocation de méthode.
Si l'expression contient plus de deux identifiants, l'analyseur fait l'hypothèse que name1 est un nom de classe, que
name2 est un nom de variable statique avec name3 - nameM comme références de champ, et que nameN est une
invocation de méthode.
3. Si la deuxième hypothèse n'est pas vraie, l'analyseur fait l'hypothèse que name1 est un nom d'espace de noms, que name2
est un nom de classe, que name3 est un nom de variable statique, que name4 - nameM sont des références de champ et que
nameN est une invocation de méthode.
4. Si la troisième hypothèse n'est pas vraie, l'analyseur renvoie une erreur.
Cependant, avec des variables de classe, le langage Apex utilise également une notation pointée pour référencer des variables
de membre. Ces variables de membre peuvent référencer d'autres instances de classe, ou référencer un sObject qui possède ses
propres règles de notation pointée pour référencer des noms de champ (éventuellement des clés étrangères de navigation).
Lorsque vous saisissez un champ sObject dans une expression, la suite de l'expression reste dans le domaine du sObject, c.-à-d.
que les champs sObject ne peuvent pas de nouveau référencer des expressions Apex.
Par exemple, si vous avez la classe suivante :
public class c {
c1 c1 = new c1();
class c1 { c2 c2; }
class c2 { Account a; }
}
Les expressions suivantes sont toutes légales :
c.c1.c2.a.name
c.c1.c2.a.owner.lastName.toLowerCase()
Classes, objets et interfaces
salesforce | Résolution du type et espace de noms système pour
les types | 181
c.c1.c2.a.tasks
c.c1.c2.a.contacts.size()
Résolution du type et espace de noms système pour les types
Puisque que le système type doit résoudre les types définis par l'utilisateur localement ou dans d'autres classes, l'analyseur Apex
évalue les types comme suit :
1.
2.
3.
4.
Pour une référence de type TypeN, l'analyseur commence par examiner ce type en tant que scalaire.
Si TypeN n'est pas trouvé, l'analyseur examine les types définis localement.
Si TypeN n'est toujours pas trouvé, l'analyseur examine une classe portant ce nom.
Si TypeN n'est toujours pas trouvé, l'analyseur examine les types système en tant que sObjects.
Pour le type T1.T2, cela peut correspondre à un type interne T2 dans une classe de niveau supérieur T1, ou une classe de
niveau supérieur T2 dans l'espace de noms T1 (dans l'ordre de précédence).
Paramètres de version
Pour faciliter la rétrocompatibilité, les classes et des déclencheurs sont stockés avec les paramètres d'une version d'API
Salesforce.com spécifique. Si une classe ou un déclencheur Apex référence des composants (par exemple un objet personnalisé)
dans des packages gérés installés, les paramètres de version de chaque package géré que la classe référence sont également
enregistrés. Ainsi, lorsque Apex, l'API et les composants de packages gérés évoluent avec les versions publiées ultérieurement,
une classe ou un déclencheur reste lié aux versions avec un comportement spécifique connu.
La définition d'une version pour un package installé détermine l'interface et le comportement exposés par n'importe quel code
Apex dans le package installé. Cela permet de continuer à référencer un code Apex qui peut être déprécié dans la dernière
version d'un package installé, si vous avez installé une version du package avant la dépréciation du code.
Généralement, vous référencez la dernière version de l'API Salesforce.com et chaque version de package installé. Si vous
enregistrez une classe ou un déclencheur Apex sans spécifier la version de l'API Salesforce.com, la classe ou le déclencheur est
associé par défaut à la dernière version installée. Si vous enregistrez une classe ou un déclencheur Apex qui référence un package
géré sans spécifier la version du package, la classe ou le déclencheur est associé par défaut à la dernière version installée du
package géré.
Définition de la version de l'API Salesforce pour des classes et des déclencheurs
Pour définir la version de l'API et de l'Apex Salesforce.com pour une classe ou un déclencheur :
1. Modifiez une classe ou un déclencheur, puis cliquez sur Paramètres de version.
2. Sélectionnez la Version de l'API Salesforce.com. Il s'agit également de la version Apex associée à la classe ou au déclencheur.
3. Cliquez sur Enregistrer.
Si vous passez un objet en tant que paramètre dans un appel de méthode à partir d'une classe Apex C1 vers une autre classe
C2, et que C2 a différents champs exposés en raison du paramètre de version de l'API Salesforce.com, les champs dans les
objets sont contrôlés par les paramètres de version de la classe C2.
Classes, objets et interfaces
salesforce | Définition de la version de l'API Salesforce pour
des classes et des déclencheurs | 182
En utilisant l'exemple ci-dessous, le champ Categories est défini sur null après avoir appelé la méthode insertIdea
dans la classe C2 à partir d'une méthode dans la classe de test C1, car le champ Categories n'est pas disponible dans la
version 13.0 de l'API.
La première classe est enregistrée en utilisant l'API Salesforce.com version 13.0 :
// This class is saved using Salesforce API version 13.0
// Version 13.0 does not include the Idea.categories field
global class C2
{
global Idea insertIdea(Idea a) {
insert a; // category field set to null on insert
// retrieve the new idea
Idea insertedIdea = [SELECT title FROM Idea WHERE Id =:a.Id];
return insertedIdea;
}
}
La classe suivantes est enregistrée en utilisant l'API Salesforce.com version 16.0 :
@isTest
// This class is bound to API version 16.0 by Version Settings
private class C1
{
static testMethod void testC2Method() {
Idea i = new Idea();
i.CommunityId = '09aD000000004YCIAY';
i.Title = 'Testing Version Settings';
i.Body = 'Categories field is included in API version 16.0';
i.Categories = 'test';
C2 c2 = new C2();
Idea returnedIdea = c2.insertIdea(i);
// retrieve the new idea
Idea ideaMoreFields = [SELECT title, categories FROM Idea
Classes, objets et interfaces
salesforce | Définition de versions de package pour des classes
des déclencheurs Apex | 183
WHERE Id = :returnedIdea.Id];
// assert that the categories field from the object created
// in this class is not null
System.assert(i.Categories != null);
// assert that the categories field created in C2 is null
System.assert(ideaMoreFields.Categories == null);
}
}
Définition de versions de package pour des classes des déclencheurs Apex
Pour configurer les paramètres de version de package pour une classe ou un déclencheur :
1. Modifiez une classe ou un déclencheur, puis cliquez sur Paramètres de version.
2. Sélectionnez une Version pour chaque package géré référencé par la classe ou le déclencheur. Cette version du package
géré continue à être utilisée par la classe ou le déclencheur si des versions ultérieures du package géré sont installées, sauf
si vous mettez manuellement à jour le paramètre de version. Pour ajouter un package géré installé à la liste des paramètres,
sélectionnez un package dans la liste des packages disponibles. Cette liste s'affiche uniquement si un package géré installé
n'est pas déjà associé à la classe ou au déclencheur.
3. Cliquez sur Enregistrer.
Notez les points suivants lors de l'utilisation des paramètres de version de package :
•
•
Si vous enregistrez une classe ou un déclencheur Apex qui référence un package géré sans spécifier la version du package,
la classe ou le déclencheur Apex est associé par défaut à la dernière version installée du package géré.
Vous ne pouvez pas Supprimer le paramètre de version d'une classe ou d'un déclencheur pour un package géré si le package
est référencé dans la classe ou dans le déclencheur. Utilisez Afficher les dépendances afin de déterminer où un package
géré est référencé par une classe ou un déclencheur.
Chapitre 5
Test du code Apex
Sujets :
•
•
•
•
•
Compréhension du test dans Apex
Test unitaire Apex
Exécution de méthodes de test
unitaire
Meilleures pratiques de test
Exemple de test
Le langage Apex fournit une infrastructure de test qui permet d'écrire des tests
unitaires, d'exécuter vos tests, d'examiner les résultats des tests et d'obtenir les
résultats de couverture de code.
Ce chapitre présente les tests unitaires, la visibilité des données de tests, ainsi
que les outils disponibles sur La plate-forme Force.com pour tester le code Apex.
•
•
•
•
•
Compréhension du test dans Apex
Test unitaire Apex
Exécution de méthodes de test unitaire
Meilleures pratiques de test
Exemple de test
Test du code Apex
salesforce | Compréhension du test dans Apex | 185
Compréhension du test dans Apex
Le test est la clé de la réussite du développement à long terme et forme un composant essentiel du processus de développement.
Nous recommandons vivement d'utiliser un processus de développement piloté par des tests, c.-à-d. des tests effectués parallèlement
au développement du code.
Pourquoi tester le code Apex ?
La phase de test est primordiale pour la réussite de votre application, notamment lorsque vous envisagez de la déployer chez
vos clients. Si vous validez le fonctionnement normal de votre application, sans comportement inattendu, vous allez augmenter
la confiance de vos clients dans votre société.
Il existe deux façons de tester une application. La première utilise l'interface utilisateur de Salesforce. Elle est importante, mais
ne permet pas de détecter tous les cas d'utilisation de votre application. La deuxième consiste à tester les fonctionnalités en
masse : jusqu'à 200 enregistrements peuvent être passés par votre code s'il est invoqué en utilisant l'API SOAP ou par un
contrôleur set Visualforce standard.
Une application est rarement terminée. Vous allez publier des versions supplémentaires, qui permettent de modifier et d'étendre
les fonctionnalités. Si vous avez écrit des tests complets, vous pouvez vérifier que les nouvelles fonctionnalités n'entraînent
aucune régression.
Avant de pouvoir déployer votre code ou l'empaqueter pour Force.com AppExchange, les conditions suivantes doivent être
remplies :
•
Au moins 75 % de votre code Apex doit être couvert par des tests unitaires, et tous ces tests doivent être réussis.
Notez les points suivants :
◊ Lors du déploiement d'une organisation de production, chaque test unitaire dans l'espace de noms de votre organisation
est exécuté.
◊ Les appels à System.debug ne sont pas pris en compte dans la couverture du code Apex.
◊ Les méthodes de test et les classes de test ne sont pas prises en compte dans la couverture du code Apex.
◊ Alors que seulement 75 % de votre code Apex doit être couvert par des tests, votre attention ne doit pas se porter sur
le pourcentage du code couvert. Assurez-vous plutôt que chaque cas d'utilisation de votre application est couvert, y
compris les cas positifs et négatifs, ainsi que les enregistrements en masse et uniques. Ils doivent représenter 75 % ou
plus de couverture de votre code par des tests unitaires.
•
•
Chaque déclencheur doit avoir une couverture de test.
Toutes les classes et tous les déclencheurs doivent être compilés avec succès.
Salesforce exécute tous les tests dans l'ensemble des organisations qui ont un code Apex, afin de s'assurer que le comportement
n'est pas altéré par les mises à niveau du service.
Éléments à tester dans un code Apex
Salesforce.com recommande d'écrire des tests pour les éléments suivants :
Action unique
Un test pour vérifier si un enregistrement unique produit un résultat correct et attendu.
Test du code Apex
salesforce | Test unitaire Apex | 186
Actions en masse
Tout code Apex, que ce soit un déclencheur, une classe ou une extension, peut être invoqué pour 1 à 200 enregistrements.
Vous devez tester non seulement le cas d'un enregistrement unique, mais également les cas d'enregistrements multiples.
Comportement positif
Un test pour vérifier si le comportement attendu se produit dans chaque permutation possible, c.-à-d. lorsque l'utilisateur
a renseigné tous les éléments correctement, sans dépasser les limitations.
Comportement négatif
Vos applications présentent souvent des limitations, par exemple l'impossibilité d'ajouter une date future, de spécifier
un montant négatif, etc. Vous devez vérifier que les messages d'erreur s'affichent correctement aussi bien dans les cas
négatifs que dans les cas positifs (lorsque les limitations sont respectées).
Utilisateur restreint
Vérifiez si utilisateur disposant d'un accès limité aux sObjects utilisés dans votre code est soumis à un comportement
attendu, c.-à-d. s'il peut exécuter le code ou recevoir des messages d'erreur.
Remarque: Les opérateurs conditionnels et ternaires ne sont pas considérés comme exécutés tant que les branches
positives et négatives n'ont pas été exécutées.
Pour consulter des exemples de ces types de test, reportez-vous à Exemple de test à la page 195.
Test unitaire Apex
Pour faciliter le développement d'un code robuste et sans erreur, Apex prend en charge la création et l'exécution de tests unitaires.
Les test unitaires sont des méthodes de classe qui vérifient le fonctionnement normal d'une portion de code. Les méthodes de
test unitaires ne prennent aucun argument, ne soumettent aucune donnée à la base de données, n'envoient aucun e-mail et
sont marquées avec le mot clé testMethod dans la définition de la méthode.
Par exemple :
public class myClass {
static testMethod void myTest() {
code_block
}
}
Utilisez l'annotation isTest pour définir des classes ou des méthodes individuelles qui contiennent uniquement le code utilisé
pour tester votre application. L'annotation isTest est semblable à la création de méthodes déclarées testMethod.
Remarque: Les classes définies avec l'annotation isTest ne sont pas prises en compte dans les limitations de votre
organisation de 3 Mo pour l'ensemble du code Apex. Les méthodes de test individuelles dans une classe non annotées
avec isTest sont prises en compte dans la limitation de la taille du code de votre organisation. Reportez-vous à
Compréhension des limitations et des gouverneurs d'exécution à la page 273.
Test du code Apex
salesforce | Isolation des données test de celles de l'organisation
dans les tests unitaires | 187
L'exemple suivant présente une classe de test privé qui contient deux méthodes de test.
@isTest
private class MyTestClass {
// Methods for testing
@isTest static void test1() {
// Implement test code
}
@isTest static void test2() {
// Implement test code
}
}
Considérations sur les tests unitaires
Voici quelques points à noter concernant les tests unitaires.
•
•
•
•
•
Les méthodes de test ne peuvent pas être utilisées pour tester des appels de services Web. Les appels de services Web sont
asynchrones, alors que les tests unitaires sont synchrones.
Vous ne pouvez pas envoyer d'e-mail à partir d'une méthode de test.
Puisque les méthodes de test n'engagent pas les données créées dans le test, il n'est pas nécessaire de supprimer ces données
une fois les tests effectués.
Pour certains sObjects qui incluent des champs avec des contraintes uniques, l'insertion d'enregistrements sObject dupliqués
génère une erreur. Par exemple, l'insertion de sObjects CollaborationGroup portant le même nom entraîne une erreur, car
les enregistrements CollaborationGroup doivent avoir des noms uniques.
Le suivi des modifications pour un enregistrement (FeedTrackedChange records) dans les fils Chatter n'est pas disponible
lorsque les méthodes de test modifient l'enregistrement associé. Les enregistrements FeedTrackedChange nécessitent que
la modification de l'enregistrement parent auquel ils sont associés soit engagée dans la base de données avant leur création.
Puisque les méthodes de test n'engagent pas de données, elles n'entraînent pas la création d'enregistrements
FeedTrackedChange. De la même façon, les enregistrements de suivi d'historique des champs (tels que Historique de
compte) ne peuvent pas être créés dans des méthodes de test, car ils nécessitent l'engagement préalable d'autres
enregistrements (par exemple, Compte).
Voir aussi :
Annotations IsTest
Isolation des données test de celles de l'organisation dans les tests unitaires
À compter du code Apex enregistré en utilisant l'API Salesforce.com versions 24.0 et supérieures, les méthodes de test n'ont
pas accès par défaut aux données préexistantes dans l'organisation, telles que les objets standard, les objets personnalisés et les
Test du code Apex
salesforce | Isolation des données test de celles de l'organisation
dans les tests unitaires | 188
données des paramètres personnalisés, et peuvent accéder uniquement aux données qu'elles créent. Cependant, les objets utilisés
pour gérer votre organisation ou les objets de métadonnées peuvent être accédés dans vos tests, tels que :
•
•
•
•
•
•
•
•
User
Profile
Organization
RecordType
ApexClass
ApexTrigger
ApexComponent
ApexPage
Dès que possible, créez des données test pour chaque test. Vous pouvez désactiver cette restriction en annotant votre classe de
test ou méthode de test avec l'annotation IsTest(SeeAllData=true). Pour plus d'informations, reportez-vous à Annotation
IsTest(SeeAllData=true).
Le code de test enregistré en utilisant l'API Salesforce.com version 23.0 ou antérieure garde accès à toutes les données de
l'organisation et son accès aux données reste inchangé.
Considérations sur l'accès aux données
•
•
•
•
Si une nouvelle méthode de test enregistrée en utilisant l'API Salesforce.com version 24.0 ou supérieure appelle une
méthode dans une autre classe enregistrée avec la version 23.0 ou antérieure, les restrictions d'accès aux données de
l'appelant s'appliquent à la méthode appelée ; c.-à-d. que la méthode appelée n'a pas accès aux données de l'organisation,
car l'appelant ne disposent pas de cet accès, même si la méthode a été enregistrée dans une version antérieure.
Cette restriction d'accès aux données test s'applique à l'ensemble du code exécuté dans un contexte de test. Par
exemple, si une méthode active un déclencheur et que le test n'a pas accès aux données de l'organisation, le déclencheur
n'y a pas accès non plus.
Si un test effectue une requête Visualforce, le test exécuté reste dans un contexte de test, mais il est exécuté dans un
thread différent. Par conséquent, l'isolation des données test ne s'applique plus. Dans ce cas, le test peut accéder à
toutes les données de l'organisation après avoir initialisé la requête Visualforce. Cependant, si la requête Visualforce
exécute un rappel, par exemple un appel distant JavaScript, les données insérées par le rappel ne sont pas visibles par
le test.
Dans certains cas, il peut s'avérer impossible de créer des types de données à partir de votre méthode de test en raison
de limitations spécifiques. Voici quelques exemples de ces limitations.
◊ Il n'est pas possible d'insérer une entrée de catalogue de prix pour un produit à partir d'un test, car le catalogue
de prix standard n'est pas accessible et ne peut pas être créé dans un test en cours d'exécution. En outre, l'insertion
d'une entrée de catalogue de prix à partir d'un catalogue personnalisé n'est pas pris en charge, car elle nécessite la
définition d'un catalogue de prix standard. Dans ce cas, annotez votre méthode de test avec
IsTest(SeeAllData=true) pour permettre à votre test d'accéder aux données de l'organisation.
◊ Certains objets standard ne peuvent pas être créés. Pour plus d'informations sur ces objets, reportez-vous au guide
Object Reference for Salesforce and Force.com.
◊ Pour certains sObjects qui incluent des champs avec des contraintes uniques, l'insertion d'enregistrements sObject
dupliqués génère une erreur. Par exemple, l'insertion de sObjects CollaborationGroup portant le même nom
entraîne une erreur, car les enregistrements CollaborationGroup doivent avoir des noms uniques. Cela se produit
que votre test soit annoté ou non avec IsTest(SeeAllData=true).
◊ Les enregistrements créés uniquement après des enregistrements associés sont validés dans la base de données,
comme les modifications suivies dans Chatter. Le suivi des modifications pour un enregistrement
(FeedTrackedChange records) dans les fils Chatter n'est pas disponible lorsque les méthodes de test modifient
Test du code Apex
salesforce | Utilisation de la méthode runAs | 189
l'enregistrement associé. Les enregistrements FeedTrackedChange nécessitent que la modification de
l'enregistrement parent auquel ils sont associés soit engagée dans la base de données avant leur création. Puisque
les méthodes de test n'engagent pas de données, elles n'entraînent pas la création d'enregistrements
FeedTrackedChange. De la même façon, les enregistrements de suivi d'historique des champs (tels que Historique
de compte) ne peuvent pas être créés dans des méthodes de test, car ils nécessitent l'engagement préalable d'autres
enregistrements (par exemple, Compte).
Utilisation de la méthode runAs
Généralement, l'ensemble du code Apex est exécuté en mode système, et les autorisations et le partage d'enregistrement de
l'utilisateur actuel ne sont pas pris en compte. La méthode système runAs permet d'écrire des méthodes de test qui changent
le contexte de l'utilisateur en utilisateur existant ou en nouvel utilisateur, ou d'exécuter en utilisant le code d'une version
spécifique d'un package géré. Lors de l'exécution en tant qu'utilisateur, l'ensemble du partage d'enregistrement de cet utilisateur
s'applique. Vous pouvez également utiliser runAs dans une méthode de test. Le contexte système d'origine est redémarré une
fois toutes les méthodes de test runAs terminées. Pour plus d'informations sur l'utilisation de la méthode runAs et la
spécification du contexte de version d'un package, reportez-vous à Test du comportement dans des versions de package à la
page 284.
Remarque: Chaque appel à runAs est pris en compte dans le nombre total d'instructions DML émises dans le
processus.
Dans l'exemple suivant, un utilisateur test est créé, puis le code est exécuté sous l'identité de cet utilisateur avec ses autorisations
et son accès aux enregistrements :
public class TestRunAs {
public static testMethod void testRunAs() {
// Setup test data
// This code runs as the system user
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User u = new User(Alias = 'standt', Email='[email protected]',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='[email protected]');
System.runAs(u) {
// The following code runs as user 'u'
System.debug('Current User: ' + UserInfo.getUserName());
System.debug('Current Profile: ' + UserInfo.getProfileId()); }
}
Test du code Apex
salesforce | Utilisation de la méthode runAs | 190
}
Vous pouvez imbriquer plusieurs méthodes runAs. Par exemple :
public class TestRunAs2 {
public static testMethod void test2() {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User u2 = new User(Alias = 'newUser', Email='[email protected]',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='[email protected]');
System.runAs(u2) {
// The following code runs as user u2.
System.debug('Current User: ' + UserInfo.getUserName());
System.debug('Current Profile: ' + UserInfo.getProfileId());
// The following code runs as user u3.
User u3 = [SELECT Id FROM User WHERE UserName='[email protected]'];
System.runAs(u3) {
System.debug('Current User: ' + UserInfo.getUserName());
System.debug('Current Profile: ' + UserInfo.getProfileId());
}
// Any additional code here would run as user u2.
}
}
}
Meilleures pratiques d'utilisation de runAs
Les éléments suivants utilisent les autorisations accordées par l'utilisateur spécifié avec runAs, exécuté en tant qu'utilisateur
spécifique :
•
•
Apex dynamique
Méthodes utilisant with sharing ou without sharing
Test du code Apex
•
salesforce | Utilisation de limitations, startTest, et
stopTest | 191
Enregistrements partagés
Les autorisations d'origine sont réinitialisées une fois runAs terminé.
La méthode runAs ignore les limites en licences utilisateur. Vous pouvez créer des utilisateurs avec runAs même si votre
organisation n'a plus de licences utilisateur supplémentaires.
Utilisation de limitations, startTest, et stopTest
Les méthodes Limits renvoient la limite spécifique du gouverneur particulier, notamment le nombre d'appels d'une méthode
ou la taille du segment mémoire restant.
Il existe deux versions de chaque méthode : La première renvoie la quantité de ressources qui ont été utilisées dans le contexte
actuel, alors que la deuxième version contient le terme « limit » et renvoie la quantité totale de ressources disponibles pour ce
contexte. Par exemple, getCallouts renvoie le nombre d'appels à un service externe qui ont déjà été traités dans le contexte
actuel, alors que getLimitCallouts renvoie le nombre total d'appels disponibles dans le contexte donné.
En plus des méthodes Limits, utilisez les méthodes startTest et stopTest pour valider la proximité du code des limites
du gouverneur.
La méthode startTest marque dans votre code test le point auquel le test commence. Chaque testMethod est autorisé
à appeler une seule fois cette méthode. Tout le code qui précède cette méthode être utilisé pour initialiser des variables,
renseigner des structures de données, etc., permettant de définir tout ce dont vous avez besoin pour exécuter votre test. Tout
code exécuté après l'appel à startTest et avant stopTest se voit attribuer un nouvel ensemble de limitations du gouverneur.
La méthode startTest n'actualise pas le contexte du test : elle ajoute un contexte à votre test. Par exemple, si votre classe
effectue 98 requêtes SOQL avant d'appeler startTest, et que la première instruction significative après startTest est une
instruction DML, le programme peut maintenant effectuer 100 requêtes supplémentaires. Toutefois, une fois stopTest
appelé, le programme revient dans le contexte d'origine et peut effectuer 2 requêtes SOQL supplémentaires seulement avant
d'atteindre la limite de 100.
La méthode stopTest marque dans votre code test le point auquel le test se termine. Utilisez cette méthode conjointement
à la méthode startTest. Chaque testMethod est autorisé à appeler une seule fois cette méthode. Tout code exécuté après
la méthode stopTest se voit attribuer les limitations d'origine qui étaient en vigueur avant l'appel de startTest. Tous les
appels asynchrones effectués après la méthode startTest sont collectés par le système. Lors de l'exécution de stopTest,
tous les processus asynchrones sont exécutés de façon synchrone.
Ajout de requêtes SOSL à des tests unitaires
Pour garantir un comportement cohérent pour les méthodes de test, toute requête SOSL (Object Search Language) Salesforce
qui est ajoutée à une méthode de test Apex renvoie un ensemble vide de résultats de recherche lors de l'exécution de la méthode.
Si vous ne souhaitez pas que la requête renvoie une liste de résultats vide, vous pouvez utiliser la méthode système
Test.setFixedSearchResults pour définir une liste d'ID d'enregistrements qui sont renvoyés par la recherche. Toutes
les requêtes SOSL exécutées ultérieurement dans la méthode de test renvoient la liste des ID d'enregistrement qui ont été
spécifiés par la méthode Test.setFixedSearchResults. De plus, la méthode de test peut appeler
Test.setFixedSearchResults plusieurs fois pour définir différents ensembles de résultats pour différentes requêtes
SOSL. Si vous n'appelez pas la méthode Test.setFixedSearchResults dans une méthode de test ou si vous appelez
cette méthode sans spécifier de liste d'ID d'enregistrement, toutes les requêtes SOSL exécutées ultérieurement dans la méthode
de test renvoient une liste de résultats vide.
Test du code Apex
salesforce | Exécution de méthodes de test unitaire | 192
La liste des ID d'enregistrement spécifiés par la méthode Test.setFixedSearchResults remplace les résultats qui seraient
normalement renvoyés par la requête SOSL si elle n'était soumise à aucune clause WHERE ou LIMIT. Si ces clauses existent
dans la requête SOSL, elles s'appliquent à la liste des résultats de recherche fixes. Par exemple :
public class SoslFixedResultsTest1 {
public static testMethod void testSoslFixedResults() {
Id [] fixedSearchResults= new Id[1];
fixedSearchResults[0] = '001x0000003G89h';
Test.setFixedSearchResults(fixedSearchResults);
List<List<SObject>> searchList = [FIND 'test'
IN ALL FIELDS RETURNING
Account(id, name WHERE name = 'test' LIMIT 1)];
}
}
Bien que l'enregistrement Account avec l'ID 001x0000003G89h peut ne pas correspondre à la chaîne de requête dans la
clause FIND ('test'), l'enregistrement est passé dans la clause RETURNING de l'instruction SOSL. Si l'enregistrement avec
l'ID 001x0000003G89h correspond au filtre de la clause WHERE, l'enregistrement est renvoyé. S'il ne correspond pas à la
clause WHERE, aucun n'enregistrement n'est renvoyé.
Exécution de méthodes de test unitaire
Vous pouvez exécuter des tests unitaires pour :
•
•
•
Une classe spécifique
Un sous-ensemble de classes
Tous les tests unitaires de votre organisation
Pour exécuter un test, utilisez l'un des éléments suivants :
•
•
•
L'interface utilisateur de Salesforce
L'IDE Force.com
L'API
Exécution de tests via l'interface utilisateur de Salesforce
Vous pouvez exécuter des tests unitaires à l'aide de la page Exécution du test Apex. Les tests démarrés sur cette page sont
exécutés de façon asynchrone, c.-à-d. qu'ils n'ont pas à attendre la fin de l'exécution d'une classe de test. La page Exécution
du test Apex actualise le statut d'un test et affiche les résultats une fois le test terminé.
Test du code Apex
salesforce | Exécution de méthodes de test unitaire | 193
Pour utiliser la page Exécution du test Apex :
1. Cliquez sur Votre nom > Configuration > Développer > Exécution du test Apex.
2. Cliquez sur Sélectionner des tests.
Remarque: Si vous avez des classes Apex installées à partir d'un package géré, commencez par compiler ces classes
en cliquant sur Compiler toutes les classes dans la page Classes Apex pour les afficher dans la liste. Reportez-vous
à Gestion des classes Apex.
3. Sélectionnez les tests à exécuter. La liste des tests inclut des classes qui contiennent des méthodes de test.
•
•
•
Pour sélectionner des tests à partir d'un package géré installé, sélectionnez leur espace de noms correspondant dans la
liste déroulante. Seules les classes du package de géré avec l'espace de noms sélectionné sont affichées dans la liste.
Pour sélectionner des tests qui existent localement dans votre organisation, sélectionnez [Mon espace de noms] dans
la liste déroulante. Seules les classes locales qui ne proviennent pas de packages gérés sont affichées dans la liste.
Pour sélectionner un test, sélectionnez [Tous les espaces de noms] dans la liste déroulante. Toutes les classes de
l'organisation sont affichées, quelles proviennent ou non d'un package géré.
Remarque: Les classes dont les tests sont en cours d'exécution ne sont pas affichées dans la liste.
4. Cliquez sur Exécuter.
Après l'exécution de tests à l'aide de la page Exécution du test Apex, vous pouvez afficher le pourcentage de couverture de
code par ces tests dans la liste de classes Apex. Cliquez sur Votre nom > Configuration > Développer > Classes Apex, puis
cliquez sur Calculer le code de couverture de votre organisation.
Remarque: La valeur de la couverture de code calculée par Calculer la couverture du code de votre organisation
peut différer de la valeur de la couverture de code calculée par l'exécution de tous les tests unitaires en utilisant Exécuter
tous les tests. En effet, l'option Calculer la couverture du code de votre organisation exclut les classes qui font partie
de packages gérés installés, contrairement à Exécuter tous les tests.
Vous pouvez également déterminer quelles lignes de code sont couvertes par des tests pour une classe individuelle. Cliquez
sur Votre nom > Configuration > Développer > Classes Apex, puis sur la valeur de pourcentage dans la colonne Couverture
du code d'une classe.
Cliquez sur Votre nom > Configuration > Développer > Exécution du testApex > Afficher l'historique des tests pour
afficher tous les résultats des tests de votre organisation, pas seulement les tests que vous avez exécutés. Une fois les tests
exécutés, les résultats sont conservés pendant 30 jours, sauf s'ils sont supprimés.
Test du code Apex
salesforce | Meilleures pratiques de test | 194
Exécution de tests en utilisant l'IDE Force.com
De plus, vous pouvez exécuter des tests avec l'IDE Force.com (reportez-vous à
https://wiki.developerforce.com/index.php/Apex_Toolkit_for_Eclipse).
Meilleures pratiques de test
Des tests de qualité doivent respecter les points suivants :
•
Couvrir autant de lignes de code que possible. Avant de pouvoir déployer votre code Apex ou de l'empaqueter pour
Force.com AppExchange, les conditions suivantes doivent être remplies.
Important:
◊ Au moins 75 % de votre code Apex doit être couvert par des tests unitaires, et tous ces tests doivent être réussis.
Notez les points suivants :
-
Lors du déploiement d'une organisation de production, chaque test unitaire dans l'espace de noms de votre
organisation est exécuté.
Les appels à System.debug ne sont pas pris en compte dans la couverture du code Apex.
Les méthodes de test et les classes de test ne sont pas prises en compte dans la couverture du code Apex.
Alors que seulement 75 % de votre code Apex doit être couvert par des tests, votre attention ne doit pas se
porter sur le pourcentage du code couvert. Assurez-vous plutôt que chaque cas d'utilisation de votre
application est couvert, y compris les cas positifs et négatifs, ainsi que les enregistrements en masse et
uniques. Ils doivent représenter 75 % ou plus de couverture de votre code par des tests unitaires.
◊ Chaque déclencheur doit avoir une couverture de test.
◊ Toutes les classes et tous les déclencheurs doivent être compilés avec succès.
•
•
•
•
•
•
•
•
•
•
En cas de logique conditionnelle (comprenant des opérateurs ternaires), exécuter chaque branche de logique de code.
Effectuer des appels à des méthodes en utilisant des entrées valides et non valides.
Réussir sans lever aucune exception, sauf si ces erreurs sont attendues et détectées dans un bloc try…catch.
Toujours traiter toutes les exceptions détectées, ne pas se contenter de leur détection.
Utiliser des méthodes System.assert pour démontrer que le code ce comporte correctement.
Utiliser la méthode runAs pour tester votre application dans différents contextes utilisateur.
Utiliser l'annotation isTest. Les classes définies avec l'annotation isTest ne sont pas prises en compte dans les limitations
de votre organisation de 3 Mo pour l'ensemble du code Apex. Reportez-vous à Annotation IsTest à la page 162.
Pratiquer la fonctionnalité de déclencheur en masse : utiliser au moins 20 enregistrements dans les tests.
Utiliser les mots clés ORDER BY pour s'assurer que les enregistrements sont renvoyés dans l'ordre attendu.
Ne pas supposer que les ID d'enregistrement sont dans l'ordre séquentiel.
Les ID d'enregistrement ne sont pas créés dans l'ordre ascendant, sauf si vous insérez plusieurs enregistrements dans la
même requête. Par exemple, si vous créez un compte A et recevez l'ID 001D000000IEEmT, puis créez le compte B, l'ID
du compte B peut être ou non plus haut dans la séquence.
•
La liste des classes Apex contient une colonne Couverture de code. Si vous cliquez sur la valeur du pourcentage de couverture,
une page s'ouvre. Elle indique en bleu toutes les lignes de code de cette classe ou de ce déclencheur qui sont couvertes par
Test du code Apex
•
salesforce | Exemple de test | 195
des tests, et en rouge toutes les lignes de code qui ne sont pas couvertes par des tests. Elle indique également le nombre de
fois qu'une ligne donnée dans la classe ou le déclencheur a été exécutée par le test.
Configurer des données test :
◊ Créez les données nécessaires dans des classes de test afin d'éviter que les tests dépendent des données d'une organisation
particulière.
◊ Créez toutes les données test avant d'appeler la méthode starttest.
◊ Puisque les tests ne sont pas engagés, il n'est pas nécessaire de supprimer les données.
•
•
Écrire des commentaires précisant non seulement les éléments à tester, mais également les hypothèses du testeur concernant
les données, le résultat attendu, etc.
Tester les classes individuellement dans votre application. Ne jamais tester l'application entière dans un test unique.
Si vous exécutez de nombreux tests, notez les points suivants :
•
•
Dans l'IDE Force.com, il peut être nécessaire d'augmenter la valeur Read timeout pour votre projet Apex. Pour plus
d'informations, reportez-vous à https://wiki.developerforce.com/index.php/Apex_Toolkit_for_Eclipse.
Dans l'interface utilisateur de Salesforce, il peut être nécessaire de tester individuellement les classes de votre organisation,
au lieu d'essayer d'exécuter tous les tests à la fois via le bouton Exécuter tous les tests.
Exemple de test
L'exemple suivant inclut des requêtes pour les types de test suivants :
•
•
•
Cas positif avec des enregistrements uniques et multiples
Cas négatif avec des enregistrements uniques et multiples
Test avec d'autres utilisateurs
Le test est utilisé dans une simple application de suivi de la distance parcourue (en miles). Le code existant de l'application
vérifie que la distance maximale saisie pour une seule journée ne dépasse pas 500 miles. L'objet principal est un objet personnalisé
appelé Mileage__c. Voici la classe de test complète. Les sections suivantes présentent pas à pas des portions spécifiques du
code.
@isTest
private class MileageTrackerTestSuite {
static testMethod void runPositiveTestCases() {
Double totalMiles = 0;
final Double maxtotalMiles = 500;
final Double singletotalMiles = 300;
final Double u2Miles = 100;
Test du code Apex
salesforce | Exemple de test | 196
//Set up user
User u1 = [SELECT Id FROM User WHERE Alias='auser'];
//Run As U1
System.RunAs(u1){
System.debug('Inserting 300
miles... (single record validation)');
Mileage__c testMiles1 = new Mileage__c(Miles__c = 300, Date__c = System.today());
insert testMiles1;
//Validate single insert
for(Mileage__c m:[SELECT miles__c FROM Mileage__c
WHERE CreatedDate = TODAY
and CreatedById = :u1.id
and miles__c != null]) {
totalMiles += m.miles__c;
}
System.assertEquals(singletotalMiles, totalMiles);
//Bulk validation
totalMiles = 0;
System.debug('Inserting 200 mileage records... (bulk validation)');
List<Mileage__c> testMiles2 = new List<Mileage__c>();
for(integer i=0; i<200; i++) {
testMiles2.add( new Mileage__c(Miles__c = 1, Date__c = System.today()) );
}
insert testMiles2;
Test du code Apex
salesforce | Exemple de test | 197
for(Mileage__c m:[SELECT miles__c FROM Mileage__c
WHERE CreatedDate = TODAY
and CreatedById = :u1.Id
and miles__c != null]) {
totalMiles += m.miles__c;
}
System.assertEquals(maxtotalMiles, totalMiles);
}//end RunAs(u1)
//Validate additional user:
totalMiles = 0;
//Setup RunAs
User u2 = [SELECT Id FROM User WHERE Alias='tuser'];
System.RunAs(u2){
Mileage__c testMiles3 = new Mileage__c(Miles__c = 100, Date__c = System.today());
insert testMiles3;
for(Mileage__c m:[SELECT miles__c FROM Mileage__c
WHERE CreatedDate = TODAY
and CreatedById = :u2.Id
and miles__c != null]) {
totalMiles += m.miles__c;
}
//Validate
System.assertEquals(u2Miles, totalMiles);
} //System.RunAs(u2)
} // runPositiveTestCases()
Test du code Apex
salesforce | Exemple de test | 198
static testMethod void runNegativeTestCases() {
User u3 = [SELECT Id FROM User WHERE Alias='tuser'];
System.RunAs(u3){
System.debug('Inserting a record with 501 miles... (negative test case)');
Mileage__c testMiles3 = new Mileage__c( Miles__c = 501, Date__c = System.today() );
try {
insert testMiles3;
} catch (DmlException e) {
//Assert Error Message
System.assert( e.getMessage().contains('Insert failed. First exception on ' +
'row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, ' +
'Mileage request exceeds daily limit(500): [Miles__c]'),
e.getMessage() );
//Assert field
System.assertEquals(Mileage__c.Miles__c, e.getDmlFields(0)[0]);
//Assert Status Code
System.assertEquals('FIELD_CUSTOM_VALIDATION_EXCEPTION' ,
e.getDmlStatusCode(0) );
} //catch
} //RunAs(u3)
} // runNegativeTestCases()
} // class MileageTrackerTestSuite
Cas de test positif
La procédure suivante présente les étapes du code pour le cas de test positif pour des enregistrements uniques et multiples.
Test du code Apex
salesforce | Exemple de test | 199
1. Ajoutez un texte au journal de débogage, en indiquant l'étape suivante du code :
System.debug('Inserting 300 more miles...single record validation');
2. Créez un objet Mileage__c object, puis insérez-le dans la base de données.
Mileage__c testMiles1 = new Mileage__c(Miles__c = 300, Date__c = System.today() );
insert testMiles1;
3. Validez le code en renvoyant les enregistrements insérés :
for(Mileage__c m:[SELECT miles__c FROM Mileage__c
WHERE CreatedDate = TODAY
and CreatedById = :createdbyId
and miles__c != null]) {
totalMiles += m.miles__c;
}
4. Utilisez la méthode system.assertEquals pour vérifier que le résultat attendu est renvoyé :
System.assertEquals(singletotalMiles, totalMiles);
5. Avant de passer au test suivant, définissez le nombre total de miles sur 0 :
totalMiles = 0;
6. Validez le code en créant une insertion en masse de 200 enregistrements.
Commencez par ajouter un texte au journal de débogage, en indiquant l'étape suivante du code :
System.debug('Inserting 200 Mileage records...bulk validation');
7. Insérez ensuite 200 enregistrements Mileage__c :
List<Mileage__c> testMiles2 = new List<Mileage__c>();
for(Integer i=0; i<200; i++){
testMiles2.add( new Mileage__c(Miles__c = 1, Date__c = System.today()) );
}
insert testMiles2;
Test du code Apex
salesforce | Exemple de test | 200
8. Utilisez System.assertEquals pour vérifier que le résultat attendu est renvoyé :
for(Mileage__c m:[SELECT miles__c FROM Mileage__c
WHERE CreatedDate = TODAY
and CreatedById = :CreatedbyId
and miles__c != null]) {
totalMiles += m.miles__c;
}
System.assertEquals(maxtotalMiles, totalMiles);
Cas de test négatif
La procédure suivante présente les étapes du code pour le cas de test négatif.
1. Créez une méthode de test statique appelée runNegativeTestCases :
static testMethod void runNegativeTestCases(){
2. Ajoutez un texte au journal de débogage, en indiquant l'étape suivante du code :
System.debug('Inserting 501 miles... negative test case');
3. Créez un enregistrement Mileage__c record avec 501 miles.
Mileage__c testMiles3 = new Mileage__c(Miles__c = 501, Date__c = System.today());
4. Placez l'instruction insert dans un bloc try/catch. Cela permet de capturer l'exception de validation et de déclarer le
message d'erreur généré.
try {
insert testMiles3;
} catch (DmlException e) {
5. Utilisez maintenant System.assert et System.assertEquals pour effectuer le test. Ajoutez le code suivant au bloc
catch créé précédemment :
//Assert Error Message
System.assert(e.getMessage().contains('Insert failed. First exception '+
'on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, '+
'Mileage request exceeds daily limit(500): [Miles__c]'),
Test du code Apex
salesforce | Exemple de test | 201
e.getMessage());
//Assert Field
System.assertEquals(Mileage__c.Miles__c, e.getDmlFields(0)[0]);
//Assert Status Code
System.assertEquals('FIELD_CUSTOM_VALIDATION_EXCEPTION'
,
e.getDmlStatusCode(0));
}
}
}
Test d'un deuxième utilisateur
La procédure suivante présente les étapes du code pour l'exécution d'un deuxième utilisateur.
1. Avant de passer au test suivant, définissez le nombre total de miles sur 0 :
totalMiles = 0;
2. Configurez l'utilisateur suivant.
User u2 = [SELECT Id FROM User WHERE Alias='tuser'];
System.RunAs(u2){
3. Ajoutez un texte au journal de débogage, en indiquant l'étape suivante du code :
System.debug('Setting up testing - deleting any mileage records for ' +
UserInfo.getUserName() +
' from today');
4. Insérez ensuite un enregistrement Mileage__c :
Mileage__c testMiles3 = new Mileage__c(Miles__c = 100, Date__c = System.today());
insert testMiles3;
5. Validez le code en renvoyant les enregistrements insérés :
for(Mileage__c m:[SELECT miles__c FROM Mileage__c
WHERE CreatedDate = TODAY
Test du code Apex
salesforce | Exemple de test | 202
and CreatedById = :u2.Id
and miles__c != null]) {
totalMiles += m.miles__c;
}
6. Utilisez la méthode system.assertEquals pour vérifier que le résultat attendu est renvoyé :
System.assertEquals(u2Miles, totalMiles);
Chapitre 6
Apex dynamique
Sujets :
•
•
•
•
Compréhension de l'information
Describe Apex
Requête SOQL dynamique
Requête SOSL dynamique
Requêtes DML dynamiques
Un code Apex dynamique permet aux développeurs de créer des applications plus
flexibles en leur permettant d'effectuer les opérations suivantes :
•
Accéder à l'information describe de sObject et de champ
L'information Describe fournit des détails sur les propriétés de sObject et de
champ. Par exemple, l'information describe d'un sObject indique si le type
de sObject prend en charge des opérations telles que la création ou l'annulation
de la suppression, le nom et l'étiquette du sObject, les champs et les objets
enfant du sObject, etc. L'information describe d'un champ indique s'il a une
valeur par défaut, que ce soit un champ calculé, le type du champ, etc.
Notez que l'information describe fournit des détails sur les objets d'une
organisation, pas sur des enregistrements individuels.
•
Écrire des requêtes SOQL dynamiques, des requêtes SOSL dynamiques et
des requêtes DML dynamiques
Les requêtes SOQL et SOSL dynamiques permettent d'exécuter SOQL ou
SOSL en tant que chaîne à l'exécution, alors que le DML dynamique permet
de créer un enregistrement de façon dynamique, puis de l'insérer dans la base
de données à l'aide du langage de manipulation de données DML. En utilisant
des SOQL, SOSL et DML dynamiques, une application peut être adaptée
avec précision à l'organisation ainsi qu'aux autorisations de l'utilisateur. Elles
peuvent s'avérer utiles pour les applications qui ont été installées à partir de
Force.com AppExchange.
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 204
Compréhension de l'information Describe Apex
Le langage Apex fournit deux structures de données pour l'information describe d'un sObject et d'un champ :
•
•
Jeton : une référence, légère et qui peut être sérialisée, et à un sObject ou à un champ qui est validée lors de la compilation.
Résultat Describe : un objet qui contient toutes les propriétés describe du sObject ou du champ. Les objets de résultat
Describe ne peuvent pas être sérialisés, et ils sont validés à l'exécution.
Le passage d'un jeton à son résultat describe, et inversement, est aisé. Les deux jetons de sObject et de champ incluent la
méthode getDescribe qui renvoie le résultat describe pour ce jeton. Dans le résultat describe, les méthodes getSObjectType
et getSObjectField renvoient les jetons de sObject et de champ, respectivement.
Les jetons étant légers, leur utilisation peut accélérer votre code et le rendre plus efficace. Par exemple, utilisez la version du
jeton d'un sObject ou d'un champ pour déterminer le type d'un sObject ou d'un champ que votre code doit utiliser. Le jeton
peut être comparé en utilisant l'opérateur d'égalité (==) afin de déterminer si un sObject est l'objet Compte, par exemple, ou
si un champ est le champ Nom ou un champ calculé personnalisé.
L'exemple de code suivant montre comment utiliser des jetons et des résultats describe pour accéder à des informations sur
les propriétés de sObject et de champ :
// Create a new account as the generic type sObject
sObject s = new Account();
// Verify that the generic sObject is an Account sObject
System.assert(s.getsObjectType() == Account.sObjectType);
// Get the sObject describe result for the Account object
Schema.DescribeSObjectResult r = Account.sObjectType.getDescribe();
// Get the field describe result for the Name field on the Account object
Schema.DescribeFieldResult f = Schema.sObjectType.Account.fields.Name;
// Verify that the field token is the token for the Name field on an Account object
System.assert(f.getSObjectField() == Account.Name);
// Get the field describe result from the token
f = f.getSObjectField().getDescribe();
L'algorithme suivant montre comment utiliser l'information describe dans le langage Apex :
1. Générez une liste ou un mappage de jetons pour les sObjects de votre organisation (reportez-vous à Accès à tous les sObjects
à la page 207).
2. Déterminez le sObject auquel vous devez accéder.
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 205
3. Générez le résultat describe du sObject.
4. Si nécessaire, générez un mappage des jetons de champ pour le sObject (reportez-vous à Accès à tous les résultats Describe
de champ d'un sObject à la page 209).
5. Générez le résultat describe pour le champ auquel le code doit accéder.
Compréhension des autorisations de l'information Describe
Un code Apex est généralement exécuté en mode système. Toutes les classes et tous les déclencheurs qui ne sont pas inclus
dans un package, c.-à-d. natifs pour votre organisation, n'ont aucune restriction sur les sObjects qu'ils peuvent référencer
dynamiquement. Cela signifie qu'avec un code natif, vous pouvez générer un mappage de tous les sObjects de votre organisation,
quelles que soient les autorisations de l'utilisateur actuel.
Le code Apex dynamique, inclus dans des packages gérés créés par des partenaires FAI de salesforce.com et installés à partir
de Force.com AppExchange, a un accès restreint à tout sObject extérieur au package géré. Les partenaires de peuvent définir
la valeur Accès API au sein du package pour accorder l'accès aux sObjects standard qui ne sont pas inclus dans le package
géré. Alors que les partenaires peuvent demander l'accès aux objets standard, les objets personnalisés ne sont pas inclus dans
le package géré et ne peuvent jamais être référencés ni accédés par un code Apex dynamique d'un package.
Pour plus d'informations, reportez-vous à « À propos de l'accès API et Apex dynamique dans les packages » dans l'aide en
ligne de Salesforce.
Utilisation des jetons d'un sObject
Les sObject, tels que Compte et MyCustomObject__c, agissent en tant que classes statiques avec des méthodes statiques
spéciales et des variables de membre pour accéder aux informations de jeton et de résultat describe. Vous devez référencer
explicitement un sObject et un nom de champ lors de la compilation pour avoir accès au résultat describe.
Pour accéder au jeton d'un sObject, utilisez l'une des méthodes suivantes :
Accédez au membre de variable sObjectType dans un type sObject, tel que Compte.
Appelez la méthode getSObjectType dans un résultat describe sObject, une variable sObject, une liste ou un mappage.
•
•
Schema.SObjectType est le type de données d'un jeton sObject.
Dans l'exemple suivant, le jeton du sObject Account est renvoyé :
Schema.sObjectType t = Account.sObjectType;
Le code suivant renvoie également un jeton pour le sObject Account :
Account A = new Account();
Schema.sObjectType T = A.getSObjectType();
Cet exemple peut être utilisé pour déterminer si un sObject ou une liste de sObject correspond à un type particulier :
public class sObjectTest {
{
// Create a generic sObject variable s
SObject s = Database.query('SELECT Id FROM Account LIMIT 1');
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 206
// Verify if that sObject variable is an Account token
System.assertEquals(s.getSObjectType(), Account.sObjectType);
// Create a list of generic sObjects
List<sObject> l = new Account[]{};
// Verify if the list of sObjects contains Account tokens
System.assertEquals(l.getSObjectType(), Account.sObjectType);
}
}
Certains sObject standard ont un champ appelé sObjectType, par exemple AssignmentRule, QueueSObject et RecordType.
Pour ces types de sObject, utilisez toujours la méthode getSObjectType pour récupérer le jeton. Si vous utilisez la propriété,
par exemple RecordType.sObjectType, le champ est renvoyé.
Utilisation des résultats describe de sObject
Pour accéder au résultat describe d'un sObject, utilisez l'une des méthodes suivantes :
•
•
Appelez la méthode getDescribe dans un jeton sObject.
Utilisez la variable statique Schema sObjectType avec le nom du sObject. Par exemple, Schema.sObjectType.Lead.
Schema.DescribeSObjectResult est le type de données du résultat describe d'un sObject.
L'exemple suivant utilise la méthode getDescribe dans un jeton sObject :
Schema.DescribeSObjectResult D = Account.sObjectType.getDescribe();
L'exemple suivant utilise la variable de membre statique Schema sObjectType :
Schema.DescribeSObjectResult D = Schema.SObjectType.Account;
Pour plus d'informations sur les méthodes disponibles avec des résultats describe d'un sObject, reportez-vous à Méthodes de
résultat Describe d'un sObject à la page 442.
Utilisation de jetons de champ
Pour accéder au jeton d'un champ, utilisez l'une des méthodes suivantes :
•
•
Accédez au nom de la variable membre statique d'un type statique de sObject, par exemple Account.Name.
Appelez la méthode getSObjectField dans le résultat describe d'un champ.
Le jeton du champ utilise le type de données Schema.SObjectField.
Dans l'exemple suivant, le jeton du champ est renvoyé pour le champ AccountNumber de l'objet Account :
Schema.SObjectField F = Account.AccountNumber;
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 207
Dans l'exemple suivant, le jeton du champ est renvoyé à partir du résultat describe du champ :
// Get the describe result for the Name field on the Account object
Schema.DescribeFieldResult f = Schema.sObjectType.Account.fields.Name;
// Verify that the field token is the token for the Name field on an Account object
System.assert(f.getSObjectField() == Account.Name);
// Get the describe result from the token
f = f.getSObjectField().getDescribe();
Utilisation des résultats describe de champ
Pour accéder au résultat describe d'un champ, utilisez l'une des méthodes suivantes :
•
•
Appelez la méthode getDescribe dans un jeton de champ.
Accédez à la variable de membre fields d'un jeton de sObject avec une variable de membre de champ (telle que Name,
BillingCity, etc.).
Le résultat describe de champ utilise le type de données Schema.DescribeFieldResult.
L'exemple suivant utilise la méthode getDescribe :
Schema.DescribeFieldResult F = Account.AccountNumber.getDescribe();
Cet exemple utilise la méthode de variable de membre fields :
Schema.DescribeFieldResult F = Schema.SObjectType.Account.fields.Name;
Dans l'exemple ci-dessus, le système utilise une analyse spéciale pour confirmer lors de la compilation que la variable de membre
finale (Name) est valide pour le sObject spécifié. Lorsque l'analyseur trouve la variable de membre fields, il recherche en
arrière pour trouver le nom du sObject (Account), et confirme que le nom du champ qui suit la variable de membre fields
est légitime. La variable de membre fields fonctionne uniquement lorsqu'elle est utilisée de cette façon.
Vous pouvez avoir 100 instructions de variable de membre fields dans une classe ou un déclencheur Apex.
Remarque: Vous ne devez pas utiliser la variable de membre fields sans utiliser également un nom de variable de
membre de champ ou la méthode getMap. Pour plus d'informations sur getMap, reportez-vous à Accès à tous les
résultats Describe de champ d'un sObject à la page 209.
Pour plus d'informations sur les méthodes disponibles avec le résultat describe d'un champ, reportez-vous à Méthodes de
résultat Describe d'un champ à la page 446.
Accès à tous les sObjects
Utilisez la méthode Schema getGlobalDescribe pour renvoyer un mappage qui représente la relation entre tous les noms
de sObject (clés) et les jetons de sObject (valeurs). Par exemple :
Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 208
Le mappage a les caractéristiques suivantes :
•
•
•
•
Il est dynamique, c.-à-d. qu'il est généré à l'exécution dans les sObjects actuellement disponibles pour l'organisation, en
fonction d'autorisations.
Les noms de sObject ne sont pas sensibles à la casse.
Les clés utilisent les espaces de noms requis.
Les clés indiquent si le sObject est un objet personnalisé.
Par exemple, si le bloc de code qui génère le mappage se trouve dans un espace de noms N1 et qu'un sObject est également
dans N1, la clé est représentée par MyObject__c dans le mappage. Cependant, si le bloc de code se trouve dans un espace
de noms N1 et que le sObject est dans un espace de noms N2, la clé est N2__MyObject__c.
De plus, les sObjects standard n'ont pas de préfixe d'espace de noms.
Remarque: Si la méthode getGlobalDescribe est appelée dans un package géré installé, elle renvoie les noms de
sObject et les jetons de sObjects Chatter, tels que NewsFeed et UserProfileFeed, même si Chatter n'est pas activé
dans l'organisation d'installation. Cela n'est pas vrai si la méthode getGlobalDescribe est appelée à partir d'une
classe qui ne figure pas dans un package géré installé.
Création de sObjects de façon dynamique
Vous pouvez créer des sObjects dont les types sont déterminés à l'exécution en appelant la méthode newSObject de la classe
de jeton sObject Schema.sObjectType. L'exemple suivant montre comment obtenir un jeton sObject qui correspond à un
nom de type de sObject en utilisant la méthode Schema.getGlobalDescribe. Une instance de sObject est ensuite créée
via la méthode newSObject de Schema.sObjectType. Cet exemple contient également une méthode de test qui vérifie la
création dynamique d'un compte.
public class DynamicSObjectCreation {
public static sObject createObject(String typeName) {
Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName);
if (targetType == null) {
// throw an exception
}
// Instantiate an sObject with the type passed in as an argument
//
at run time.
return targetType.newSObject();
}
static testmethod void testObjectCreation() {
String typeName = 'Account';
String acctName = 'Acme';
// Create a new sObject by passing the sObject type as an argument.
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 209
Account a = (Account)createObject(typeName);
System.assertEquals(typeName, String.valueOf(a.getSobjectType()));
// Set the account name and insert the account.
a.Name = acctName;
insert a;
// Verify the new sObject got inserted.
Account[] b = [SELECT Name from Account WHERE Name = :acctName];
system.assert(b.size() > 0);
}
}
Accès à tous les résultats Describe de champ pour un sObject
Utilisez la méthode getMap de résultat describe de champ pour renvoyer un mappage qui représente la relation entre tous les
noms de champ (clés) et jetons de champ (valeurs) d'un sObject.
L'exemple suivant génère un mappage qui peut être utilisé pour accéder à un champ par nom :
Map<String, Schema.SObjectField> M = Schema.SObjectType.Account.fields.getMap();
Remarque: Le type de valeur de ce mappage n'est pas un résultat describe de champ. L'utilisation des résultats
describe consommerait trop de ressources système. À la place, il s'agit d'un mappage de jetons que vous pouvez utiliser
pour rechercher le champ approprié. Une fois le champ déterminé, générez pour lui le résultat describe.
Le mappage a les caractéristiques suivantes :
•
•
•
•
Il est dynamique, c.-à-d. qu'il est généré à l'exécution dans les champs de cet sObject.
Tous les noms de champ ne sont pas sensibles à la casse.
Les clés utilisent les espaces de noms requis.
Les clés indiquent si le champ est un objet personnalisé.
Par exemple, si le bloc de code qui génère le mappage se trouve dans un espace de noms N1 et qu'un champ est également
dans N1, la clé est représentée par MyField__c dans le mappage. Cependant, si le bloc de code se trouve dans un espace de
noms N1 et que le champ est dans un espace de noms N2, la clé est N2__MyField__c.
De plus, les champs standard n'ont pas de préfixe d'espace de noms.
Remarque: Un résultat describe de champ exécuté à partir d'un package géré installé renvoie des champs Chatter,
même si Chatter n'est pas activé dans l'organisation de l'installation. Cela n'est pas vrai si le résultat describe de champ
est exécuté à partir d'une classe qui ne figure pas dans un package géré installé.
Accès à toutes les catégories de données associées à un sObject
Utilisez les méthodes describeDataCategory Groups et describeDataCategory GroupStructures pour renvoyer
les catégories associées à un objet spécifique :
1. Renvoyez tous les groupes de catégories associés aux objets de votre choix (reportez-vous à describeDataCategory Groups
à la page 433).
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 210
2. Pour le mappage renvoyé, obtenez le nom du groupe de catégories et le nom du sObject que vous souhaitez interroger
(reportez-vous à Schema.DescribeDataCategoryGroupResult à la page 435).
3. Spécifiez le groupe de catégories et l'objet associé, puis récupérez les catégories disponibles pour cet objet (reportez-vous
à describeDataCategory GroupStructures à la page 433).
La méthode describeDataCategory GroupStructures renvoie les catégories disponibles pour l'objet dans le groupe
catégorie que vous spécifiez. Pour plus d'informations sur les catégories de données, reportez-vous à « Que sont les catégories
de données ? » dans l'aide en ligne de Salesforce.
Dans l'exemple suivant, la méthode describeDataCategoryGroupSample renvoie tous les groupes de catégories associés
aux objets Article et Question. La méthode describeDataCategoryGroupStructures renvoie toutes les catégories
disponibles pour des articles et des questions dans le groupe de catégories Regions. Pour plus d'informations sur les articles et
les questions, reportez-vous à « Gestion des articles et des traductions » et à « Présentation des réponses » dans l'aide en ligne
de Salesforce.
Pour utiliser l'exemple suivant, vous devez :
•
•
•
•
•
Activer Salesforce Knowledge.
Activer la fonctionnalité des réponses.
Créer un groupe de catégories de données appelé Regions.
Attribuer Regions en tant que groupe de catégories de données qu'utilise Answers.
S'assurer que le groupe de catégories de données Regions est attribué à Salesforce Knowledge.
Pour plus d'informations sur la création de groupes de catégories de données, reportez-vous à « Création et modification de
groupes de catégories » dans l'aide en ligne de Salesforce. Pour plus d'informations sur les réponses, reportez-vous à « Présentation
des réponses » dans l'aide en ligne de Salesforce.
public class DescribeDataCategoryGroupSample {
public static List<DescribeDataCategoryGroupResult> describeDataCategoryGroupSample(){
List<DescribeDataCategoryGroupResult> describeCategoryResult;
try {
//Creating the list of sobjects to use for the describe
//call
List<String> objType = new List<String>();
objType.add('KnowledgeArticleVersion');
objType.add('Question');
//Describe Call
describeCategoryResult = Schema.describeDataCategoryGroups(objType);
//Using the results and retrieving the information
for(DescribeDataCategoryGroupResult singleResult : describeCategoryResult){
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 211
//Getting the name of the category
singleResult.getName();
//Getting the name of label
singleResult.getLabel();
//Getting description
singleResult.getDescription();
//Getting the sobject
singleResult.getSobject();
}
} catch(Exception e){
}
return describeCategoryResult;
}
}
public class DescribeDataCategoryGroupStructures {
public static List<DescribeDataCategoryGroupStructureResult>
getDescribeDataCategoryGroupStructureResults(){
List<DescribeDataCategoryGroupResult> describeCategoryResult;
List<DescribeDataCategoryGroupStructureResult> describeCategoryStructureResult;
try {
//Making the call to the describeDataCategoryGroups to
//get the list of category groups associated
List<String> objType = new List<String>();
objType.add('KnowledgeArticleVersion');
objType.add('Question');
describeCategoryResult = Schema.describeDataCategoryGroups(objType);
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 212
//Creating a list of pair objects to use as a parameter
//for the describe call
List<DataCategoryGroupSobjectTypePair> pairs =
new List<DataCategoryGroupSobjectTypePair>();
//Looping throught the first describe result to create
//the list of pairs for the second describe call
for(DescribeDataCategoryGroupResult singleResult :
describeCategoryResult){
DataCategoryGroupSobjectTypePair p =
new DataCategoryGroupSobjectTypePair();
p.setSobject(singleResult.getSobject());
p.setDataCategoryGroupName(singleResult.getName());
pairs.add(p);
}
//describeDataCategoryGroupStructures()
describeCategoryStructureResult =
Schema.describeDataCategoryGroupStructures(pairs, false);
//Getting data from the result
for(DescribeDataCategoryGroupStructureResult singleResult :
describeCategoryStructureResult){
//Get name of the associated Sobject
singleResult.getSobject();
//Get the name of the data category group
singleResult.getName();
//Get the name of the data category group
singleResult.getLabel();
//Get the description of the data category group
singleResult.getDescription();
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 213
//Get the top level categories
DataCategory [] toplevelCategories =
singleResult.getTopCategories();
//Recursively get all the categories
List<DataCategory> allCategories =
getAllCategories(toplevelCategories);
for(DataCategory category : allCategories) {
//Get the name of the category
category.getName();
//Get the label of the category
category.getLabel();
//Get the list of sub categories in the category
DataCategory [] childCategories =
category.getChildCategories();
}
}
} catch (Exception e){
}
return describeCategoryStructureResult;
}
private static DataCategory[] getAllCategories(DataCategory [] categories){
if(categories.isEmpty()){
return new DataCategory[]{};
} else {
DataCategory [] categoriesClone = categories.clone();
DataCategory category = categoriesClone[0];
DataCategory[] allCategories = new DataCategory[]{category};
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 214
categoriesClone.remove(0);
categoriesClone.addAll(category.getChildCategories());
allCategories.addAll(getAllCategories(categoriesClone));
return allCategories;
}
}
}
Test de l'accès à toutes les catégories de données associées à un sObject
L'exemple suivant teste la méthode describeDataCategoryGroupSample présentée dans Accès à toutes les catégories
de données associées à un sObject. Il s'assure que le groupe de catégories et les objets associés renvoyés sont corrects.
@isTest
private class DescribeDataCategoryGroupSampleTest {
public static testMethod void describeDataCategoryGroupSampleTest(){
List<DescribeDataCategoryGroupResult>describeResult =
DescribeDataCategoryGroupSample.describeDataCategoryGroupSample();
//Assuming that you have KnowledgeArticleVersion and Questions
//associated with only one category group 'Regions'.
System.assert(describeResult.size() == 2,
'The results should only contain two results: ' + describeResult.size());
for(DescribeDataCategoryGroupResult result : describeResult) {
//Storing the results
String name = result.getName();
String label = result.getLabel();
String description = result.getDescription();
String objectNames = result.getSobject();
//asserting the values to make sure
System.assert(name == 'Regions',
'Incorrect name was returned: ' + name);
System.assert(label == 'Regions of the World',
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 215
'Incorrect label was returned: ' + label);
System.assert(description == 'This is the category group for all the regions',
'Incorrect description was returned: ' + description);
System.assert(objectNames.contains('KnowledgeArticleVersion')
|| objectNames.contains('Question'),
'Incorrect sObject was returned: ' + objectNames);
}
}
}
Cet exemple teste la méthode describeDataCategoryGroupStructures présentée dans Accès à toutes les catégories
de données associées à un sObject. Il s'assure que le groupe de catégories, les catégories et les objets associés renvoyés sont
corrects.
@isTest
private class DescribeDataCategoryGroupStructuresTest {
public static testMethod void getDescribeDataCategoryGroupStructureResultsTest(){
List<Schema.DescribeDataCategoryGroupStructureResult> describeResult =
DescribeDataCategoryGroupStructures.getDescribeDataCategoryGroupStructureResults();
System.assert(describeResult.size() == 2,
'The results should only contain 2 results: ' + describeResult.size());
//Creating category info
CategoryInfo world = new CategoryInfo('World', 'World');
CategoryInfo asia = new CategoryInfo('Asia', 'Asia');
CategoryInfo northAmerica = new CategoryInfo('NorthAmerica',
'North America');
CategoryInfo southAmerica = new CategoryInfo('SouthAmerica',
'South America');
CategoryInfo europe = new CategoryInfo('Europe', 'Europe');
List<CategoryInfo> info = new CategoryInfo[] {
asia, northAmerica, southAmerica, europe
};
Apex dynamique
salesforce | Compréhension de l'information Describe
Apex | 216
for (Schema.DescribeDataCategoryGroupStructureResult result : describeResult) {
String name = result.getName();
String label = result.getLabel();
String description = result.getDescription();
String objectNames = result.getSobject();
//asserting the values to make sure
System.assert(name == 'Regions',
'Incorrect name was returned: ' + name);
System.assert(label == 'Regions of the World',
'Incorrect label was returned: ' + label);
System.assert(description == 'This is the category group for all the regions',
'Incorrect description was returned: ' + description);
System.assert(objectNames.contains('KnowledgeArticleVersion')
|| objectNames.contains('Question'),
'Incorrect sObject was returned: ' + objectNames);
DataCategory [] topLevelCategories = result.getTopCategories();
System.assert(topLevelCategories.size() == 1,
'Incorrect number of top level categories returned: ' + topLevelCategories.size());
System.assert(topLevelCategories[0].getLabel() == world.getLabel() &&
topLevelCategories[0].getName() == world.getName());
//checking if the correct children are returned
DataCategory [] children = topLevelCategories[0].getChildCategories();
System.assert(children.size() == 4,
'Incorrect number of children returned: ' + children.size());
for(Integer i=0; i < children.size(); i++){
System.assert(children[i].getLabel() == info[i].getLabel() &&
children[i].getName() == info[i].getName());
}
}
Apex dynamique
salesforce | Requête SOQL dynamique | 217
}
private class CategoryInfo {
private final String name;
private final String label;
private CategoryInfo(String n, String l){
this.name = n;
this.label = l;
}
public String getName(){
return this.name;
}
public String getLabel(){
return this.label;
}
}
}
Requête SOQL dynamique
Une requête SOQL dynamique correspond à la création d'une chaîne SOQL à l'exécution avec un code Apex. Une requête
SOQL dynamique permet de créer des applications plus flexibles. Par exemple, vous pouvez créer une recherche basée sur la
saisie d'un utilisateur final ou mettre à jour des enregistrements des noms de champ variables.
Pour créer une requête SOQL dynamique à l'exécution, utilisez la méthode de base de données query dans l'une des méthodes
suivantes :
•
Renvoyez un sObject unique lorsque la requête renvoie un enregistrement unique :
sObject S = Database.query(string_limit_1);
Apex dynamique
•
salesforce | Requête SOSL dynamique | 218
Renvoyez une liste de sObject lorsque la requête renvoie plusieurs enregistrements :
List<sObject> L = Database.query(string);
La méthode de base de données query peut être utilisée partout où une requête SOQL en ligne est utilisable, notamment
dans des instructions d'attribution régulières et des boucles for. Les résultats sont traités de façon similaire aux requêtes SOQL
statiques.
Les résultats de requêtes SOQL dynamiques peuvent être spécifiés en tant que sObjects concrets, tels que Account ou
MyCustomObject__c, ou en tant que type de données sObject générique. À l'exécution, le système confirme que le type de
la requête correspond au type déclaré de la variable. Si la requête ne renvoie pas le type sObject correct, une erreur d'exécution
est levée. Cela signifie qu'il n'est pas nécessaire de convertir un sObject générique en sObject concret.
Les requêtes SOQL dynamiques ont les mêmes limitations du gouverneur que les requêtes statiques. Pour plus d'informations
sur les limitations du gouverneur, reportez-vous à Compréhension des limitations et des gouverneurs d'exécution à la page
273.
Pour une description complète de la syntaxe d'une requête SOQL, reportez-vous à Salesforce Object Query Language (SOQL)
dans le guide Force.com SOQL and SOSL Reference.
Injection SOQL
L'injection SOQL est une technique par laquelle un utilisateur conduit votre application à exécuter des méthodes de base de
données que vous n'aviez pas prévues en passant des instructions SOQL dans votre code. Cela peut se produire dans un code
Apex lorsque votre application dépend de la construction par un utilisateur final d'une instruction SOQL dynamique et que
vous n'avez pas géré correctement l'entrée.
Pour empêcher l'injection SOQL, utilisez la méthode escapeSingleQuotes. Cette méthode ajoute le caractère d'échappement
(\) à tous les guillemets simples d'une chaîne transmise par un utilisateur. Cette méthode permet de traiter tous les guillemets
simples en tant que chaînes englobantes, au lieu de commandes de base de données.
Requête SOSL dynamique
Une requête SOSL dynamique correspond à la création d'une chaîne SOSL à l'exécution avec un code Apex. Une requête SOSL
dynamique permet de créer des applications plus flexibles. Par exemple, vous pouvez créer une recherche basée sur la saisie
d'un utilisateur final ou mettre à jour des enregistrements des noms de champ variables.
Pour créer une requête SOSL dynamique à l'exécution, utilisez la méthode de recherche query. Par exemple :
List<List <sObject>> myQuery = search.query(SOSL_search_string);
L'exemple suivant présente une simple chaîne de requête SOSL.
String searchquery='FIND\'Edge*\'IN ALL FIELDS RETURNING Account(id,name),Contact, Lead';
List<List<SObject>>searchList=search.query(searchquery);
Les instructions SOSL dynamiques évaluent à une liste de listes de sObjects, dans laquelle chaque liste contient les résultats
de la recherche d'un type sObject particulier. Les listes de résultats sont toujours renvoyées dans le même ordre, telles que
spécifiées dans la requête SOSL dynamique. Dans l'exemple ci-dessus, les résultats de Account sont les premiers, suivis de
Contact, puis de Lead.
Apex dynamique
salesforce | Requêtes DML dynamiques | 219
La méthode de recherche query peut être utilisée partout où une requête SOSL en ligne est utilisable, notamment dans des
instructions d'attribution régulières et des boucles for. Les résultats sont traités de façon similaire aux requêtes SOSL statiques.
Les requêtes SOSL dynamiques ont les mêmes limitations du gouverneur que les requêtes statiques. Pour plus d'informations
sur les limitations du gouverneur, reportez-vous à Compréhension des limitations et des gouverneurs d'exécution à la page
273.
Pour une description complète de la syntaxe d'une requête SOSL, reportez-vous à Salesforce Object Search Language (SOSL)
dans le guide Force.com SOQL and SOSL Reference.
Injection SOSL
L'injection SOSL est une technique par laquelle un utilisateur conduit votre application à exécuter des méthodes de base de
données que vous n'aviez pas prévues en passant des instructions SOSL dans votre code. Cela peut se produire dans un code
Apex lorsque votre application dépend de la construction par un utilisateur final d'une instruction SOSL dynamique et que
vous n'avez pas géré correctement l'entrée.
Pour empêcher l'injection SOSL, utilisez la méthode escapeSingleQuotes. Cette méthode ajoute le caractère d'échappement
(\) à tous les guillemets simples d'une chaîne passée par un utilisateur. Elle permet de traiter tous les guillemets simples en
tant que chaînes englobantes, au lieu de commandes de base de données.
Requêtes DML dynamiques
Outre l'interrogation de l'information describe et de la création de requêtes SOQL à l'exécution, vous pouvez créer
dynamiquement des sObjects et les insérer dans la base de données en utilisant le langage de manipulation de données DML.
Pour créer un sObject d'un type donné, utilisez la méthode newSObject dans un jeton sObject. Notez que le jeton doit être
converti en type sObject concret (tel que Account). Par exemple :
// Get a new account
Account A = new Account();
// Get the token for the account
Schema.sObjectType tokenA = A.getSObjectType();
// The following produces an error because the token is a generic sObject, not an Account
// Account B = tokenA.newSObject();
// The following works because the token is cast back into an Account
Account B = (Account)tokenA.newSObject();
Bien que le jeton sObject tokenA soit un jeton de Account, il est considéré comme un sObject, car il est accédé séparément.
Il doit être reconverti en Account du type de sObject concret pour utiliser la méthode newSObject. Pour plus d'informations
sur la conversion, reportez-vous à Classes et conversion à la page 170.
Apex dynamique
salesforce | Requêtes DML dynamiques | 220
Voici un autre exemple qui présente comment obtenir le jeton sObject via la méthode Schema.getGlobalDescribe, puis
créer un nouveau sObject en utilisant la méthode newSObject dans le jeton. Cet exemple contient également une méthode
de test qui vérifie la création dynamique d'un compte.
public class DynamicSObjectCreation {
public static sObject createObject(String typeName) {
Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName);
if (targetType == null) {
// throw an exception
}
// Instantiate an sObject with the type passed in as an argument
//
at run time.
return targetType.newSObject();
}
static testmethod void testObjectCreation() {
String typeName = 'Account';
String acctName = 'Acme';
// Create a new sObject by passing the sObject type as an argument.
Account a = (Account)createObject(typeName);
System.assertEquals(typeName, String.valueOf(a.getSobjectType()));
// Set the account name and insert the account.
a.Name = acctName;
insert a;
// Verify the new sObject got inserted.
Account[] b = [SELECT Name from Account WHERE Name = :acctName];
system.assert(b.size() > 0);
}
}
Apex dynamique
salesforce | Requêtes DML dynamiques | 221
Vous pouvez également spécifier un ID avec newSObject pour créer un sObject qui référence un enregistrement existant que
vous pouvez mettre à jour ultérieurement. Par exemple :
SObject s = Database.query('SELECT Id FROM account LIMIT 1')[0].getSObjectType().
newSObject([SELECT Id FROM Account LIMIT 1][0].Id);
Reportez-vous à Schema.sObjectType à la page 452.
Définition et récupération de valeurs de champ
Utilisez les méthodes get et put dans un objet pour définir et récupérer des valeurs de champs en utilisant le nom d'API des
champs, exprimé en tant que chaîne, ou le jeton des champs. Dans l'exemple suivant, le nom d'API du champ AccountNumber
est utilisé :
SObject s = [SELECT AccountNumber FROM Account LIMIT 1];
Object o = s.get('AccountNumber');
s.put('AccountNumber', 'abc');
L'exemple suivant utilise à la place le jeton du champ AccountNumber :
Schema.DescribeFieldResult f = Schema.sObjectType.Account.fields.AccountNumber;
Sobject s = Database.query('SELECT AccountNumber FROM Account LIMIT 1');
s.put(f.getsObjectField(), '12345');
Le type de données scalaire Object peut être utilisé en tant que type de données générique pour définir ou récupérer les valeurs
de champ dans un sObject. Il équivaut au type de champ anyType. Notez que le type de données Object est différent du type
de données sObject, qui peut être utilisé en tant que type générique pour n'importe quel sObject.
Remarque: Les classes et les déclencheurs Apex sauvegardés (compilés) en utilisant l'API versions 15.0 et supérieures,
génèrent une erreur d'exécution si vous attribuez une valeur String trop longue pour le champ.
Définition et récupération de clés étrangères
Le langage Apex prend en charge le renseignement des clés étrangères par le nom (ou l'ID externe) de la même façon que
l'API. Pour définir ou récupérer la valeur ID scalaire d'une clé étrangère, utilisez la méthode get ou put.
Pour définir ou récupérer l'enregistrement associé à une clé étrangère, utilisez les méthodes getSObject et putSObject.
Notez que ces méthodes doivent être utilisées avec le type de données sObject, pas Object. Par exemple :
SObject c =
Database.query('SELECT Id, FirstName, AccountId, Account.Name FROM Contact LIMIT 1');
SObject a = c.getSObject('Account');
Il n'est pas nécessaire de spécifier un ID externe pour une valeur sObject parente en utilisant des sObject enfants. Si vous
fournissez un ID dans le sObject parent, il est ignoré par l'opération DML. Le langage Apex considère que la clé étrangère
Apex dynamique
salesforce | Requêtes DML dynamiques | 222
est renseignée via une requête relationnelle SOQL, qui renvoie toujours un objet parent avec un ID renseigné. Si vous avez
un ID, utilisez-le avec l'objet enfant.
Par exemple, supposons que l'objet personnalisé C1 a une clé étrangère c2__c liée à un objet personnalisé enfant C2. Vous
souhaitez créer un objet C1 et l'associer à un enregistrement C2 nommé 'xxx' (attribué à la valeur c2__r). Vous n'avez pas
besoin de l'ID de l'enregistrement 'xxx', car il est renseigné via la relation du parent à l'enfant. Par exemple :
insert new C1__c(name = 'x', c2__r = new C2__c(name = 'xxx'));
Si vous aviez attribué une valeur à l'ID pour c2__r, elle serait ignorée. Si vous avez l'ID, attribuez-le à l'objet (c2__c), pas à
l'enregistrement.
Vous pouvez également accéder à des clés étrangères en utilisant un code Apex dynamique. L'exemple suivant montre comment
obtenir les valeurs d'une sous-requête dans une relation parent à enfant, en utilisant un code Apex dynamique :
String queryString = 'SELECT Id, Name, ' +
'(SELECT FirstName, LastName FROM Contacts LIMIT 1) FROM Account';
SObject[] queryParentObject = Database.query(queryString);
for (SObject parentRecord : queryParentObject){
Object ParentFieldValue = parentRecord.get('Name');
// Prevent a null relationship from being accessed
SObject[] childRecordsFromParent = parentRecord.getSObjects('Contacts');
if (childRecordsFromParent != null) {
for (SObject childRecord : childRecordsFromParent){
Object ChildFieldValue1 = childRecord.get('FirstName');
Object ChildFieldValue2 = childRecord.get('LastName');
System.debug('Account Name: ' + ParentFieldValue +
'. Contact Name: '+ ChildFieldValue1 + ' ' + ChildFieldValue2);
}
}
}
Chapitre 7
Apex par lot
Sujets :
•
•
Utilisation d'une tâche Apex par lot
Compréhension du partage géré Apex
Un développeur peut désormais utiliser un code Apex par lot pour créer des
processus complexes et longs à exécuter sur la plate-forme Force.com. Par exemple,
un développeur peut créer une solution d'archivage, exécutée la nuit, qui recherche
les enregistrements d'une ancienneté spécifique pour les ajouter à une archive.
Un développeur peut également créer une opération de nettoyage des données
qui analyse l'ensemble des comptes et des opportunités la nuit, et les met à jour
si nécessaire selon des critères personnalisés.
Le code Apex par lot est exposé sous la forme d'une interface qui doit être mise
en oeuvre par le développeur. Les tâches par lot peuvent être invoquées par
programmation à l'exécution en utilisant Apex.
Vous pouvez avoir uniquement cinq tâches par lot en file d'attente ou actives en
même temps. Vous pouvez déterminer le nombre actuel en affichant la page
Tâches planifiées dans Salesforce, ou par programmation en utilisant l'API SOAP
pour interroger l'objet AsyncapexJob.
ATTENTION: Soyez très prudent(e) si vous envisagez d'invoquer
une tâche par lot à partir d'un déclencheur. Vous devez vous assurer que
le déclencheur n'ajoute pas d'autres tâches par lot aux cinq autorisées.
En particulier, considérez les mises à jour en masse d'API, les assistants
d'importation, les modifications d'enregistrement en masse via l'interface
utilisateur et toutes les situations dans lesquelles plusieurs enregistrements
peuvent être mis à jour à la fois.
L'exécution des tâches par lot peut être programmée à des heures spécifiques en
utilisant le planificateur Apex ou via la page Planifier Apex dans l'interface
utilisateur de Salesforce. Pour plus d'informations sur la page Planifier Apex,
reportez-vous à « Planification de classes Apex » dans l'aide en ligne de Salesforce.
L'interface Apex par lot est également utilisée pour les recalculs de partage géré
Apex.
Pour plus d'informations sur les tâches par lot, reportez-vous à Utilisation d'une
tâche Apex par lot à la page 224.
Pour plus d'informations sur le partage géré Apex, reportez-vous à Compréhension
du partage géré Apex à la page 237.
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 224
Utilisation d'une tâche Apex par lot
Pour utiliser une tâche Apex par lot, vous devez écrire une classe Apex qui met en oeuvre l'interface Database.Batchable
fournie par Salesforce, puis invoquer la classe par programmation.
Pour suivre ou arrêter l'exécution de la tâche Apex par lot, cliquez sur Votre nom > Configuration > Surveillance > Tâches
Apex. Pour plus d'informations, reportez-vous à « Surveillance de la file d'attente des tâches Apex » dans l'aide en ligne de
Salesforce.
Mise en oeuvre de l'interface Database.Batchable
L'interface Database.Batchable inclut trois méthodes qui doivent être mises en oeuvre :
•
La méthode start :
global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc)
{}
La méthode start est appelée au début d'une tâche Apex par lot. Utilisez la méthode start pour collecter les
enregistrements ou les objets à passer à la méthode d'interface execute. Cette méthode renvoie un objet
Database.QueryLocator, ou un itérable qui contient les enregistrements ou les objets passés dans la tâche.
Utilisez l'objet Database.QueryLocator lorsque vous utilisez une requête simple (SELECT) pour générer la portée des
objets utilisés dans la tâche par lot. Si vous utilisez l'objet querylocator, les limitations du gouverneur en nombre total
d'enregistrements récupérés par des requêtes SOQL sont ignorées. Par exemple, une tâche Apex par lot pour l'objet Account
peut renvoyer un QueryLocator pour tous les enregistrements account (jusqu'à 50 millions d'enregistrements) dans une
organisation. Un autre exemple est le recalcul du partage pour l'objet Contact qui renvoie un QueryLocator pour tous
les enregistrements account de l'organisation.
Utilisez l'itérable lorsque vous souhaitez créer une portée complexe pour la tâche par lot. Vous pouvez également l'utiliser
pour créer votre propre processus personnalisé afin d'itérer dans la liste.
Important: Si vous utilisez un itérable, les limitations du gouverneur en nombre total d'enregistrements récupérés
par des requêtes SOQL restent applicables.
•
La méthode execute :
global void execute(Database.BatchableContext BC, list<P>){}
La méthode execute est appelée pour chaque lot d'enregistrements transmis à la méthode. Utilisez cette méthode afin
d'effectuer tout le traitement requis pour chaque segment de données.
Cette méthode prend les éléments suivants :
◊ Une référence à l'objet Database.BatchableContext.
◊ Une liste de sObjects, telle que List<sObject>, ou une liste de types paramétrés. Si vous utilisez un
Database.QueryLocator, la liste renvoyée doit être utilisée.
L'exécution des lots d'enregistrements dans l'ordre dans lequel ils sont reçus depuis la méthode start n'est pas garantie.
•
La méthode finish :
global void finish(Database.BatchableContext BC){}
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 225
La méthode finish est appelée une fois tous les lots traités. Elle permet d'envoyer des e-mails de confirmation ou d'exécuter
des opérations de post-traitement.
Chaque exécution d'une tâche Apex par lot est considérée comme une transaction discrète. Par exemple, une tâche Apex par
lot qui contient 1000 enregistrements et qui est exécutée sans le paramètre facultatif scope depuis Database.executeBatch,
est considérée en cinq transactions de 200 enregistrements chacun. Les limitations du gouverneur Apex sont réinitialisées pour
chaque transaction. Si la première transaction réussit et la deuxième échoue, les mises à jour effectuées dans la base de données
avec la première transaction ne sont pas annulées.
Utilisation de Database.BatchableContext
Toutes les méthodes de l'interface Database.Batchable nécessitent une référence à un objet
Database.BatchableContext. Utilisez cet objet pour suivre la progression de la tâche par lot.
La méthode d'instance avec l'objet Database.BatchableContext est la suivante :
Nom
Arguments
getJobID
Renvoie
Description
ID
Renvoie l'ID de l'objet AsyncApexJob associé à cette
tâche par lot en tant que chaîne. Utilisez cette méthode
pour suivre la progression d'enregistrements dans la tâche
par lot. Vous pouvez également utiliser cet ID avec la
méthode System.abortJob.
L'exemple suivant utilise l'objet Database.BatchableContext pour interroger l'objet AsyncApexJob associé à la tâche
par lot.
global void finish(Database.BatchableContext BC){
// Get the ID of the AsyncApexJob representing this batch job
// from Database.BatchableContext.
// Query the AsyncApexJob object to retrieve the current job's information.
AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
TotalJobItems, CreatedBy.Email
FROM AsyncApexJob WHERE Id =
:BC.getJobId()];
// Send an email to the Apex job's submitter notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {a.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('Apex Sharing Recalculation ' + a.Status);
mail.setPlainTextBody
('The batch Apex job processed ' + a.TotalJobItems +
' batches with '+ a.NumberOfErrors + ' failures.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 226
}
Utilisation de Database.QueryLocator pour définir la portée
La méthode start peut renvoyer un objet Database.QueryLocator contenant les enregistrements à utiliser dans la tâche
par lot, ou renvoyer un itérable.
L'exemple suivant utilise un objet Database.QueryLocator :
global class SearchAndReplace implements Database.Batchable<sObject>{
global final String Query;
global final String Entity;
global final String Field;
global final String Value;
global SearchAndReplace(String q, String e, String f, String v){
Query=q; Entity=e; Field=f;Value=v;
}
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<sObject> scope){
for(sobject s : scope){
s.put(Field,Value);
}
update scope;
}
global void finish(Database.BatchableContext BC){
}
}
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 227
Utilisation d'un itérable dans une tâche Apex par lot pour définir la portée
La méthode start peut renvoyer un objet Database.QueryLocator contenant les enregistrements à utiliser dans la tâche
par lot, ou renvoyer un itérable. Utilisez un itérable pour parcourir aisément les éléments renvoyés.
global class batchClass implements Database.batchable{
global Iterable start(Database.BatchableContext info){
return new CustomAccountIterable();
}
global void execute(Database.BatchableContext info, List<Account> scope){
List<Account> accsToUpdate = new List<Account>();
for(Account a : scope){
a.Name = 'true';
a.NumberOfEmployees = 70;
accsToUpdate.add(a);
}
update accsToUpdate;
}
global void finish(Database.BatchableContext info){
}
}
Utilisation de la méthode Database.executeBatch
Vous pouvez utiliser la méthode Database.executeBatch pour commencer par programmation une tâche par lot.
Important: Lorsque vous appelez Database.executeBatch, Salesforce ajoute le processus à la file d'attente
uniquement à l'heure planifiée. L'exécution réelle peut être retardée en fonction de la disponibilité du service.
La méthode Database.executeBatch prend deux paramètres :
•
•
La classe qui met en oeuvre Database.Batchable.
La méthode Database.executeBatch prend un paramètre facultatif scope. Ce paramètre spécifie le nombre
d'enregistrements qui doivent être passés dans la méthode execute. Utilisez ce paramètre lorsque vous avez de nombreuses
opérations pour chaque enregistrement passé et que vous atteignez les limitations du gouverneur. En limitant le nombre
d'enregistrements, vous limitez également les opérations par transaction. Cette valeur doit être supérieure à zéro. Si la
méthode start renvoie un QueryLocator, le paramètre de portée facultatif de Database.executeBatch peut avoir
une valeur maximale de 2000. Si vous définissez une valeur plus importante, Salesforce segmente les enregistrements
renvoyés par QueryLocator en lots plus petits limités à 2000 enregistrements. Si la méthode start renvoie un itérable, la
valeur du paramètre de portée n'a pas de limite maximale. Si vous utilisez une valeur très élevée, vous risquez toutefois
d'atteindre d'autres limites.
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 228
La méthode Database.executeBatch renvoie l'ID de l'objet AsyncApexJob, qui peut ensuite être utilisé pour suivre la
progression de la tâche. Par exemple :
ID batchprocessid = Database.executeBatch(reassign);
AsyncApexJob aaj = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors
FROM AsyncApexJob WHERE ID =: batchprocessid ];
Pour plus d'informations sur l'objet AsyncApexJob object, reportez-vous à AsyncApexJob dans le guide Object Reference for
Salesforce and Force.com.
Vous pouvez également utiliser cet ID avec la méthode System.abortJob.
Exemples de tâche Apex par lot
L'exemple suivant utilise un objet Database.QueryLocator :
global class UpdateAccountFields implements Database.Batchable<sObject>{
global final String Query;
global final String Entity;
global final String Field;
global final String Value;
global UpdateAccountFields(String q, String e, String f, String v){
Query=q; Entity=e; Field=f;Value=v;
}
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC,
List<sObject> scope){
for(Sobject s : scope){s.put(Field,Value);
}
update scope;
}
global void finish(Database.BatchableContext BC){
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 229
}
}
Le code suivant peut être utilisé pour appeler la classe ci-dessus :
Id batchInstanceId = Database.executeBatch(new UpdateAccountFields(q,e,f,v), 5);
La classe suivante utilise une tâche Apex par lot pour réattribuer tous les comptes d'un utilisateur spécifique à un autre utilisateur.
global class OwnerReassignment implements Database.Batchable<sObject>{
String query;
String email;
Id toUserId;
Id fromUserId;
global Database.querylocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);}
global void execute(Database.BatchableContext BC, List<sObject> scope){
List<Account> accns = new List<Account>();
for(sObject s : scope){Account a = (Account)s;
if(a.OwnerId==fromUserId){
a.OwnerId=toUserId;
accns.add(a);
}
}
update accns;
}
global void finish(Database.BatchableContext BC){
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {email});
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 230
mail.setReplyTo('[email protected]');
mail.setSenderDisplayName('Batch Processing');
mail.setSubject('Batch Process Completed');
mail.setPlainTextBody('Batch Process has completed');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
Utilisez le code suivant pour exécuter la classe OwnerReassignment dans l'exemple précédent :
OwnerReassignment reassign = new OwnerReassignment();
reassign.query = 'SELECT Id, Name, Ownerid FROM Account ' +
'WHERE ownerid=\'' + u.id + '\'';
reassign.email='[email protected]';
reassign.fromUserId = u;
reassign.toUserId = u2;
ID batchprocessid = Database.executeBatch(reassign);
L'exemple suivant est une classe Apex par lot pour la suppression d'enregistrements.
global class BatchDelete implements Database.Batchable<sObject> {
public String query;
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<sObject> scope){
delete scope;
DataBase.emptyRecycleBin(scope);
}
global void finish(Database.BatchableContext BC){
}
}
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 231
Ce code appelle la classe Apex par lot BatchDelete pour supprimer les anciens documents. La requête spécifiée sélectionne
dans un dossier tous les documents antérieurs à une date définie pour les supprimer. L'exemple invoque ensuite la tâche par
lot.
BatchDelete BDel = new BatchDelete();
Datetime d = Datetime.now();
d = d.addDays(-1);
// Replace this value with the folder ID that contains
// the documents to delete.
String folderId = '00lD000000116lD';
// Query for selecting the documents to delete
BDel.query = 'SELECT Id FROM Document WHERE FolderId=\'' + folderId +
'\' AND CreatedDate < '+d.format('yyyy-MM-dd')+'T'+
d.format('HH:mm')+':00.000Z';
// Invoke the batch job.
ID batchprocessid = Database.executeBatch(BDel);
System.debug('Returned batch process ID: ' + batchProcessId);
Utilisation d'appels dans une tâche Apex par lot
Pour utiliser un appel dans une tâche Apexpar lot, vous devez spécifier Database.AllowsCallouts dans la définition de
la classe. Par exemple :
global class SearchAndReplace implements Database.Batchable<sObject>,
Database.AllowsCallouts{
}
Les appels incluent des requêtes HTTP, ainsi que les méthodes définies avec le mot clé webService.
Utilisation d'un état dans une tâche Apex par lot
Chaque exécution d'une tâche Apex par lot est considérée comme une transaction discrète. Par exemple, une tâche Apex par
lot qui contient 1000 enregistrements et qui est exécutée sans le paramètre facultatif scope est considérée en cinq transactions
de 200 enregistrements chacun.
Si vous spécifiez Database.Stateful dans la définition de la classe, vous pouvez maintenir l'état dans ces transactions.
Lors de l'utilisation de Database.Stateful, seules les variables de membre d'instance conservent leur valeur entre les
transactions, contrairement aux variables de membre statiques qui sont réinitialisées entre les transactions. La conservation de
l'état est utile pour compter ou résumer des enregistrements pendant leur traitement. Par exemple, supposons que votre tâche
a traité des enregistrements d'opportunité. Vous pouvez définir une méthode dans execute pour regrouper les totaux des
montants d'opportunité pendant leur traitement.
Si vous ne spécifiez pas Database.Stateful, toutes les variables de membre statiques et d'instance sont réinitialisées à leur
valeur d'origine.
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 232
L'exemple suivant récapitule un champ personnalisé total__c pendant le traitement des enregistrements :
global class SummarizeAccountTotal implements
Database.Batchable<sObject>, Database.Stateful{
global final String Query;
global integer Summary;
global SummarizeAccountTotal(String q){Query=q;
Summary = 0;
}
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator(query);
}
global void execute(
Database.BatchableContext BC,
List<sObject> scope){
for(sObject s : scope){
Summary = Integer.valueOf(s.get('total__c'))+Summary;
}
}
global void finish(Database.BatchableContext BC){
}
}
Vous pouvez en outre spécifier une variable pour accéder à l'état initial de la classe. Vous pouvez utiliser cette variable pour
partager l'état initial avec toutes les instances les méthodes Database.Batchable. Par exemple :
// Implement the interface using a list of Account sObjects
// Note that the initialState variable is declared as final
global class MyBatchable implements Database.Batchable<sObject> {
private final String initialState;
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 233
String query;
global MyBatchable(String intialState) {
this.initialState = initialState;
}
global Database.QueryLocator start(Database.BatchableContext BC) {
// Access initialState here
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC,
List<sObject> batch) {
// Access initialState here
}
global void finish(Database.BatchableContext BC) {
// Access initialState here
}
}
Notez que initialState est l'état initial de la classe. Vous ne pouvez pas l'utiliser pour passer des informations entre des
instances de la classe pendant l'exécution de la tâche par lot. Par exemple, si vous changez la valeur de initialState dans
execute, le deuxième segment d'enregistrements traités ne peut pas accéder à la nouvelle valeur : seule la valeur initiale est
accessible.
Test d'une tâche Apex par lot
Lors du test de votre Apex par lot, vous pouvez tester une seule exécution de la méthode execute. Vous pouvez utiliser le
paramètre scope de la méthode executeBatch afin de limiter le nombre de enregistrements passés dans la méthode execute
pour ne pas atteindre les limitations du gouverneur.
La méthode executeBatch lance un processus asynchrone. Cela signifie que lorsque vous testez une tâche Apex, vous devez
vous assurer que la tâche par lot est terminée avant de tester les résultats. Utilisez les méthodes de Test startTest et stopTest
autour de la méthode executeBatch pour vous assurer qu'elle est terminée avant de poursuivre votre test. Tous les appels
asynchrones effectués après la méthode startTest sont collectés par le système. Lors de l'exécution de stopTest, tous les
processus asynchrones sont exécutés de façon synchrone. Si vous n'incluez pas la méthode executeBatch dans les méthodes
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 234
startTest et stopTest, la tâche par lot est exécutée à la fin de votre méthode de test pour le code Apex enregistré à l'aide
de l'API Salesforce.com versions 25.0 et supérieures, mais pas dans les versions antérieures.
À compter du code Apex enregistré en utilisant l'API Salesforce.com version 22.0, les exceptions qui se produisent durant
l'exécution d'une tâche Apex par lot, qui est invoquée par une méthode de test, sont désormais transmises à la méthode de test
d'appel, ce qui entraîne l'échec de la méthode de test. Si vous souhaitez gérer des exceptions dans la méthode de test, insérez
votre code dans des instructions try et catch. Vous devez placer le bloc catch après la méthode stopTest. Notez cependant
qu'avec le code Apex enregistré en utilisant l'API Salesforce.com versions 21.0 et antérieures, ces exceptions ne sont pas
transmises à la méthode de test, qui n'échoue pas.
Remarque: Les appels asynchrones, tels que @future ou executeBatch, appelés dans un bloc startTest,
stopTest, ne sont pas pris en compte dans les limitations du nombre de tâches en file d'attente.
L'exemple ci-dessous teste la classe classe OwnerReassignment.
public static testMethod void testBatch() {
user u = [SELECT ID, UserName FROM User
WHERE username='[email protected]'];
user u2 = [SELECT ID, UserName FROM User
WHERE username='[email protected]'];
String u2id = u2.id;
// Create 200 test accounts - this simulates one execute.
// Important - the Salesforce.com test framework only allows you to
// test one execute.
List <Account> accns = new List<Account>();
for(integer i = 0; i<200; i++){
Account a = new Account(Name='testAccount'+'i',
Ownerid = u.ID);
accns.add(a);
}
insert accns;
Test.StartTest();
OwnerReassignment reassign = new OwnerReassignment();
reassign.query='SELECT ID, Name, Ownerid ' +
'FROM Account ' +
'WHERE OwnerId=\'' + u.Id + '\'' +
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 235
' LIMIT 200';
reassign.email='[email protected]';
reassign.fromUserId = u.Id;
reassign.toUserId = u2.Id;
ID batchprocessid = Database.executeBatch(reassign);
Test.StopTest();
System.AssertEquals(
database.countquery('SELECT COUNT()'
+' FROM Account WHERE OwnerId=\'' + u2.Id + '\''),
200);
}
}
Limitations du gouverneur pour une tâche Apex par lot
Notez les limitations du gouverneur suivantes pour une tâche Apex par lot :
•
•
Jusqu'à cinq tâches par lot en file d'attente ou actives sont autorisées pour Apex.
Un utilisateur peut avoir jusqu'à 50 curseurs de requête ouverts en même temps. Par exemple, si 50 curseurs sont ouverts
et qu'une application cliente toujours connectée sous le même utilisateur tente d'en ouvrir un nouveau, le plus ancien des
50 curseurs est libéré. Notez que cette limitation est différente pour la méthode start Apex, qui peut avoir jusqu'à cinq
curseurs de requête ouverts à la fois par utilisateur. Les autres méthodes Apex par lot ont une limite plus élevée de 50
curseurs.
Les limitations en curseur des différentes fonctionnalités Force.com sont suivies séparément. Par exemple, vous pouvez
avoir 50 Apex curseurs de requête, 50 curseur par lot et 50 curseurs Visualforce ouverts en même temps.
•
•
•
•
•
•
•
Un maximum de 50 millions d'enregistrements peuvent être renvoyés dans l'objet Database.QueryLocator. Si plus
de 50 millions d'enregistrements sont renvoyés, la tâche par lot est immédiatement terminée et marquée comme échouée.
Si la méthode start renvoie un QueryLocator, le paramètre de portée facultatif de Database.executeBatch peut
avoir une valeur maximale de 2000. Si vous définissez une valeur plus importante, Salesforce segmente les enregistrements
renvoyés par QueryLocator en lots plus petits limités à 2000 enregistrements. Si la méthode start renvoie un itérable, la
valeur du paramètre de portée n'a pas de limite maximale. Si vous utilisez une valeur très élevée, vous risquez toutefois
d'atteindre d'autres limites.
Si aucune taille n'est spécifiée avec le paramètre facultatif scope de Database.executeBatch, Salesforce segmente les
enregistrements renvoyés par la méthode start en lots de 200, puis passe chaque lot à la méthode execute. Les limitations
du gouverneur Apex sont réinitialisés à chaque exécution de la méthode execute.
Chaque méthode start, execute et finish peut mettre en oeuvre jusqu'à 10 appels.
Les exécutions par lot sont limitées à 10 appels par exécution de méthode.
Le nombre maximal d'exécutions par lot est de 250 000 par 24 heures.
Une seule méthode start d'une tâche Apex par lot peut être exécutée à la fois dans une organisation. Les tâches par lot
qui n'ont pas encore commencé restent dans la file d'attente jusqu'à leur démarrage. Notez que cette limite n'entraîne aucun
Apex par lot
salesforce | Utilisation d'une tâche Apex par lot | 236
échec de tâche par lot, et les méthodes execute des tâches Apex par lot continuent de s'exécuter en parallèle si plusieurs
taches simultanées sont en cours.
Meilleures pratiques des tâches Apex par lot
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Soyez très prudent(e) si vous envisagez d'invoquer une tâche par lot à partir d'un déclencheur. Vous devez vous assurer que
le déclencheur n'ajoute pas d'autres tâches par lot aux cinq autorisées. En particulier, considérez les mises à jour en masse
d'API, les assistants d'importation, les modifications d'enregistrement en masse via l'interface utilisateur et toutes les
situations dans lesquelles plusieurs enregistrements peuvent être mis à jour à la fois.
Lorsque vous appelez Database.executeBatch, Salesforce place la tâche dans la file d'attente uniquement à l'heure
planifiée. L'exécution réelle peut être retardée en fonction de la disponibilité du service.
Lors du test de votre Apex par lot, vous pouvez tester une seule exécution de la méthode execute. Vous pouvez utiliser
le paramètre scope de la méthode executeBatch afin de limiter le nombre de enregistrements passés dans la méthode
execute pour ne pas atteindre les limitations du gouverneur.
La méthode executeBatch lance un processus asynchrone. Cela signifie que lorsque vous testez une tâche Apex, vous
devez vous assurer que la tâche par lot est terminée avant de tester les résultats. Utilisez les méthodes de Test startTest
et stopTest autour de la méthode executeBatch pour vous assurer qu'elle est terminée avant de poursuivre votre test.
Utilisez Database.Stateful avec la définition de la classe si vous souhaitez partager des variables de membre d'instance
ou des données à travers des transactions de tâche. Sinon, toutes les variables de membre sont réinitialisées à leur état initial
au début de chaque transaction.
Les méthodes déclarées comme future ne sont pas autorisées dans les classes qui mettent en oeuvre l'interface
Database.Batchable.
Les méthodes déclarées comme future ne peuvent pas être appelées à partir d'une classe Apex par lot.
Pour une classe Apex par lot enregistrée en utilisant l'API Salesforce.com versions 25.0 et antérieures, vous ne pouvez pas
appeler la méthode Database.executeBatch à partir d'une méthode Apex par lot. À compter d'une classe Apex
enregistrée en utilisant l'API Salesforce.com version 26.0, vous pouvez appeler Database.executeBatch uniquement
à partir de la méthode finish. La version utilisée est celle de la classe par lot en cours d'exécution qui lance une autre
tâche par lot. Si la méthode finish dans la classe par lot en cours d'exécution appelle une méthode dans une classe helper
pour lancer la tâche par lot, la version de l'API Salesforce.com de la classe helper n'a aucune importance.
Vous ne pouvez pas utiliser les méthodes PageReference getContent et getContentAsPDF dans une tâche par lot.
En cas d'échec grave, par exemple une panne de service, toute opération en cours est marquée comme échouée. Vous devez
réexécuter la tâche par lot pour corriger les erreurs éventuelles.
Lorsqu'une tâche Apex par lot est exécutée, les notifications par e-mail sont envoyées à l'utilisateur qui a soumis la tâche
par lot ou, si le code est inclus dans un package géré et que l'organisation abonnée exécute la tâche par lot, l'e-mail est
envoyé au destinataire indiqué dans le champ Destinataire de notification d'exception Apex.
Chaque exécution de méthode utilise le bloc anonyme, le contrôleur Visualforce ou la méthode WSDL des limitations du
gouverneur standard.
Chaque invocation Apex par lot crée un enregistrement AsyncApexJob. Utilisez l'ID de cet enregistrement pour construire
une requête SOQL qui récupère l'état de la tâche, le nombre d'erreurs, la progression et l'émetteur de la requête. Pour plus
d'informations sur l'objet AsyncApexJob, reportez-vous à AsyncApexJob dans le guide Object Reference for Salesforce and
Force.com.
Tous les 10 000 enregistrements AsyncApexJob, Apex crée un enregistrement AsyncApexJob supplémentaire de type
BatchApexWorker à usage interne. Lors de l'interrogation de tous les enregistrements AsyncApexJob, nous
recommandons de filtrer les enregistrements de type BatchApexWorker en utilisant le champ JobType. Sinon, la requête
renvoie un enregistrement supplémentaire tous les 10 000 enregistrements AsyncApexJob. Pour plus d'informations sur
l'objet AsyncApexJob, reportez-vous à AsyncApexJob dans le guide Object Reference for Salesforce and Force.com.
Toutes les méthodes dans la classe doivent être définies comme global ou public.
Apex par lot
•
salesforce | Compréhension du partage géré Apex | 237
Pour un recalcul de partage, nous recommandons que la méthode execute supprime puis recrée tout le partage Apex géré
pour les enregistrements du lot. Cela garantit un partage précis et complet.
Voir aussi :
Instructions d'exception
Compréhension des limitations et des gouverneurs d'exécution
Compréhension du partage
Compréhension du partage géré Apex
Le partage est l'acte par lequel des autorisations sont accordées à un utilisateur ou à un groupe d'utilisateurs pour exécuter une
série d'actions dans un enregistrement ou un ensemble d'enregistrements. Le partage de l'accès peut être accordé en utilisant
l'interface utilisateur de Salesforce et Force.com, ou par programmation en utilisant le langage Apex.
Cette section présente le partage en utilisant Apex :
•
•
•
Compréhension du partage
Partage d'un enregistrement en utilisant Apex
Recalcul du partage géré Apex
Pour plus d'informations sur le partage, reportez-vous à « Définition de vos paramètres de partage par défaut à l'échelle de
l'organisation » dans l'aide en ligne de Salesforce.
Compréhension du partage
Le partage permet de contrôler l'accès au niveau de l'enregistrement pour tous les objets personnalisés, ainsi que de nombreux
objets standard (tels que Compte, Contact, Opportunité et Requête). Les administrateurs commencent par définir le niveau
d'accès en partage par défaut à l'échelle d'organisation pour un objet, puis accordent des accès supplémentaires basés sur la
propriété des enregistrements, la hiérarchie des rôles, les règles de partage et le partage manuel. Les développeurs peuvent
utiliser le partage géré Apex pour accorder par programmation un accès supplémentaire avec un code Apex. La plupart du
partage d'un enregistrement est géré dans un objet de partage associé, similaire à une liste de contrôle d'accès (ACL) existant
dans d'autres plates-formes.
Types de partage
Salesforce comprend les types de partage suivants :
Partage géré Force.com
Le partage géré Force.com nécessite un accès en partage accordé par Force.com basé sur la propriété des enregistrements,
la hiérarchie des rôles et des règles de partage :
Propriété de l'enregistrement
Chaque enregistrement appartient à un utilisateur ou éventuellement à une file d'attente d'objets personnalisés, de
requêtes et de pistes. Un accès complet est automatiquement accordé au propriétaire de l'enregistrement, ce qui lui
permet d'afficher, de modifier, de transférer, de partager et de supprimer l'enregistrement.
Apex par lot
salesforce | Compréhension du partage | 238
Hiérarchie des rôles
La hiérarchie des rôles permet aux utilisateurs de niveau supérieur à un utilisateur dans la hiérarchie de disposer du
même niveau d'accès aux enregistrements appartenant à ou partagés avec les utilisateurs de niveau inférieur. Par
conséquent, les utilisateurs de niveau supérieur à un propriétaire d'un enregistrement dans la hiérarchie des rôles
disposent implicitement d'un accès complet à l'enregistrement, comportement qui peut toutefois être désactivé
pour des objets personnalisés spécifiques. La hiérarchie des rôles n'est pas gérée par le partage d'enregistrements.
À la place, l'accès de la hiérarchie des rôles est dérivé à l'exécution. Pour plus d'informations, reportez-vous à «
Contrôler l'accès par le biais des hiérarchies » dans l'aide en ligne de Salesforce.
Règles de partage
Les règles de partage sont utilisés par les administrateurs pour accorder automatiquement aux utilisateurs d'un groupe
ou d'un rôle donné l'accès aux enregistrements appartenant à un groupe d'utilisateurs spécifique. Les règles de
partage ne peuvent pas être ajoutées à un package et utilisées pour prendre en charge une logique de partage
d'applications installées à partir de Force.com AppExchange.
Les règles de partage peuvent être basées sur la propriété d'un enregistrement ou d'autres critères. Vous ne pouvez
pas utiliser un code Apex pour créer des règles de partage basées sur des critères. De plus, le partage basé sur des
critères ne peut pas être testé en utilisant Apex.
L'ensemble du partage implicite ajouté par le partage géré Force.com ne peut pas être modifié directement en utilisant
l'interface utilisateur de Salesforce, l'API SOAP ou le langage Apex.
Partage géré utilisateur, également appelé partage manuel
Le partage géré utilisateur permet au propriétaire d'un enregistrement ou à n'importe quel utilisateur disposant d'un
accès complet à l'enregistrement de la partager avec un utilisateur ou un groupe d'utilisateurs. Cela est généralement
effectué par un utilisateur final pour un seul enregistrement. Seuls le propriétaire de l'enregistrement et les utilisateurs
de niveau supérieur au propriétaire dans la hiérarchie des rôles disposent d'un accès complet à l'enregistrement. Il n'est
pas possible d'accorder l'accès complet à d'autres utilisateurs. Les utilisateurs qui disposent de l'autorisation au niveau
de l'objet « Modifier tout » pour un objet donné ou « Modifier toutes les données » peuvent également partager
manuellement un enregistrement. Le partage géré utilisateur est retiré lorsque le propriétaire de l'enregistrement change
ou lorsque l'accès octroyé dans le partage n'accorde pas pour l'objet un accès supplémentaire dépassant le niveau d'accès
en partage par défaut de l'organisation.
Partage géré Apex
Le partage géré Apex permet aux développeurs de prendre en charge par programmation les besoins en partage spécifiques
à une application via un code Apex ou l'API SOAP. Ce type de partage est similaire au partage géré Force.com. Seuls
les utilisateurs qui disposent de l'autorisation « Modifier toutes les données » peuvent ajouter ou modifier le partage géré
Apex dans un enregistrement. Le partage géré Apex est conservé en cas de changement de propriété d'un enregistrement.
Remarque: Les motifs de partage Apex et le recalcul du partage géré Apex sont disponibles uniquement pour
des objets personnalisés.
Le champ Motif de partage
Dans l'interface utilisateur de Salesforce, le champ Motif d'un objet personnalisé spécifie le type de partage utilisé pour un
enregistrement. Ce champ est appelé rowCause dans le langage Apex ou dans l'API Force.com.
Chaque élément de la liste suivante est un type de partage utilisé pour des enregistrements. Les tableaux indiquent la valeur
du champ Motif et la valeur associée rowCause.
•
Partage géré Force.com
Apex par lot
•
•
salesforce | Compréhension du partage | 239
Valeur du champ Motif
Valeur rowCause (utilisée dans Apex ou l'API Force.com)
Partage de compte
ImplicitChild
Propriétaire de l'enregistrement ou partage associé
ImplicitParent
Propriétaire
Owner
Équipe d'opportunité
Team
Règle de partage
Rule
Règle d'attribution de territoire
TerritoryRule
Partage géré utilisateur
Valeur du champ Motif
Valeur rowCause (utilisée dans Apex ou l'API Force.com)
Partage manuel
Manual
Territoire manuel
TerritoryManual
Partage géré Apex
Valeur du champ Motif
Valeur rowCause (utilisée dans Apex ou l'API Force.com)
Définie par le développeur
Définie par le développeur
Le motif affiché du partage géré Apex est défini par le développeur.
Niveaux d'accès
Pour déterminer l'accès d'un utilisateur à un enregistrement, le niveau d'accès le plus permissif est utilisé. La plupart des objets
de partage prennent en charge les niveaux d'accès suivants :
Niveau d'accès
Nom d'API
Description
Privé
Aucun
Seuls le propriétaire de l'enregistrement et les utilisateurs de niveau
supérieur au propriétaire dans la hiérarchie des rôles peuvent afficher et
modifier l'enregistrement. Ce niveau d'accès s'applique uniquement à l'objet
AccountShare.
Lecture seule
Lire
L'utilisateur ou le groupe spécifié peut uniquement afficher l'enregistrement.
Lecture/Écriture
Modifier
L'utilisateur ou le groupe spécifié peut afficher et modifier l'enregistrement.
Accès complet
Tous
L'utilisateur ou le groupe spécifié peut afficher, modifier, transférer, partager
et supprimer l'enregistrement.
Remarque: Ce niveau d'accès peut être accordé uniquement avec
le partage géré Force.com.
Apex par lot
salesforce | Partage d'un enregistrement en utilisant Apex | 240
Partage d'un enregistrement en utilisant Apex
Pour accéder au partage par programmation, vous devez utiliser l'objet de partage associé à l'objet standard ou personnalisé
avec lequel vous souhaitez partager. Par exemple, AccountShare est l'objet de partage de l'objet Account, ContactShare est
l'objet de partage de l'objet Contact, etc. De plus, tous les objets de partage d'objets personnalisés sont nommés comme suit,
MonObjetPersonnalisé correspondant au nom de l'objet personnalisé :
MonObjetPersonnalisé__Share
Les objets côté détails d'une relation principal-détails n'ont pas d'objet de partage associé. L'accès aux enregistrements de détail
est déterminé par l'objet de partage du principal et des paramètres de partage de la relation. Pour plus d'informations,
reportez-vous à « Sécurité des objets personnalisés » dans l'aide en ligne de Salesforce.
Un objet de partage inclut des enregistrements prenant en charge les trois types de partage : partage géré Force.com, partage
géré utilisateur et partage géré Apex. Le partage accordé implicitement aux utilisateurs via les paramètres par défaut de
l'organisation, la hiérarchie des rôles et les autorisations, telles que « Afficher tout » et « Modifier tout » pour un objet donné,
« Afficher toutes les données » et « Modifier toutes les données », ne sont pas suivis avec cet objet.
Chaque objet de partage inclut les propriétés suivantes :
Nom de propriété
Description
objectNameAccessLevel
Le niveau d'accès de l'utilisateur ou du groupe spécifié a été accordé pour un sObject de
partage. Le nom de propriété est AccessLevel ajouté au nom de l'objet. Par exemple, le
nom de propriété de l'objet LeadShare est LeadShareAccessLevel. Les valeurs valides
sont :
• Edit
• Read
• All
Remarque: Le niveau d'accès All peut être utilisé uniquement par le partage géré
Force.com.
Ce champ doit être défini sur un niveau d'accès supérieur à celui par défaut de l'organisation
pour l'objet parent. Pour plus d'informations, reportez-vous à Niveaux d'accès à la page 239.
ParentID
L'ID de l'objet. Ce champ ne peut pas être mis à jour.
RowCause
La raison pour laquelle l'accès est accordé à l'utilisateur ou au groupe. Elle détermine le type
de partage, qui contrôle qui peut modifier l'enregistrement de partage. Ce champ ne peut pas
être mis à jour.
UserOrGroupId
L'ID de l'utilisateur ou du groupe auquel vous accordez l'accès. Un groupe peut être un groupe
public, un rôle ou un territoire. Ce champ ne peut pas être mis à jour.
Vous pouvez partager un objet standard ou personnalisé avec des utilisateurs ou des groupes. Pour plus d'informations sur les
types d'utilisateur et de groupe avec lesquels vous pouvez partager un objet, reportez-vous à User et à Group dans le guide
Object Reference for Salesforce and Force.com.
Apex par lot
salesforce | Partage d'un enregistrement en utilisant Apex | 241
Création d'un partage géré utilisateur en utilisant Apex
Il est possible de partager manuellement un enregistrement avec un utilisateur ou un groupe en utilisant le langage Apex ou
l'API SOAP. Si le propriétaire de l'enregistrement change, le partage est automatiquement supprimé. L'exemple de classe
suivant inclut une méthode qui partage la tâche spécifiée par l'ID de tâche avec l'ID de l'utilisateur ou du groupe spécifié avec
un accès en lecture. Il inclut également une méthode de test qui valide cette méthode. Avant d'enregistrer cet exemple de
classe, créez un objet personnalisé appelé Job.
public class JobSharing {
static boolean manualShareRead(Id recordId, Id userOrGroupId){
// Create new sharing object for the custom object Job.
Job__Share jobShr
= new Job__Share();
// Set the ID of record being shared.
jobShr.ParentId = recordId;
// Set the ID of user or group being granted access.
jobShr.UserOrGroupId = userOrGroupId;
// Set the access level.
jobShr.AccessLevel = 'Read';
// Set rowCause to 'manual' for manual sharing.
// This line can be omitted as 'manual' is the default value for sharing objects.
jobShr.RowCause = Schema.Job__Share.RowCause.Manual;
// Insert the sharing record and capture the save result.
// The false parameter allows for partial processing if multiple records passed
// into the operation.
Database.SaveResult sr = Database.insert(jobShr,false);
// Process the save results.
if(sr.isSuccess()){
// Indicates success
return true;
}
Apex par lot
salesforce | Partage d'un enregistrement en utilisant Apex | 242
else {
// Get first save result error.
Database.Error err = sr.getErrors()[0];
// Check if the error is related to trival access level.
// Access levels equal or more permissive than the object's default
// access level are not allowed.
// These sharing records are not required and thus an insert exception is acceptable.
if(err.getStatusCode() == StatusCode.FIELD_FILTER_VALIDATION_EXCEPTION
err.getMessage().contains('AccessLevel')){
// Indicates success.
return true;
}
else{
// Indicates failure.
return false;
}
}
}
// Test for the manualShareRead method
static testMethod void testManualShareRead(){
// Select users for the test.
List<User> users = [SELECT Id FROM User WHERE IsActive = true LIMIT 2];
Id User1Id = users[0].Id;
Id User2Id = users[1].Id;
// Create new job.
Job__c j = new Job__c();
j.Name = 'Test Job';
j.OwnerId = user1Id;
insert j;
&&
Apex par lot
salesforce | Partage d'un enregistrement en utilisant Apex | 243
// Insert manual share for user who is not record owner.
System.assertEquals(manualShareRead(j.Id, user2Id), true);
// Query job sharing records.
List<Job__Share> jShrs = [SELECT Id, UserOrGroupId, AccessLevel,
RowCause FROM job__share WHERE ParentId = :j.Id AND UserOrGroupId= :user2Id];
// Test for only one manual share on job.
System.assertEquals(jShrs.size(), 1, 'Set the object\'s sharing model to Private.');
// Test attributes of manual share.
System.assertEquals(jShrs[0].AccessLevel, 'Read');
System.assertEquals(jShrs[0].RowCause, 'Manual');
System.assertEquals(jShrs[0].UserOrGroupId, user2Id);
// Test invalid job Id.
delete j;
// Insert manual share for deleted job id.
System.assertEquals(manualShareRead(j.Id, user2Id), false);
}
}
Important: Le niveau d'accès par défaut de l'organisation pour l'objet ne doit pas être défini sur le niveau d'accès le
plus permissif. Pour des objets personnalisés, il correspond à Accès public en lecture/écriture. Pour plus d'informations,
reportez-vous à Niveaux d'accès à la page 239.
Création d'un partage géré Apex
Le partage géré Apex permet aux développeurs de manipuler par programmation le partage pour prendre en charge le
comportement de leur application via un code Apex ou l'API SOAP. Ce type de partage est similaire au partage géré Force.com.
Seuls les utilisateurs qui disposent de l'autorisation « Modifier toutes les données » peuvent ajouter ou modifier le partage géré
Apex dans un enregistrement. Le partage géré Apex est conservé en cas de changement de propriété d'un enregistrement.
Le partage géré Apex doit utiliser un motif de partage Apex. Les motifs de partage Apex permettent aux développeurs de suivre
les raisons pour lesquelles ils ont partagé un enregistrement avec un utilisateur ou un groupe d'utilisateurs. L'utilisation de
motifs de partage Apex multiples simplifie le code requis pour effectuer des mises à jour et des suppressions d'enregistrements
Apex par lot
salesforce | Partage d'un enregistrement en utilisant Apex | 244
de partage. Ils permettent également aux développeurs de partager plusieurs fois avec le même utilisateur ou le même groupe
pour différentes raisons.
Les motifs de partage Apex sont définies dans la page de détails d'un objet. Chaque motif de partage Apex a une étiquette et
un nom :
L'étiquette s'affiche dans la colonne Motif lors de la consultation du partage d'un enregistrement dans l'interface utilisateur.
Cela permet aux utilisateurs et aux administrateurs de comprendre la source du partage. L'étiquette est également activée
pour la traduction via le Système de traduction.
Le nom est utilisé lors du référencement du motif dans l'API et Apex.
•
•
Les noms de motif de partage Apex ont tous le format suivant :
MyReasonName__c
Les motifs de partage Apex peuvent être référencés par programmation comme suit :
Schema.CustomObject__Share.rowCause.SharingReason__c
Par exemple, un motif de partage Apex appelé Recruiter pour un objet appelé Job peut être référencé comme suit :
Schema.Job__Share.rowCause.Recruiter__c
Pour plus d'informations, reportez-vous à Méthodes Schema à la page 432.
Pour créer un motif de partage Apex :
1.
2.
3.
4.
Cliquez sur Votre nom > Configuration > Créer > Objets.
Sélectionnez l'objet personnalisé.
Cliquez sur Nouveau dans la liste associée Motifs de partage Apex.
Saisissez une étiquette pour le motif de partage Apex. L'étiquette s'affiche dans la colonne Motif lors de la consultation
du partage d'un enregistrement dans l'interface utilisateur. L'étiquette est également activée pour la traduction via le Système
de traduction.
5. Saisissez un nom pour le motif de partage Apex. Le nom est utilisé lors du référencement du motif dans l'API et Apex.
Ce nom peut contenir uniquement des traits de soulignement et des caractères alphanumériques, et doit être unique dans
votre organisation. Il doit commencer par une lettre, ne pas inclure d’espace, ne pas se terminer pas un trait de soulignement
et ne pas contenir deux traits de soulignement consécutifs.
6. Cliquez sur Enregistrer.
Remarque: Les motifs de partage Apex et le recalcul du partage géré Apex sont disponibles uniquement pour des
objets personnalisés.
Exemple de partage géré Apex
Pour cet exemple, supposons que nous créons une application de recrutement et que nous avons un objet appelé Job. Nous
souhaitons confirmer que le recruteur et le responsable du recrutement répertoriés dans le job ont accès à l'enregistrement. Le
déclencheur suivant accorde l'accès au recruteur et au responsable du recrutement lors de la création de l'enregistrement Job.
Cet exemple nécessite un objet personnalisé appelé Job, avec deux champs de référence associés aux enregistrements utilisateur
appelés Hiring_Manager et Recruiter. De plus, l'objet personnalisé Job doit avoir deux motifs de partage ajoutés appelés
Hiring_Manager et Recruiter.
trigger JobApexSharing on Job__c (after insert) {
Apex par lot
salesforce | Partage d'un enregistrement en utilisant Apex | 245
if(trigger.isInsert){
// Create a new list of sharing objects for Job
List<Job__Share> jobShrs
= new List<Job__Share>();
// Declare variables for recruiting and hiring manager sharing
Job__Share recruiterShr;
Job__Share hmShr;
for(Job__c job : trigger.new){
// Instantiate the sharing objects
recruiterShr = new Job__Share();
hmShr = new Job__Share();
// Set the ID of record being shared
recruiterShr.ParentId = job.Id;
hmShr.ParentId = job.Id;
// Set the ID of user or group being granted access
recruiterShr.UserOrGroupId = job.Recruiter__c;
hmShr.UserOrGroupId = job.Hiring_Manager__c;
// Set the access level
recruiterShr.AccessLevel = 'edit';
hmShr.AccessLevel = 'read';
// Set the Apex sharing reason for hiring manager and recruiter
recruiterShr.RowCause = Schema.Job__Share.RowCause.Recruiter__c;
hmShr.RowCause = Schema.Job__Share.RowCause.Hiring_Manager__c;
// Add objects to list for insert
jobShrs.add(recruiterShr);
jobShrs.add(hmShr);
}
Apex par lot
salesforce | Partage d'un enregistrement en utilisant Apex | 246
// Insert sharing records and capture save result
// The false parameter allows for partial processing if multiple records are passed
// into the operation
Database.SaveResult[] lsr = Database.insert(jobShrs,false);
// Create counter
Integer i=0;
// Process the save results
for(Database.SaveResult sr : lsr){
if(!sr.isSuccess()){
// Get the first save result error
Database.Error err = sr.getErrors()[0];
// Check if the error is related to a trivial access level
// Access levels equal or more permissive than the object's default
// access level are not allowed.
// These sharing records are not required and thus an insert exception is
// acceptable.
if(!(err.getStatusCode() == StatusCode.FIELD_FILTER_VALIDATION_EXCEPTION
&&
err.getMessage().contains('AccessLevel'))){
// Throw an error when the error is not related to trivial access level.
trigger.newMap.get(jobShrs[i].ParentId).
addError(
'Unable to grant sharing access due to following exception: '
+ err.getMessage());
}
}
i++;
}
}
Apex par lot
salesforce | Recalcul du partage géré Apex | 247
}
Dans certaines conditions, l'insertion d'une ligne de partage entraîne une mise à jour d'une ligne de partage existante. Notez
les exemples suivants :
•
•
Si un niveau d'accès de partage manuel est défini sur Lire et que vous insérez un nouvel accès défini sur Écriture, les lignes
de partage d'origine sont mises à jour vers Écriture, indiquant le niveau d'accès supérieur.
Si des utilisateurs peuvent accéder à un compte, parce qu'ils ont accès à ses enregistrements enfants (contact, requête,
opportunité, etc.), et qu'une règle de partage de compte est créée, le motif de la ligne du partage implicite parent est remplacé
par le motif de la ligne de la règle de partage, indiquant le niveau d'accès supérieur.
Important: Le niveau d'accès par défaut de l'organisation pour l'objet ne doit pas être défini sur le niveau d'accès le
plus permissif. Pour des objets personnalisés, il correspond à Accès public en lecture/écriture. Pour plus d'informations,
reportez-vous à Niveaux d'accès à la page 239.
Recalcul du partage géré Apex
Salesforce recalcule automatiquement le partage pour tous les enregistrements d'un objet lorsque son niveau d'accès en partage
par défaut à l'échelle de l'organisation change. Le recalcul ajoute le partage géré Force.com au moment approprié. En outre,
tous les types de partage sont supprimés si l'accès qu'ils accordent est considéré comme redondant. Par exemple, le partage
manuel qui accorde un accès en lecture seule à un utilisateur est supprimé lorsque le modèle de partage de l'objet change de
Privé à Accès public en lecture seule.
Pour recalculer le partage géré Apex, vous devez écrire une classe Apex qui met en oeuvre une interface fournie par Salesforce
pour effectuer le nouveau calcul. Vous devez ensuite associer la classe à l'objet personnalisé, via sa page de détails, dans la liste
associée Recalcul de partage Apex.
Remarque: Les motifs de partage Apex et le recalcul du partage géré Apex sont disponibles uniquement pour des
objets personnalisés.
Vous pouvez exécuter cette classe à partir de la page de détails de l'objet personnalisé, dans laquelle le motif de partage Apex
est spécifié. Un administrateur peut souhaiter recalculer le partage géré Apex pour un objet si un problème de verrouillage
empêche le code Apex d'accorder l'accès à un utilisateur, selon la définition dans la logique de l'application. Vous pouvez
utiliser la méthode Database.executeBatch pour invoquer par programmation un recalcul de partage géré Apex.
Remarque: Chaque fois que le niveau d'accès en partage par défaut de l'organisation pour un objet personnalisé est
mis à niveau, toutes les classes de recalcul Apex définies pour l'objet personnalisé sont également exécutées.
Pour suivre ou arrêter l'exécution du recalcul Apex, cliquez sur Votre nom > Configuration > Surveillance > Tâches Apex.
Pour plus d'informations, reportez-vous à « Surveillance de la file d'attente des tâches Apex » dans l'aide en ligne de Salesforce.
Création d'une classe Apex pour recalculer le partage
Pour recalculer le partage géré Apex, vous devez écrire une classe Apex qui effectue ce calcul. La classe doit mettre en oeuvre
l'interface Database.Batchable fournie par Salesforce.
L'interface Database.Batchable est utilisée pour tous les processus Apex par lot, notamment le recalcul du partage géré
Apex. Vous pouvez mettre en oeuvre cette interface plusieurs fois dans votre organisation. Pour plus d'informations sur les
méthodes à mettre en oeuvre, reportez-vous à Utilisation d'une tâche Apex par lot à la page 224.
Avant de créer une classe de recalcul de partage géré Apex, consultez les meilleures pratiques.
Apex par lot
salesforce | Recalcul du partage géré Apex | 248
Important: Le niveau d'accès par défaut de l'organisation pour l'objet ne doit pas être défini sur le niveau d'accès le
plus permissif. Pour des objets personnalisés, il correspond à Accès public en lecture/écriture. Pour plus d'informations,
reportez-vous à Niveaux d'accès à la page 239.
Exemple de recalcul de partage géré Apex
Pour cet exemple, supposons que nous créons une application de recrutement et que nous avons un objet appelé Job. Nous
souhaitons confirmer que le recruteur et le responsable du recrutement répertoriés dans le job ont accès à l'enregistrement. La
classe Apex suivante effectue cette validation. Cet exemple nécessite un objet personnalisé appelé Job, avec deux champs de
référence associés aux enregistrements utilisateur appelés Hiring_Manager et Recruiter. De plus, l'objet personnalisé Job doit
avoir deux motifs de partage ajoutés appelés Hiring_Manager et Recruiter. Avant d'exécuter cet exemple, remplacez l'adresse
e-mail par une adresse valide à laquelle vous souhaitez envoyer les notifications d'erreur et de fin de tâche.
global class JobSharingRecalc implements Database.Batchable<sObject> {
// String to hold email address that emails will be sent to.
// Replace its value with a valid email address.
static String emailAddress = '[email protected]';
// The start method is called at the beginning of a sharing recalculation.
// This method returns a SOQL query locator containing the records
// to be recalculated.
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator([SELECT Id, Hiring_Manager__c, Recruiter__c
FROM Job__c]);
}
// The executeBatch method is called for each chunk of records returned from start.
global void execute(Database.BatchableContext BC, List<sObject> scope){
// Create a map for the chunk of records passed into method.
Map<ID, Job__c> jobMap = new Map<ID, Job__c>((List<Job__c>)scope);
// Create a list of Job__Share objects to be inserted.
List<Job__Share> newJobShrs = new List<Job__Share>();
// Locate all existing sharing records for the Job records in the batch.
// Only records using an Apex sharing reason for this app should be returned.
List<Job__Share> oldJobShrs = [SELECT Id FROM Job__Share WHERE Id IN
Apex par lot
salesforce | Recalcul du partage géré Apex | 249
:jobMap.keySet() AND
(RowCause = :Schema.Job__Share.rowCause.Recruiter__c OR
RowCause = :Schema.Job__Share.rowCause.Hiring_Manager__c)];
// Construct new sharing records for the hiring manager and recruiter
// on each Job record.
for(Job__c job : jobMap.values()){
Job__Share jobHMShr = new Job__Share();
Job__Share jobRecShr = new Job__Share();
// Set the ID of user (hiring manager) on the Job record being granted access.
jobHMShr.UserOrGroupId = job.Hiring_Manager__c;
// The hiring manager on the job should always have 'Read Only' access.
jobHMShr.AccessLevel = 'Read';
// The ID of the record being shared
jobHMShr.ParentId = job.Id;
// Set the rowCause to the Apex sharing reason for hiring manager.
// This establishes the sharing record as Apex managed sharing.
jobHMShr.RowCause = Schema.Job__Share.RowCause.Hiring_Manager__c;
// Add sharing record to list for insertion.
newJobShrs.add(jobHMShr);
// Set the ID of user (recruiter) on the Job record being granted access.
jobRecShr.UserOrGroupId = job.Recruiter__c;
// The recruiter on the job should always have 'Read/Write' access.
jobRecShr.AccessLevel = 'Edit';
// The ID of the record being shared
jobRecShr.ParentId = job.Id;
Apex par lot
salesforce | Recalcul du partage géré Apex | 250
// Set the rowCause to the Apex sharing reason for recruiter.
// This establishes the sharing record as Apex managed sharing.
jobRecShr.RowCause = Schema.Job__Share.RowCause.Recruiter__c;
// Add the sharing record to the list for insertion.
newJobShrs.add(jobRecShr);
}
try {
// Delete the existing sharing records.
// This allows new sharing records to be written from scratch.
Delete oldJobShrs;
// Insert the new sharing records and capture the save result.
// The false parameter allows for partial processing if multiple records are
// passed into operation.
Database.SaveResult[] lsr = Database.insert(newJobShrs,false);
// Process the save results for insert.
for(Database.SaveResult sr : lsr){
if(!sr.isSuccess()){
// Get the first save result error.
Database.Error err = sr.getErrors()[0];
// Check if the error is related to trivial access level.
// Access levels equal or more permissive than the object's default
// access level are not allowed.
// These sharing records are not required and thus an insert exception
// is acceptable.
if(!(err.getStatusCode() == StatusCode.FIELD_FILTER_VALIDATION_EXCEPTION
&&
err.getMessage().contains('AccessLevel'))){
// Error is not related to trivial access level.
Apex par lot
salesforce | Recalcul du partage géré Apex | 251
// Send an email to the Apex job's submitter.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {emailAddress};
mail.setToAddresses(toAddresses);
mail.setSubject('Apex Sharing Recalculation Exception');
mail.setPlainTextBody(
'The Apex sharing recalculation threw the following exception: ' +
err.getMessage());
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
}
} catch(DmlException e) {
// Send an email to the Apex job's submitter on failure.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {emailAddress};
mail.setToAddresses(toAddresses);
mail.setSubject('Apex Sharing Recalculation Exception');
mail.setPlainTextBody(
'The Apex sharing recalculation threw the following exception: ' +
e.getMessage());
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
// The finish method is called at the end of a sharing recalculation.
global void finish(Database.BatchableContext BC){
// Send an email to the Apex job's submitter notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {emailAddress};
mail.setToAddresses(toAddresses);
mail.setSubject('Apex Sharing Recalculation Completed.');
mail.setPlainTextBody
Apex par lot
salesforce | Recalcul du partage géré Apex | 252
('The Apex sharing recalculation finished processing');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
Test de recalcul de partage géré Apex
Cet exemple insère cinq enregistrements Job et invoque la tâche par lot qui est mise en oeuvre dans la classe par lot de l'exemple
précédent. Cet exemple nécessite un objet personnalisé appelé Job, avec deux champs de référence associés aux enregistrements
utilisateur appelés Hiring_Manager et Recruiter. De plus, l'objet personnalisé Job doit avoir deux motifs de partage ajoutés
appelés Hiring_Manager et Recruiter. Avant d'exécuter ce test, définissez le partage par défaut à l'échelle de l'organisation
pour le Job sur Privé. Notez qu'aucun e-mail n'est envoyé à partir de tests et que la classe par lot est invoquée par une méthode
de test. Par conséquent, aucune notification par e-mail ne sera envoyée dans le cas présent.
@isTest
private class JobSharingTester {
// Test for the JobSharingRecalc class
static testMethod void testApexSharing(){
// Instantiate the class implementing the Database.Batchable interface.
JobSharingRecalc recalc = new JobSharingRecalc();
// Select users for the test.
List<User> users = [SELECT Id FROM User WHERE IsActive = true LIMIT 2];
ID User1Id = users[0].Id;
ID User2Id = users[1].Id;
// Insert some test job records.
List<Job__c> testJobs = new List<Job__c>();
for (Integer i=0;i<5;i++) {
Job__c j = new Job__c();
j.Name = 'Test Job ' + i;
j.Recruiter__c = User1Id;
j.Hiring_Manager__c = User2Id;
testJobs.add(j);
}
Apex par lot
salesforce | Recalcul du partage géré Apex | 253
insert testJobs;
Test.startTest();
// Invoke the Batch class.
String jobId = Database.executeBatch(recalc);
Test.stopTest();
// Get the Apex job and verify there are no errors.
AsyncApexJob aaj = [Select JobType, TotalJobItems, JobItemsProcessed, Status,
CompletedDate, CreatedDate, NumberOfErrors
from AsyncApexJob where Id = :jobId];
System.assertEquals(0, aaj.NumberOfErrors);
// This query returns jobs and related sharing records that were inserted
// by the batch job's execute method.
List<Job__c> jobs = [SELECT Id, Hiring_Manager__c, Recruiter__c,
(SELECT Id, ParentId, UserOrGroupId, AccessLevel, RowCause FROM Shares
WHERE (RowCause = :Schema.Job__Share.rowCause.Recruiter__c OR
RowCause = :Schema.Job__Share.rowCause.Hiring_Manager__c))
FROM Job__c];
// Validate that Apex managed sharing exists on jobs.
for(Job__c job : jobs){
// Two Apex managed sharing records should exist for each job
// when using the Private org-wide default.
System.assert(job.Shares.size() == 2);
for(Job__Share jobShr : job.Shares){
// Test the sharing record for hiring manager on job.
if(jobShr.RowCause == Schema.Job__Share.RowCause.Hiring_Manager__c){
System.assertEquals(jobShr.UserOrGroupId,job.Hiring_Manager__c);
System.assertEquals(jobShr.AccessLevel,'Read');
Apex par lot
salesforce | Recalcul du partage géré Apex | 254
}
// Test the sharing record for recruiter on job.
else if(jobShr.RowCause == Schema.Job__Share.RowCause.Recruiter__c){
System.assertEquals(jobShr.UserOrGroupId,job.Recruiter__c);
System.assertEquals(jobShr.AccessLevel,'Edit');
}
}
}
}
}
Association d'une classe Apex utilisée pour le recalcul
Une classe Apex utilisée pour un nouveau calcul doit être associée à un objet personnalisé.
Pour associer une classe de recalcul de partage géré Apex à un objet personnalisé :
1.
2.
3.
4.
Cliquez sur Votre nom > Configuration > Créer > Objets.
Sélectionnez l'objet personnalisé.
Cliquez sur Nouveau dans la liste associée Recalculs de partage Apex.
Choisissez la classe Apex qui recalcule le partage Apex de cet objet. La classe que vous choisissez doit mettre en oeuvre
l'interface Database.Batchable. Vous ne pouvez pas associer plusieurs fois la même classe Apex au même objet
personnalisé.
5. Cliquez sur Enregistrer.
Chapitre 8
Débogage du langage Apex
Sujets :
•
•
•
•
Compréhension du journal de
débogage
Gestion des exceptions non détectées
Compréhension des limitations et des
gouverneurs d'exécution
Utilisation d'avertissements par
e-mail pour les limitations du
gouverneur
Le langage Apex prend en charge le débogage. Vous pouvez déboguer votre code
Apex en utilisant la Console du développeur et des journaux de débogage. Pour
faciliter le débogage, le langage Apex envoie des e-mails aux développeurs pour
les exceptions non gérées. En outre, le langage Apex impose un ensemble
spécifique de limitations du gouverneur pour l'exécution du code, afin d'éviter la
monopolisation des ressources partagées dans un environnement mutualisé.
Dernier point, mais non des moindres, vous pouvez activer l'envoi d'e-mails aux
utilisateurs qui exécutent un code dépassant un certain pourcentage des limitations
du gouverneur.
Ce chapitre inclut les sections suivantes :
•
•
•
•
Compréhension du journal de débogage
Gestion des exceptions non détectées
Compréhension des limitations et des gouverneurs d'exécution
Utilisation d'avertissements par e-mail pour les limitations du gouverneur
Débogage du langage Apex
salesforce | Compréhension du journal de débogage | 256
Compréhension du journal de débogage
Un journal de débogage enregistre les opérations dans la base de données, les processus système ainsi que les erreurs qui se
produisent lors de l'exécution d'une transaction ou de tests unitaires. Le système génère un journal de débogage pour un
utilisateur chaque fois qu'il exécute une transaction qui est comprise dans les critères de filtrage.
Vous pouvez conserver et gérer les journaux de débogage pour des utilisateurs spécifiques.
Pour afficher les journaux de débogage enregistrés, cliquez sur Votre nom > Configuration > Surveillance > Journaux de
débogage.
Les limites liées aux journaux de débogage sont les suivantes :
•
•
•
Une fois ajouté, un utilisateur peut enregistrer jusqu'à 20 journaux de débogage. Lorsqu'un utilisateur atteint cette limite,
l'enregistrement des journaux de débogage s'arrête pour cet utilisateur. Cliquez sur Réinitialiser dans la page Surveillance
de journaux de débogage afin de réinitialiser le nombre de journaux de cet utilisateur à 20. Les journaux existants ne sont
pas écrasés.
Chaque journal de débogage est limité à 2 Mo. Les journaux de débogage supérieurs à 2 Mo sont tronqués.
Chaque organisation peut conserver jusqu'à 50 Mo de journaux de débogage. Lorsque les journaux de débogage de votre
organisation atteignent 50 Mo, les plus anciens journaux sont remplacés.
Inspection des sections du journal de débogage
Lorsqu'un journal de débogage est généré, le type et la quantité des informations répertoriées dépend des valeurs de filtrage
que vous avez définies pour l'utilisateur. Toutefois, le format d'un journal de débogage est toujours le même.
Un journal de débogage comprend les sections suivantes :
En-tête
L'en-tête contient les informations suivantes :
• La version de l'API utilisée durant la transaction.
• La catégorie du journal et le niveau utilisé pour générer le journal. Par exemple :
Voici un exemple d'en-tête :
25.0
APEX_CODE,DEBUG;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;
WORKFLOW,INFO
Dans cet exemple, la version de l'API est 25.0, et les catégories et niveaux de journal de débogage suivants ont été définis :
Code Apex
DEBUG
Profil Apex
INFO
Appel
INFO
Base de données
INFO
Système
DEBUG
Validation
INFO
Débogage du langage Apex
salesforce | Compréhension du journal de débogage | 257
Visualforce
INFO
Workflow
INFO
Unités d'exécution
Une unité d'exécution est équivalente à une transaction. Elle contient tout ce qui s'est passé durant la transaction.
L'exécution est délimitée par EXECUTION_STARTED et EXECUTION_FINISHED.
Unités de code
Une unité de code est une unité de travail discrète dans une transaction. Par exemple, un déclencheur est une unité de
code, comme dans la méthode webService, ou une règle de validation.
Remarque: Une classe n'est pas une unité de code discrète.
Les unités de code sont indiquées par CODE_UNIT_STARTED et CODE_UNIT_FINISHED. Les unités de travail peuvent
être incorporées à d'autres unités de travail. Par exemple :
EXECUTION_STARTED
CODE_UNIT_STARTED|[EXTERNAL]execute_anonymous_apex
CODE_UNIT_STARTED|[EXTERNAL]MyTrigger on Account trigger event BeforeInsert for [new]
CODE_UNIT_FINISHED <-- The trigger ends
CODE_UNIT_FINISHED <-- The executeAnonymous ends
EXECUTION_FINISHED
Les unités de code comprennent, notamment, les éléments suivants :
• Déclencheurs
• Invocations de workflow et workflow temporel
• Règles de validation
• Processus d'approbation
• Conversion de pistes par Apex
• Invocations de méthodes @future
• Invocations de services Web
• Appels executeAnonymous
• La propriété Visualforce accède aux contrôleurs Apex
• Actions Visualforce dans les contrôleurs Apex
• Exécution des méthodes Apex par lot start et finish, ainsi que l'exécution de la méthode execute
• Exécution de la méthode Apex System.Schedule execute
• Traitement des e-mails entrants
Lignes de journal
Incluses dans les unités de code. Elles indiquent le code ou les règles en cours d'exécution, ou les messages écrits
spécialement pour le journal de débogage. Par exemple :
Débogage du langage Apex
salesforce | Compréhension du journal de débogage | 258
Figure 5: Exemple de ligne d'un journal de débogage
Les lignes de journal sont composées d'un ensemble de champs, délimités par un tube (|). Le format est le suivant :
• timestamp : comprend l'heure à laquelle se produit l'événement et une valeur entre parenthèses. L'heure est définie
dans le fuseau horaire de l'utilisateur, sous le format HH:mm:ss.SSS La valeur représente le temps écoulé en
nanosecondes depuis le début de la requête. La valeur de temps écoulé est exclue des journaux révisés dans la Console
du développeur.
• event identifier : comprend l'événement spécifique qui a déclenché l'écriture dans le journal de débogage, tel que
SAVEPOINT_RESET ou VALIDATION_RULE, ainsi que toute information consignée avec cet événement, telle que
le nom de la méthode ou le numéro de ligne, et de caractère où le code a été exécuté.
Données de journal supplémentaires
Le journal contient en outre les informations suivantes :
• Utilisation des ressources cumulée : consignée à la fin de nombreuses unités de code, telles que des déclencheurs,
executeAnonymous, le traitement de message Apex par lot, les méthodes @future, les méthodes de test Apex,
les méthodes de services Web Apex et la conversion de pistes Apex.
• Informations de profil cumulées : consignées une seule fois à la fin de la transaction. Contient des informations sur
les requêtes les plus coûteuses (les plus exigeantes en ressources), les invocations DML, etc.
Voici un exemple de journal de débogage :
22.0
APEX_CODE,DEBUG;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;
WORKFLOW,INFO
11:47:46.030 (30064000)|EXECUTION_STARTED
11:47:46.030 (30159000)|CODE_UNIT_STARTED|[EXTERNAL]|TRIGGERS
11:47:46.030 (30271000)|CODE_UNIT_STARTED|[EXTERNAL]|01qD00000004JvP|myAccountTrigger on
Account trigger event BeforeUpdate for [001D000000IzMaE]
11:47:46.038 (38296000)|SYSTEM_METHOD_ENTRY|[2]|System.debug(ANY)
11:47:46.038 (38450000)|USER_DEBUG|[2]|DEBUG|Hello World!
11:47:46.038 (38520000)|SYSTEM_METHOD_EXIT|[2]|System.debug(ANY)
11:47:46.546 (38587000)|CUMULATIVE_LIMIT_USAGE
11:47:46.546|LIMIT_USAGE_FOR_NS|(default)|
Number of SOQL queries: 0 out of 100
Number of query rows: 0 out of 50000
Débogage du langage Apex
salesforce | Compréhension du journal de débogage | 259
Number of SOSL queries: 0 out of 20
Number of DML statements: 0 out of 150
Number of DML rows: 0 out of 10000
Number of code statements: 1 out of 200000
Maximum heap size: 0 out of 6000000
Number of callouts: 0 out of 10
Number of Email Invocations: 0 out of 10
Number of fields describes: 0 out of 100
Number of record type describes: 0 out of 100
Number of child relationships describes: 0 out of 100
Number of picklist describes: 0 out of 100
Number of future calls: 0 out of 10
11:47:46.546|CUMULATIVE_LIMIT_USAGE_END
11:47:46.038 (38715000)|CODE_UNIT_FINISHED|myAccountTrigger on Account trigger event
BeforeUpdate for [001D000000IzMaE]
11:47:47.154 (1154831000)|CODE_UNIT_FINISHED|TRIGGERS
11:47:47.154 (1154881000)|EXECUTION_FINISHED
Définition de filtres de journal de débogage pour des classes et déclencheurs Apex
Le filtrage d'un journal de débogage offre un mécanisme d'ajustement de la verbosité du journal au niveau du déclencheur et
de la classe. Ce mécanisme est particulièrement utile pour le débogage de la logique Apex. Par exemple, pour évaluer le résultat
d'un processus complexe, vous pouvez augmenter la verbosité du journal d'une classe donnée lors de la désactivation de la
consignation d'autres classes ou déclencheurs dans une requête unique.
Lorsque vous remplacez les niveaux du journal de débogage d'une classe ou d'un déclencheur, ces niveaux de débogage
s'appliquent également aux méthodes de la classe appelées par votre classe ou déclencheur et aux déclencheurs exécutés en tant
que résultat. L'ensemble des méthodes et déclencheurs de classe du chemin d'exécution héritent des paramètres du journal de
débogage de leur appelant, sauf si ces paramètres sont remplacés.
Le diagramme suivant illustre le remplacement des niveaux du journal de débogage au niveau de la classe et du déclencheur.
Dans ce scénario, supposons que Class1 crée des problèmes que vous souhaitez examiner de plus près. Pour cela, les niveaux
du journal de débogage de Class1 sont augmentés vers une granularité maximale. Class3 ne remplace pas ces niveaux de
consignation et hérite par conséquent des filtres de consignation granulaires de Class1. Cependant, UtilityClass a déjà
été testée et elle fonctionne correctement, donc ses filtres de consignation sont désactivés. De même, Class2 n'est pas le
chemin du code à l'origine du problème. Par conséquent, sa consignation est réduite pour consigner uniquement les erreurs
de la catégorie Code Apex. Trigger2 hérite de ces paramètres de consignation de Class2.
Débogage du langage Apex
salesforce | Compréhension du journal de débogage | 260
Figure 6: Ajustement de la consignation de débogage pour des classes et des déclencheurs
L'exemple suivant présente un code sur lequel repose le diagramme.
1. Trigger1 appelle une méthode de Class1 et une autre méthode de Class2. Par exemple :
trigger Trigger1 on Account (before insert) {
Class1.someMethod();
Class2.anotherMethod();
}
2. Class1 appelle une méthode de Class3 qui à son tour appelle une méthode d'une classe utilitaire. Par exemple :
public class Class1 {
public static void someMethod() {
Class3.thirdMethod();
}
}
public class Class3 {
public static void thirdMethod() {
UtilityClass.doSomething();
}
}
3. Class2 entraîne l'exécution d'un déclencheur, Trigger2. Par exemple :
public class Class2 {
public static void anotherMethod() {
// Some code that causes Trigger2 to be fired.
Débogage du langage Apex
salesforce | Utilisation de journaux dans la Console du
développeur | 261
}
}
Pour définir des filtres de journaux :
1. Dans la page de détails d'une classe ou d'un déclencheur, cliquez sur Filtres de journaux.
2. Cliquez sur Ignorer les filtres de journaux.
Les filtres de journaux sont définis sur les niveaux de consignation par défaut.
3. Sélectionnez le niveau de consignation voulu pour chaque catégorie de consignation.
Pour en savoir plus sur les catégories, les niveaux et les événements du journal de débogage, reportez-vous à Configuration des
filtres du journal de débogage.
Voir aussi :
Utilisation de journaux dans la Console du développeur
Débogage des appels d'API Apex
Utilisation de journaux dans la Console du développeur
Utilisez l'onglet des journaux dans la Console du développeur pour ouvrir les journaux de débogage.
1. Cliquez sur Ouvrir pour ouvrir le journal sélectionné dans une nouvelle vue Journal système.
2. Cliquez sur Ouvrir le journal brut pour ouvrir le contenu du journal sélectionné dans une vue de texte brut, sans mise en
forme.
3. Cliquez sur Télécharger le journal pour télécharger le journal sélectionné.
4. Cliquez sur Masquer automatiquement les journaux pour masquer automatiquement tous les journaux existants lors de
la prochaine actualisation de la page. Ce bouton permet de basculer : un nouveau clic active l'affichage tous les journaux.
5. Cliquez sur Effacer pour effacer tous les journaux de la liste.
Conseil: Si vous surveillez des journaux de débogage pour un utilisateur, ils restent accessibles depuis la page
Journal de débogage. Cliquez sur Votre nom > Configuration > Surveillance > Journaux de débogage.
6. Sélectionnez Afficher mes journaux actuels uniquement pour afficher uniquement les journaux que vous avez générés
depuis l'ouverture de la Console du développeur. Désactivez cette option pour afficher tous les journaux de débogage
enregistrés pour votre organisation, y compris les journaux système récemment générés, créés par d'autres utilisateurs.
7. Cliquez sur Filtrer, puis saisissez un texte de filtrage les journaux visibles. Par exemple, pour afficher les journaux de
débogage d'un utilisateur spécifique, saisissez le nom de cet utilisateur. Le filtre est sensible à la casse.
Débogage du langage Apex
salesforce | Utilisation de journaux dans la Console du
développeur | 262
Les journaux s'ouvrent dans une vue Journal système. Une vue Journal système est une visionneuse d'exécution sensible au
contexte qui affiche la source d'une opération, l'événement ayant déclenché l'opération et l'action ensuite exécutée. Cette vue
permet d'examiner les journaux de débogage qui comprennent les événements de la base de données, le traitement Apex, le
workflow et la logique de validation.
Pour plus d'informations sur l'utilisation de journaux dans une vue Journal système de la Console du développeur, reportez-vous
à Vue Journal système.
Lors de l'utilisation de la Console du développeur ou de la surveillance d'un journal de débogage, vous pouvez spécifier le
niveau d'information inclus dans le journal.
Catégorie de consignation
Le type d'information consignée, telles que des informations Apex ou des règles de workflow.
Niveau de consignation
La quantité d'informations consignées.
Type d’événement
La combinaison d'une catégorie de consignation et d'un niveau de consignation qui spécifie le type des événements
enregistrés. Chaque événement peut consigner des informations supplémentaires, tels que le numéro de ligne et de
caractère du début de l'événement, les champs associés à l'événement, la durée en millisecondes de l'événement, etc.
Catégories de journal de débogage
Vous pouvez indiquer les catégories de consignation ci-dessous. La quantité d'informations consignées pour chaque catégorie
dépend du niveau de consignation :
Catégorie de consignation
Description
Database
Comprend des informations sur l'activité de la base de données, y compris chaque
instruction du langage de manipulation de données (DML) ou chaque requête en
ligne SOQL ou SOSL.
Workflow
Comprend des informations sur les règles de workflow, telles que leur nom, les actions
engagées, etc.
Validation
Comprend des informations sur les règles de validation, telles que leur nom, si la règle
a évalué true ou false, etc.
Callout
Inclut le fichier XML de requête-réponse que le serveur envoie et reçoit d'un service
Web externe. Il est utile lors du débogage des problèmes liés à l'utilisation des appels
API des services Web Force.com.
Apex Code
Comprend des informations relatives au code Apex, et peut inclure des informations
telles que des messages du journal générés par des instructions DML, des requêtes en
ligne SOQL ou SOSL, le début et la fin de chaque déclencheur, le début et la fin de
chaque méthode de test, etc.
Apex Profiling
Comprend des informations sur les profils cumulés, telles que les limitations de votre
espace de noms, le nombre d'e-mails envoyés, etc.
Visualforce
Comprend des informations relatives aux événements Visualforce qui incluent la
sérialisation et la désérialisation de l'état de la vue ou l'évaluation d'un champ de
formule dans une page Visualforce.
Débogage du langage Apex
salesforce | Utilisation de journaux dans la Console du
développeur | 263
Catégorie de consignation
Description
System
Comprend des informations relatives aux appels à toutes les méthodes système, telles
que la méthode System.debug.
Niveaux du journal de débogage
Vous pouvez indiquer les niveaux de consignation suivants. Les niveaux sont répertoriés du plus bas au plus élevé. Les événements
spécifiques sont consignés selon une combinaison de catégorie et de niveaux. La consignation de la plupart des événements
commence au niveau INFO. Le niveau est cumulé, c.-à-d. que si vous sélectionnez FINE, le journal comprend également tous
les événements consignés aux niveaux DEBUG, INFO, WARN et ERROR.
Remarque: Les niveaux ne sont pas tous disponibles pour toutes les catégories. Seuls les niveaux qui correspondent
à un ou plusieurs événements sont disponibles.
•
•
•
•
•
•
•
ERROR
WARN
INFO
DEBUG
FINE
FINER
FINEST
Important: Avant d'exécuter un déploiement, assurez-vous que le niveau du journal Code Apex n'est pas défini sur
FINEST. Si le niveau du journal Code Apex est défini sur FINEST, le déploiement peut être plus long que prévu.
Si la Console du développeur est ouverte, les niveaux de journal dans la Console du développeur affectent tous les
journaux, y compris ceux créés pendant un déploiement.
Types d'événement de débogage
L'exemple suivant présente les informations consignées dans le journal de débogage. L'événement est USER_DEBUG. Le format
est timestamp | event identifier :
•
•
timestamp : comprend l'heure à laquelle se produit l'événement et une valeur entre parenthèses. L'heure est définie dans le
fuseau horaire de l'utilisateur, sous le format HH:mm:ss.SSS La valeur représente le temps écoulé en nanosecondes depuis
le début de la requête. La valeur de temps écoulé est exclue des journaux révisés dans la Console du développeur.
event identifier : comprend l'événement spécifique qui a déclenché l'écriture dans le journal de débogage, tel que
SAVEPOINT_RESET ou VALIDATION_RULE, ainsi que toute information consignée avec cet événement, telle que le nom
de la méthode ou le numéro de ligne, et de caractère où le code a été exécuté.
Voici un exemple de ligne de journal de débogage :
Figure 7: Exemple de ligne d'un journal de débogage
Débogage du langage Apex
salesforce | Utilisation de journaux dans la Console du
développeur | 264
Dans cet exemple, l'identifiant de l'événement comprend :
•
Nom de l'événement :
USER_DEBUG
•
Numéro de ligne et de caractère de l'événement dans le code :
[2]
•
Niveau de consignation défini pour la méthode System.Debug :
DEBUG
•
Chaîne fournie par l'utilisateur pour la méthode System.Debug :
Hello world!
L'exemple de ligne de journal suivant est déclenché dans cet extrait de code.
Figure 8: Extrait de code de ligne de journal de débogage
La ligne de journal suivante est enregistrée lorsque le test atteint la ligne 5 du code :
15:51:01.071 (55856000)|DML_BEGIN|[5]|Op:Insert|Type:Invoice_Statement__c|Rows:1
Dans cet exemple, l'identifiant de l'événement comprend :
•
Nom de l'événement :
DML_BEGIN
•
Numéro de ligne et de caractère de l'événement dans le code :
[5]
•
Type d'opération DML : Insert :
Op:Insert
•
Nom de l'objet :
Type:Invoice_Statement__c
Débogage du langage Apex
•
salesforce | Utilisation de journaux dans la Console du
développeur | 265
Nombre de lignes passées dans l'opération DML :
Rows:1
Le tableau ci-dessous présente les types d'événement qui sont consignés, les champs ou d'autres informations consignées avec
chaque événement, ainsi que la combinaison d'un niveau et d'une catégorie de journal qui déclenche la consignation d'un
événement.
Nom de l'événement
Champs ou informations consignées avec
l'événement
Catégorie
consignée
Événement
consigné
BULK_HEAP_ALLOCATE
Nombre d'octets alloués
Code Apex
FINEST
CALLOUT_REQUEST
Numéro de la ligne, en-têtes de la requête
Appel
INFO et supérieur
CALLOUT_RESPONSE
Numéro de la ligne, corps de la réponse
Appel
INFO et supérieur
CODE_UNIT_FINISHED
Aucun
Code Apex
ERROR et
supérieur
CODE_UNIT_STARTED
Numéro de la ligne, nom de l'unité de code Code Apex
tel que MyTrigger on Account trigger
ERROR et
supérieur
event BeforeInsert for [new]
CONSTRUCTOR_ENTRY
Numéro de la ligne, ID de la classe Apex, la Code Apex
chaîne <init>() avec les types de paramètre,
le cas échéant, entre parenthèses
DEBUG et
supérieur
CONSTRUCTOR_EXIT
Numéro de la ligne, la chaîne <init>() avec Code Apex
les types de paramètre, le cas échéant, entre
parenthèses
DEBUG et
supérieur
CUMULATIVE_LIMIT_USAGE
Aucun
Profil Apex
INFO et supérieur
CUMULATIVE_LIMIT_USAGE_END Aucun
Profil Apex
INFO et supérieur
Aucun
Profil Apex
FINE et supérieur
CUMULATIVE_PROFILING_BEGIN Aucun
Profil Apex
FINE et supérieur
CUMULATIVE_PROFILING_END Aucun
Profil Apex
FINE et supérieur
CUMULATIVE_PROFILING
DML_BEGIN
Numéro de la ligne, opération (telle que
Insert, Update, etc.), nom ou type
d'enregistrement, nombre de lignes traitées
dans l'opération DML
Code Apex
INFO et supérieur
DML_END
Numéro de la ligne
Code Apex
INFO et supérieur
EMAIL_QUEUE
Numéro de la ligne
Code Apex
INFO et supérieur
ENTERING_MANAGED_PKG
Espace de noms du package
Code Apex
INFO et supérieur
EXCEPTION_THROWN
Numéro de la ligne, type d'exception, message Code Apex
INFO et supérieur
EXECUTION_FINISHED
Aucun
Code Apex
ERROR et
supérieur
EXECUTION_STARTED
Aucun
Code Apex
ERROR et
supérieur
Débogage du langage Apex
salesforce | Utilisation de journaux dans la Console du
développeur | 266
Nom de l'événement
Champs ou informations consignées avec
l'événement
Catégorie
consignée
Événement
consigné
FATAL_ERROR
Type d'exception, message, trace de pile
Code Apex
ERROR et
supérieur
HEAP_ALLOCATE
Numéro de la ligne, nombre d'octets
Code Apex
FINER et supérieur
HEAP_DEALLOCATE
Numéro de la ligne, nombre d'octets
désaffectés
Code Apex
FINER et supérieur
IDEAS_QUERY_EXECUTE
Numéro de la ligne
Base de données
FINEST
LIMIT_USAGE_FOR_NS
Espace de noms, limites suivantes :
Profil Apex
FINEST
Number of SOQL queries
Number of query rows
Number of SOSL queries
Number of DML statements
Number of DML rows
Number of code statements
Maximum heap size
Number of callouts
Number of Email Invocations
Number of fields describes
Number of record type describes
Number of child relationships
describes
Débogage du langage Apex
Nom de l'événement
salesforce | Utilisation de journaux dans la Console du
développeur | 267
Champs ou informations consignées avec
l'événement
Catégorie
consignée
Événement
consigné
Number of picklist describes
Number of future calls
Number of find similar calls
Number of System.runAs()
invocations
METHOD_ENTRY
Numéro de la ligne, ID Force.com de la
classe, signature de la méthode
Code Apex
DEBUG et
supérieur
METHOD_EXIT
Numéro de la ligne, ID Force.com de la
classe, signature de la méthode.
Code Apex
DEBUG et
supérieur
Pour les constructeurs, les informations
suivantes sont consignées : Numéro de la
ligne, nom de la classe.
POP_TRACE_FLAGS
Numéro de la ligne, ID Force.com de la classe Système
ou du déclencheur dont les filtres de
consignation sont définis et compris dans la
portée, le nom de cette classe ou de ce
déclencheur, les paramètres du filtre de
consignation actuellement actifs après avoir
quitté cette portée
INFO et supérieur
PUSH_TRACE_FLAGS
Numéro de la ligne, ID Force.com de la classe Système
ou du déclencheur dont les filtres de
consignation sont définis et non compris dans
la portée, le nom de cette classe ou de ce
déclencheur, les paramètres du filtre de
consignation actuellement actifs après être
entrés dans cette portée
INFO et supérieur
QUERY_MORE_ITERATIONS
Numéro de la ligne, nombre d'itérations de
Base de données
INFO et supérieur
queryMore
SAVEPOINT_ROLLBACK
Numéro de la ligne, nom Savepoint
Base de données
INFO et supérieur
SAVEPOINT_SET
Numéro de la ligne, nom Savepoint
Base de données
INFO et supérieur
SLA_END
Nombre de requêtes, durée de chargement,
durée de traitement, nombre de jalons de
Workflow
INFO et supérieur
Débogage du langage Apex
Nom de l'événement
salesforce | Utilisation de journaux dans la Console du
développeur | 268
Champs ou informations consignées avec
l'événement
Catégorie
consignée
Événement
consigné
requêtes à insérer/mettre à jour/supprimer,
nouveau déclencheur
SLA_EVAL_MILESTONE
ID de jalon
Workflow
INFO et supérieur
SLA_NULL_START_DATE
Aucun
Workflow
INFO et supérieur
SLA_PROCESS_CASE
ID de requête
Workflow
INFO et supérieur
SOQL_EXECUTE_BEGIN
Numéro de la ligne, nombre d'agrégations,
source de la requête
Base de données
INFO et supérieur
SOQL_EXECUTE_END
Numéro de la ligne, nombre de lignes, durée Base de données
en millisecondes
INFO et supérieur
SOSL_EXECUTE_BEGIN
Numéro de la ligne, source de la requête
Base de données
INFO et supérieur
SOSL_EXECUTE_END
Numéro de la ligne, nombre de lignes, durée Base de données
en millisecondes
INFO et supérieur
STACK_FRAME_VARIABLE_LIST Numéro de cadre, liste de variables sous la
forme : Numéro de variable | Valeur.
Profil Apex
FINE et supérieur
Code Apex
FINER et supérieur
Par exemple :
var1:50
var2:'Hello World'
STATEMENT_EXECUTE
Numéro de la ligne
STATIC_VARIABLE_LIST
Liste de variables sous la forme : Numéro de Profil Apex
variable | Valeur. Par exemple :
FINE et supérieur
var1:50
var2:'Hello World'
SYSTEM_CONSTRUCTOR_ENTRY Numéro de la ligne, la chaîne <init>() avec Système
DEBUG
les types de paramètre, le cas échéant, entre
parenthèses
SYSTEM_CONSTRUCTOR_EXIT
Numéro de la ligne, la chaîne <init>() avec Système
les types de paramètre, le cas échéant, entre
parenthèses
DEBUG
SYSTEM_METHOD_ENTRY
Numéro de la ligne, signature de la méthode Système
DEBUG
SYSTEM_METHOD_EXIT
Numéro de la ligne, signature de la méthode Système
DEBUG
SYSTEM_MODE_ENTER
Nom de mode
Système
INFO et supérieur
SYSTEM_MODE_EXIT
Nom de mode
Système
INFO et supérieur
Débogage du langage Apex
salesforce | Utilisation de journaux dans la Console du
développeur | 269
Nom de l'événement
Champs ou informations consignées avec
l'événement
Catégorie
consignée
Événement
consigné
TESTING_LIMITS
Aucun
Profil Apex
INFO et supérieur
Profil Apex
FINE et supérieur
TOTAL_EMAIL_RECIPIENTS_QUEUED Nombre d'e-mails envoyés
USER_DEBUG
Numéro de la ligne, niveau de consignation, Code Apex
chaîne fournie par l'utilisateur
DEBUG et
supérieur par défaut.
Si l'utilisateur
définit le niveau de
consignation pour la
méthode
System.Debug,
l'événement est
consigné à la place à
ce niveau.
VALIDATION_ERROR
Message d'erreur
Validation
INFO et supérieur
VALIDATION_FAIL
Aucun
Validation
INFO et supérieur
VALIDATION_FORMULA
Source de formule, valeurs
Validation
INFO et supérieur
VALIDATION_PASS
Aucun
Validation
INFO et supérieur
VALIDATION_RULE
Nom de règle
Validation
INFO et supérieur
VARIABLE_ASSIGNMENT
Numéro de la ligne, nom de la variable,
représentation par chaîne de la valeur de la
variable, adresse de la variable
Code Apex
FINEST
VARIABLE_SCOPE_BEGIN
Numéro de la ligne, nom de la variable, type, Code Apex
valeur indiquant si la variable peut être
référencée, valeur indiquant si la variable est
statique
FINEST
VARIABLE_SCOPE_END
Aucun
Code Apex
FINEST
VF_APEX_CALL
Nom d'élément, nom de méthode, type de
renvoi
Code Apex
INFO et supérieur
VF_DESERIALIZE_VIEWSTATE_BEGIN ID d'état de la vue
Visualforce
INFO et supérieur
VF_DESERIALIZE_VIEWSTATE_END Aucun
Visualforce
INFO et supérieur
VF_EVALUATE_FORMULA_BEGIN ID d'état de la vue, formule
Visualforce
FINER et supérieur
VF_EVALUATE_FORMULA_END
Aucun
Visualforce
FINER et supérieur
VF_PAGE_MESSAGE
Texte du message
Code Apex
INFO et supérieur
VF_SERIALIZE_VIEWSTATE_BEGIN ID d'état de la vue
Visualforce
INFO et supérieur
VF_SERIALIZE_VIEWSTATE_END Aucun
Visualforce
INFO et supérieur
WF_ACTION
Description de l'action
Workflow
INFO et supérieur
WF_ACTION_TASK
Objet de la tâche, ID d'action, règle,
propriétaire, date d'échéance
Workflow
INFO et supérieur
WF_ACTIONS_END
Récapitulatif des actions exécutées
Workflow
INFO et supérieur
Débogage du langage Apex
salesforce | Utilisation de journaux dans la Console du
développeur | 270
Nom de l'événement
Champs ou informations consignées avec
l'événement
Catégorie
consignée
Événement
consigné
WF_APPROVAL
Type de transition, EntityName:
Workflow
NameField Id, nom de noeud de processus
INFO et supérieur
WF_APPROVAL_REMOVE
EntityName: NameField Id
Workflow
INFO et supérieur
WF_APPROVAL_SUBMIT
EntityName: NameField Id
Workflow
INFO et supérieur
WF_ASSIGN
Propriétaire, ID de modèle de bénéficiaire
Workflow
INFO et supérieur
WF_CRITERIA_BEGIN
EntityName: NameField Id, nom de
Workflow
INFO et supérieur
WF_CRITERIA_END
Valeur booléenne indiquant le succès (true ou Workflow
false)
INFO et supérieur
WF_EMAIL_ALERT
ID d'action, règle
Workflow
INFO et supérieur
WF_EMAIL_SENT
ID de modèle d'e-mail, destinataires, e-mails Workflow
CC
INFO et supérieur
WF_ENQUEUE_ACTIONS
Récapitulatif des actions mises en file
d'attente
Workflow
INFO et supérieur
WF_ESCALATION_ACTION
ID de requête, heures d'ouverture
Workflow
INFO et supérieur
WF_ESCALATION_RULE
Aucun
Workflow
INFO et supérieur
WF_EVAL_ENTRY_CRITERIA
Nom de processus, ID de modèle d'e-mail,
valeur booléenne indiquant le résultat (true
ou false)
Workflow
INFO et supérieur
WF_FIELD_UPDATE
EntityName: NameField Id, nom
Workflow
INFO et supérieur
règle, ID de règle, type de déclencheur (si la
règle respecte les types de déclencheur)
d'objet ou de champ
WF_FORMULA
Source de formule, valeurs
Workflow
INFO et supérieur
WF_HARD_REJECT
Aucun
Workflow
INFO et supérieur
WF_NEXT_APPROVER
Propriétaire, type de propriétaire suivant,
champ
Workflow
INFO et supérieur
WF_NO_PROCESS_FOUND
Aucun
Workflow
INFO et supérieur
WF_OUTBOUND_MSG
EntityName: NameField Id, ID
Workflow
INFO et supérieur
d'action, règle
WF_PROCESS_NODE
Nom de processus
Workflow
INFO et supérieur
WF_REASSIGN_RECORD
EntityName: NameField Id, propriétaire Workflow
INFO et supérieur
WF_RESPONSE_NOTIFY
Nom du notificateur, e-mail du notificateur, Workflow
ID de modèle du notificateur
INFO et supérieur
WF_RULE_ENTRY_ORDER
Entier, ordre d'indication
Workflow
INFO et supérieur
WF_RULE_EVAL_BEGIN
Type de règle
Workflow
INFO et supérieur
WF_RULE_EVAL_END
Aucun
Workflow
INFO et supérieur
Débogage du langage Apex
salesforce | Débogage des appels d'API Apex | 271
Nom de l'événement
Champs ou informations consignées avec
l'événement
Catégorie
consignée
Événement
consigné
WF_RULE_EVAL_VALUE
Valeur
Workflow
INFO et supérieur
WF_RULE_FILTER
Critères de filtrage
Workflow
INFO et supérieur
WF_RULE_INVOCATION
EntityName: NameField Id
Workflow
INFO et supérieur
WF_RULE_NOT_EVALUATED
Aucun
Workflow
INFO et supérieur
WF_SOFT_REJECT
Nom de processus
Workflow
INFO et supérieur
WF_SPOOL_ACTION_BEGIN
Type de noeud
Workflow
INFO et supérieur
WF_TIME_TRIGGER
EntityName: NameField Id, action
Workflow
INFO et supérieur
Workflow
INFO et supérieur
temporelle, conteneur d'action temporelle,
date/heure d'évaluation
WF_TIME_TRIGGERS_BEGIN
Aucun
Voir aussi :
Compréhension du journal de débogage
Débogage des appels d'API Apex
Débogage des appels d'API Apex
Tous les appels d'API qui invoquent Apex prennent en charge une fonctionnalité de débogage qui permet d'accéder à des
informations détaillées sur l'exécution du code, notamment tous les appels à System.debug(). En plus de la Console du
développeur, un en-tête d'entrée SOAP appelé DebuggingHeader permet de définir la granularité de consignation selon les
niveaux présentés dans le tableau suivant.
Nom de l'élément
Type
Description
LogCategory
string
Spécifie le type d'information renvoyé dans le journal de débogage. Les valeurs
valides sont :
• Db
• Workflow
• Validation
• Callout
• Apex_code
• Apex_profiling
• All
Débogage du langage Apex
salesforce | Débogage des appels d'API Apex | 272
Nom de l'élément
Type
Description
LogCategoryLevel
string
Spécifie la quantité d'information renvoyée dans le journal de débogage. Seul
l'élément Apex_code LogCategory utilise les niveaux de catégorie du journal.
Les niveaux de consignation valides (répertoriés du plus bas au plus élevé) sont les
suivants :
•
•
•
•
•
•
•
ERROR
WARN
INFO
DEBUG
FINE
FINER
FINEST
De plus, les niveaux de consignation suivant sont pris en charge dans l'élément DebuggingHeader pour la rétrocompatibilité.
Niveau de consignation
Description
NONE
Ne comprend aucun message du journal.
DEBUGONLY
Comprend les messages de niveau inférieur, ainsi que les messages générés par des appels
à la méthode System.debug.
DB
Comprend les messages du journal générés par des appels à la méthode System.debug,
ainsi que chaque instruction DML (langage de manipulation de données), ou requête
SOQL ou SOSL.
PROFILE
Comprend les messages du journal générés par des appels à la méthode System.debug,
chaque instruction DML, ou requête SOQL ou SOSL en ligne, ainsi que l'entrée et la
sortie de chaque méthode définie par l'utilisateur. De plus, la fin du journal de débogage
contient des informations de profilage globales pour les portions de la requête qui ont
utilisé la plus grande quantité de ressources en termes d'instructions SOQL et SOSL,
d'opérations DML et d'invocations de méthode Apex. Ces trois sections répertorient
les emplacements du code qui consomment le plus de temps, par ordre décroissant de
durée cumulée totale, ainsi que le nombre d'exécutions.
CALLOUT
Comprend le fichier XML de requête-réponse que le serveur envoie et reçoit d'un service
Web externe. Il est utile pour déboguer des problèmes liés à l'utilisation des appels d'API
des services Web Force.com.
DETAIL
Comprend tous les messages générés par le niveau PROFILE, ainsi que les éléments
suivants :
• Instructions de déclaration de variable
• Début des exécutions de boucle
• Tous les contrôles de boucle, tels que break et continue
• Les exceptions levées *
• Le code d'initialisation statique et de classe *
• Toute modification dans le contexte with sharing
Débogage du langage Apex
salesforce | Gestion des exceptions non détectées | 273
L'en-tête de sortie correspondant, DebuggingInfo, contient le journal de débogage qui en résulte. Pour plus informations,
reportez-vous à DebuggingHeader à la page 803.
Voir aussi :
Compréhension du journal de débogage
Utilisation de journaux dans la Console du développeur
Gestion des exceptions non détectées
Si du code Apex contient un bogue ou ne détecte pas une exception au niveau du code :
•
•
Une explication simple du problème s'affiche pour l'utilisateur dans l'interface de l'application. Ce message d'erreur inclut
la trace de la pile Apex.
Le développeur spécifié dans le champ LastModifiedBy reçoit l'erreur par e-mail avec la trace de la pile Apex ainsi que
l'ID d'utilisateur et de l'organisation du client. Aucune autre donnée de consommateur n'est renvoyée avec le rapport.
Notez que pour un code Apex exécuté de façon synchrone, certains e-mails d'erreur sont supprimés en raison d'erreurs
d'exception dupliquées. Pour un code Apex exécuté de façon asynchrone (Apex par lot, Apex planifié ou méthodes futures
(méthodes annotées avec @future), les e-mails d'erreur pour des exceptions dupliquées ne sont pas supprimés.
Compréhension des limitations et des gouverneurs d'exécution
Comme le langage Apex est exécuté dans un environnement mutualisé, le moteur d'exécution Apex applique une limitation
stricte pour empêcher qu'un emballement de code Apex ne monopolise des ressources partagées. Ces limitations, ou gouverneurs,
surveillent et appliquent les statistiques présentées dans le tableau suivant. Si un code Apex dépasse une limite, le gouverneur
associé génère une exception à l'exécution qui ne peut pas être gérée.
Les limitations du gouverneur s'appliquent à l'ensemble de l'organisation, ainsi qu'à des espaces de noms spécifiques. Par
exemple, si vous installez un package géré créé par un FAI partenaire de salesforce.com à partir de Force.com AppExchange,
les composants du package appartiennent à un espace de noms unique par rapport à d'autres composants dans votre organisation.
Par conséquent, tout code Apex inclus dans un package peut générer jusqu'à 150 instructions DML pendant l'exécution. De
plus, tout code Apex natif de votre organisation peut générer jusqu'à 150 instructions DML, ce qui signifie que plus de 150
instructions DML peuvent être exécutées durant une demande unique si un code du package géré et un code de votre organisation
native sont exécutés. Inversement, si vous installez un package à partir d'AppExchange qui n'est pas créé par un FAI partenaire
de salesforce.com, le code de ce package n'inclut pas son propre décompte séparé de limitations du gouverneur. Toutes les
ressources qu'il utilise sont prises en compte dans le total de votre organisation. Les messages de ressources cumulées et les
e-mails d'avertissement sont également générés sur la base des espaces de noms du package géré. Pour plus d'informations sur
les packages de FAI partenaires de salesforce.com, reportez-vous à Programmes partenaires salesforce.com.
Description
Nombre total de requêtes SOQL émises
Limitation
1
100
1
Nombre total de requêtes SOQL émises pour des méthodes Apex par lot et futures
200
Nombre de total d'enregistrements récupérés par des requêtes SOQL
50 000
Débogage du langage Apex
salesforce | Compréhension des limitations et des gouverneurs
d'exécution | 274
Description
Limitation
Nombre total d'enregistrements récupérés par Database.getQueryLocator
10 000
Nombre total de requêtes SOSL émises
20
Nombre de total d'enregistrements récupérés par une seule requête SOQL
200
Nombre total d'instructions DML émises2
150
Nombre total d'enregistrements traités suite à des instructions DML, Approval.process 10 000
ou database.emptyRecycleBin
Nombre total d'instructions de code exécutées
200 000
Nombre total d'instructions de code exécutées pour des méthodes Apex par lot et futures
1 000 000
Taille totale du segment mémoire3
6 Mo
Taille totale du segment mémoire pour les méthodes Apex par lot et futures
12 Mo
Profondeur totale de la pile pour toute invocation Apex qui active récursivement des
déclencheurs en raison d'instructions insert, update ou delete4
16
Taille par lot de la liste de boucles For
200
Nombre total d'appels (demandes HTTP ou appels de services Web) dans une demande
10
Délai d'expiration maximal de tous les appels (demandes HTTP ou appels de services Web) 120 secondes
dans une demande
Délai d'expiration par défaut des appels (demandes HTTP ou appels de services Web) dans 10 secondes
une demande
Nombre total de méthodes avec l'annotation future autorisées par invocation Apex5
10
Taille maximale de demande ou de réponse d'appel (demande HTTP ou appel de service
Web)6
3 Mo
Nombre total de méthodes sendEmail autorisées
10
Nombre total d'informations describe autorisées7
100
Nombre total de classe qui peuvent être planifiées simultanément
25
Nombre total de classes de test qui peuvent être mises en file d'attente par période de 24
heures8
La valeur la plus grande entre
500 et 10 multiplié par le
monde de classes de test dans
l'organisation
1
Dans une requête SOQL avec des sous-requêtes de relation parent-enfant, chaque relation parent-enfant est considérée
comme une requête supplémentaire. Ces types de requête sont limitées à trois fois le nombre de requêtes de niveau supérieur.
Le nombre de lignes de ces requêtes relationnelles est pris en compte dans le nombre de lignes de l'exécution globale du code.
En plus des instructions SOQL statiques, les appels aux méthodes suivantes sont prises en compte dans le nombre d'instructions
SOQL émises dans une demande.
•
•
Database.countQuery
Database.getQueryLocator
Débogage du langage Apex
•
2
•
•
•
•
•
•
•
•
•
•
•
•
3
salesforce | Compréhension des limitations et des gouverneurs
d'exécution | 275
Database.query
Les appels aux méthodes suivantes sont pris en compte dans le nombre de requêtes DML émises dans une demande.
Approval.process
Database.convertLead
Database.emptyRecycleBin
Database.rollback
Database.setSavePoint
delete et Database.delete
insert et Database.insert
merge
undelete et Database.undelete
update et Database.update
upsert et Database.upsert
System.runAs
La taille du segment mémoire des services de messagerie st de 36 Mo.
4
Un code Apex récursif qui n'active aucun déclencheur avec des instructions insert, update ou delete existe dans une
invocation unique, avec une pile unique. Inversement, un code Apex unique qui active un déclencheur engendre le déclencheur
dans une nouvelle invocation Apex, séparée de l'invocation du code qui a activé le déclencheur. Comme la génération d'une
nouvelle invocation de code Apex est une opération plus coûteuse qu'un appel récursif dans une invocation unique, les restrictions
sur la profondeur de la pile de ces types d'appel récursif sont plus élevées.
5
Salesforce impose également une limite sur le nombre d'invocations de méthode future : 200 appels de méthode par licence
utilisateur Salesforce complète, licence utilisateur Salesforce Platform ou licence utilisateur Force.com App Subscription, par
24 heures. Cette limitation s'applique à l'échelle de l'organisation. Les licences utilisateur Chatter Only, Utilisateurs clients
de Chatter, Customer Portal User et Partner portal ne sont pas incluses dans le calcul de cette limitation. Par exemple, supposons
que votre organisation possède trois licences Salesforce complètes, deux licences Salesforce Platform et 100 licences Customer
Portal User. Votre organisation entière est limitée à 1000 appels de méthode par 24 heures, calculés par la formule 200 * (3+2),
pas 200 * (3+2+100).
6
Les tailles des demandes et des réponses HTTP sont prises en compte dans la taille totale du segment mémoire.
7
Les informations describe comprennent les méthodes et les objets suivants :
•
•
•
•
•
Objets ChildRelationship
Objets RecordTypeInfo
Objets PicklistEntry
Appels fields
Appels fieldsets
8
Cette limite s'applique lorsque vous lancez des tests asynchrones en sélectionnant des classes de test pour l'exécution via la
page Exécution du test Apex.
Des limitations s'appliquent individuellement à chaque testMethod.
Utilisez les méthodes Limits pour déterminer les limites d'exécution de votre code pendant son exécution. Par exemple, vous
pouvez utiliser la méthode getDMLStatements pour déterminer le nombre d'instructions DML qui ont déjà été appelées
par votre programme, ou la méthode getLimitDMLStatements pour déterminer le nombre total d'instructions DML
disponibles pour votre code.
Débogage du langage Apex
salesforce | Compréhension des limitations et des gouverneurs
d'exécution | 276
Pour de meilleures performances, les requêtes SOQL doivent être sélectives, notamment pour les requêtes dans des déclencheurs.
Pour éviter les délais d'exécution importants, les requêtes SOQL non sélectives peuvent être terminées par le système. Les
développeurs reçoivent un message d'erreur lorsqu'une requête non sélective dans un déclencheur est exécutée sur un objet qui
contient plus de 100 000 enregistrements. Pour éviter cette erreur, assurez-vous d'utiliser une requête sélective. Reportez-vous
à Requêtes SOQL plus efficaces.
Pour un code Apex enregistré en utilisant l'API Salesforce.com version 20.0 ou antérieure, si un appel d'API active un
déclencheur, le lot de 200 enregistrements à traiter est divisé en lots de 100 enregistrements. Pour un code Apex enregistré en
utilisant l'API Salesforce.com versions 21.0 et supérieures, les lots d'API ne sont pas divisés. Notez que les valeurs de variable
statique sont réinitialisées entre les lots, contrairement aux limitations du gouverneur. N'utilisez pas des variables statiques
pour suivre les informations d'état entre les lots.
En plus des limitations du gouverneur d'exécution, le langage Apex comprend les limitations suivantes :
•
•
•
Le nombre maximal de caractères pour une classe est de 1 million.
Le nombre maximal de caractères pour un déclencheur est de 1 million.
Le volume maximal de code Apex utilisé dans une organisation est de 3 Mo.
Remarque: Cette limite ne s'applique pas aux packages gérés certifiés installés à partir d'AppExchange, (c.-à-d.
une application marquée Certifiée AppExchange). Le code de ces types de package appartient à un espace de
noms unique du code de votre organisation. Pour plus d'informations sur les packages certifiés AppExchange,
reportez-vous à l'aide en ligne de Force.com AppExchange.
Cette limite ne s'applique à aucun code inclus dans une classe définie avec l'annotation @isTest.
•
•
•
•
•
•
•
La taille de la méthode est limitée. Les méthodes volumineuses qui dépassent la limite autorisée entraînent une exception
à l'exécution de votre code. Comme dans Java, dans le langage Apex la limite de la taille de méthode est de 65 535 octets
de bytecode d'instructions compilées.
Si une requête SOQL est exécutée pendant plus de 120 secondes, elle peut être annulée par Salesforce.
Chaque demande Apex est limitée à 10 minutes d'exécution.
Une demande d'appel est limitée à 20 demandes simultanées à des URL avec le même hôte. L'hôte est défini par le
sous-domaine unique de l'URL, par exemple www.monsite.com et extra.monsite.com sont deux hôtes différents.
La limite est calculée sur l'ensemble des organisations qui accèdent au même hôte. Si la limite est dépassée, une exception
CalloutException est levée.
Le nombre maximal d'enregistrements qu'un rapport d'événement renvoie est de 20 000 pour un utilisateur non
administrateur système et de 100 000 pour un administrateur système.
Chaque organisation a droit à 10 demandes synchrones simultanées pour des demandes longues dont l'exécution dépasse
5 secondes. Si des demandes supplémentaires sont effectuées alors que 10 longues demandes sont en cours d'exécution,
elles sont refusées.
Un utilisateur peut avoir jusqu'à 50 curseurs de requête ouverts en même temps. Par exemple, si 50 curseurs sont ouverts
et qu'une application cliente toujours connectée sous le même utilisateur tente d'en ouvrir un nouveau, le plus ancien des
50 curseurs est libéré. Notez que cette limitation est différente pour la méthode start Apex, qui peut avoir jusqu'à cinq
curseurs de requête ouverts à la fois par utilisateur. Les autres méthodes Apex par lot ont une limite plus élevée de 50
curseurs.
Les limitations en curseur des différentes fonctionnalités Force.com sont suivies séparément. Par exemple, vous pouvez
avoir 50 Apex curseurs de requête, 50 curseur par lot et 50 curseurs Visualforce ouverts en même temps.
•
Dans une transaction unique, vous pouvez référencer uniquement 10 espaces de noms uniques. Par exemple, supposons
que vous avez un objet qui exécute une classe dans un package géré lors de la mise à jour de l'objet. Ensuite, cette classe
met à jour un deuxième objet, qui à son tour exécute une classe différente dans un package différent. Bien que le deuxième
Débogage du langage Apex
•
•
salesforce | Compréhension des limitations et des gouverneurs
d'exécution | 277
package n'a pas été accédé directement par le premier, car il se produit dans la même transaction, il est inclus dans le nombre
d'espaces de noms accédés dans une transaction unique.
Tout déploiement d'un code Apex est limité à 5000 unités de code de classes et de déclencheurs.
Si vous utilisez le produit Mise à jour Data.com et ses tâches automatisées, et que vous avez défini des déclencheurs Apex
avec des requêtes SOQL qui s'exécutent sur des enregistrements de compte, de contact ou de piste, les requêtes peuvent
interférer avec les tâches de Mise à jour de ces objets. Vos déclencheurs Apex (combinés) ne doivent pas dépasser 200
requêtes SOQL par lot. Sinon, votre tâche Mise à jour pour cet objet échoue. De plus, si vos déclencheurs appellent des
méthodes future, ils sont soumis à une limite de 10 appels future par lot.
Limitations en e-mails
Limitations en e-mails entrants
Services de messagerie : Nombre maximal d'e-mails traités
(inclut la limite pour E-mail vers requête à la demande)
Nombre de licences utilisateur
multiplié par 1 000, jusqu'à un
maximum de 1 000 000 par jour
Services de messagerie : Taille maximale d'un e-mail (corps et pièces jointes)
10 Mo1
E-mail vers requête à la demande : Taille maximale d'une pièce jointe
10 Mo
E-mail vers requête à la demande : Nombre maximal d'e-mails traités
Nombre de licences utilisateur
multiplié par 1 000, jusqu'à un
maximum de 1 000 000 par jour
(pris en compte dans la limitation des services de messagerie)
1
La taille maximale des e-mails des services de messagerie varie en fonction de la langue et du jeu de caractères.
Lors de la définition de services de messagerie, notez les éléments suivants :
•
•
•
•
•
Un service de messagerie traite uniquement les messages qu'il reçoit à l'une de ses adresses.
Salesforce limite le nombre total de messages que tous les services de messagerie combinés, E-mail vers requête à la
demande inclus, peuvent traiter quotidiennement. Les messages qui dépassent cette limite sont renvoyés, ignorés ou
mis en file d'attente pour un traitement le jour suivant, en fonction de la configuration des paramètres de réponse
d'échec de chaque service de messagerie. Salesforce calcule la limite en multipliant le nombre de licences utilisateur
par 1 000, jusqu'à une valeur quotidienne maximale de 1 000 000. Par exemple, si vous avez 10 licences, votre
organisation peut traiter jusqu'à 10 000 e-mails par jour.
Les adresses de services de messagerie que vous créez dans votre sandbox ne peuvent pas être copiées dans votre
organisation de production.
Pour chaque service de messagerie, vous pouvez instruire Salesforce d'envoyer les messages d'erreur à une adresse
spécifique au lieu de celle de l'expéditeur.
Les services de messagerie rejettent les e-mails et notifient l'expéditeur si l'e-mail (corps de texte, corps HTML et
pièces jointes combinés) dépassent 10 Mo environ (selon la langue et le jeu de caractères).
E-mail sortant : Limitations pour les e-mails individuels et en masse envoyés en utilisant Apex
Vous pouvez envoyer des e-mails individuels au maximum à 1000 adresses e-mail externes par jour, en fonction de l'heure
GMT. Les e-mails individuels envoyés en utilisant l'application ne sont pas pris en compte dans cette limite.
Vous pouvez envoyer des e-mails en masse à 1 000 adresses e-mail externes par organisation et par jour, en fonction de
l'heure GMT. Le nombre maximum d'adresses externes que vous pouvez inclure dans chaque e-mail en masse dépend
de l'édition Salesforce que vous utilisez :
Débogage du langage Apex
salesforce | Compréhension des limitations et des gouverneurs
d'exécution | 278
Edition
Limitation en adresses par e-mails en masse
Professional
250
Enterprise Edition
500
Unlimited Edition
1000
Remarque: Notez les points suivants sur les limitation en e-mails :
•
•
•
Les limitations en e-mails individuels et en masse ne prennent pas en compte les adresses uniques. Par
exemple, si vous avez 10 fois l'adresse [email protected] dans votre e-mail, 10 adresses sont
prises en compte dans la limite.
Vous pouvez envoyer un nombre illimité d'e-mails à vos utilisateurs internes. Ces limites s'appliquent
également aux e-mails envoyés à l'aide de l'API et d'Apex.
Dans les organisations Developer Edition et dans celles qui utilisent Salesforce pendant une période
d'évaluation, votre organisation peut envoyer un e-mail en masse au maximum à 10 adresses e-mail externes
par jour. Cette limitation inférieure ne s'applique pas si votre organisation a été créée avant la version Winter
'12 et si elle a déjà activé les e-mails en masse avec une limitation supérieure.
Limitations du gouverneur pour une tâche Apex par lot
Notez les limitations du gouverneur suivantes pour une tâche Apex par lot :
•
•
Jusqu'à cinq tâches par lot en file d'attente ou actives sont autorisées pour Apex.
Un utilisateur peut avoir jusqu'à 50 curseurs de requête ouverts en même temps. Par exemple, si 50 curseurs sont ouverts
et qu'une application cliente toujours connectée sous le même utilisateur tente d'en ouvrir un nouveau, le plus ancien des
50 curseurs est libéré. Notez que cette limitation est différente pour la méthode start Apex, qui peut avoir jusqu'à cinq
curseurs de requête ouverts à la fois par utilisateur. Les autres méthodes Apex par lot ont une limite plus élevée de 50
curseurs.
Les limitations en curseur des différentes fonctionnalités Force.com sont suivies séparément. Par exemple, vous pouvez
avoir 50 Apex curseurs de requête, 50 curseur par lot et 50 curseurs Visualforce ouverts en même temps.
•
•
•
•
•
•
•
Un maximum de 50 millions d'enregistrements peuvent être renvoyés dans l'objet Database.QueryLocator. Si plus
de 50 millions d'enregistrements sont renvoyés, la tâche par lot est immédiatement terminée et marquée comme échouée.
Si la méthode start renvoie un QueryLocator, le paramètre de portée facultatif de Database.executeBatch peut
avoir une valeur maximale de 2000. Si vous définissez une valeur plus importante, Salesforce segmente les enregistrements
renvoyés par QueryLocator en lots plus petits limités à 2000 enregistrements. Si la méthode start renvoie un itérable, la
valeur du paramètre de portée n'a pas de limite maximale. Si vous utilisez une valeur très élevée, vous risquez toutefois
d'atteindre d'autres limites.
Si aucune taille n'est spécifiée avec le paramètre facultatif scope de Database.executeBatch, Salesforce segmente les
enregistrements renvoyés par la méthode start en lots de 200, puis passe chaque lot à la méthode execute. Les limitations
du gouverneur Apex sont réinitialisés à chaque exécution de la méthode execute.
Chaque méthode start, execute et finish peut mettre en oeuvre jusqu'à 10 appels.
Les exécutions par lot sont limitées à 10 appels par exécution de méthode.
Le nombre maximal d'exécutions par lot est de 250 000 par 24 heures.
Une seule méthode start d'une tâche Apex par lot peut être exécutée à la fois dans une organisation. Les tâches par lot
qui n'ont pas encore commencé restent dans la file d'attente jusqu'à leur démarrage. Notez que cette limite n'entraîne aucun
Débogage du langage Apex
salesforce | Utilisation d'avertissements par e-mail pour les
limitations du gouverneur | 279
échec de tâche par lot, et les méthodes execute des tâches Apex par lot continuent de s'exécuter en parallèle si plusieurs
taches simultanées sont en cours.
Voir aussi :
Quelles sont les limitations du langage Apex ?
Annotation Future
https://help.salesforce.com/apex/HTViewHelpDoc?id=data_dot_com_clean_scheduling_jobs.htm
Utilisation d'avertissements par e-mail pour les limitations du gouverneur
Lorsqu'un utilisateur invoque un code Apex qui dépasse de plus de 50 % une limitation du gouverneur, vous pouvez désigner
un utilisateur de votre organisation comme destinataire d'un e-mail de notification de l'événement qui contient des informations
supplémentaires. Pour activer les avertissements par e-mail :
1.
2.
3.
4.
5.
Connectez-vous à Salesforce en tant qu'utilisateur administrateur.
Cliquez sur Votre nom > Configuration > Gérer les utilisateurs > Utilisateurs.
Cliquez sur Modifier en regard du nom de l'utilisateur qui doit recevoir les notifications par e-mail.
Sélectionnez l'option Envoyer des e-mails d'avertissement Apex.
Cliquez sur Enregistrer.
Chapitre 9
Développement de code Apex dans des packages gérés
Sujets :
•
•
•
Versions de package
Dépréciation du code Apex
Comportement dans les versions de
package
Un package est un conteneur qui regroupe des éléments aussi petits qu'un
composant individuel ou aussi grands qu'une série d'applications associées. Une
fois le package créé, vous pouvez le distribuer à d'autres utilisateurs et organisations
Salesforce, même hors de votre société. Une organisation peut créer un seul
package géré que de nombreuses organisations peuvent télécharger et installer.
Les packages gérés diffèrent des packages non gérés car ils contiennent certains
composants verrouillés pour permettre leur mise à niveau ultérieure. Les packages
non gérés ne comprennent pas les composants verrouillés et ne peuvent pas être
mis à niveau.
Ce chapitre comprend les rubriques suivantes relatives au développement de code
Apex dans des packages gérés :
•
•
•
Versions de package
Dépréciation du code Apex
Comportement dans des versions de package
Développement de code Apex dans des packages gérés
salesforce | Versions de package | 281
Versions de package
Une version de package est un numéro qui identifie l'ensemble de composants chargés dans un package. Le numéro de version
se présente sous la forme numéroMajeur.numéroMineur.numéroCorrectif (par exemple, 2.1.3). Les numéros majeur
et mineur sont incrémentés à chaque publication d'une version importante. Le numéroCorrectif est généré et téléchargé
uniquement lors de la publication d'un correctif.
Les packages non gérés ne peuvent pas être mis à niveau. Chaque version du package est un simple ensemble de composants
à distribuer. Une version de package a plus d'importance pour des packages gérés. Les packages peuvent exposer des
comportements différents selon les versions. Les versions de package permettent aux éditeurs d'adapter les composants de leurs
packages gérés en publiant gracieusement des versions ultérieures sans gêner les intégrations clientes existantes utilisant le
package.
Lorsqu'un abonné existant installe une nouvelle version d'un package, le package ne contient qu'une seule instance de chaque
composant, mais les composants peuvent émuler des versions antérieures. Par exemple, un abonné peut utiliser un package
géré qui contient une classe Apex. Si l'éditeur décide de rendre obsolète une méthode dans la classe Apex et de publier une
nouvelle version du package, l'abonné continue de voir une seule instance de la classe Apex après l'installation de la nouvelle
version. Cependant, cette classe Apex peut continuer à émuler la version précédente de tout code qui référence la méthode
obsolète de la version antérieure.
Notez les points suivants lors du développement de code Apex dans des packages gérés :
•
•
•
•
•
•
•
•
Le code inclus dans une classe ou un déclencheur Apex faisant partie d'un package géré est automatiquement masqué et
ne peut pas être affiché dans une organisation d'installation. Les seules exceptions sont les méthodes déclarées comme
globales, dont les signatures peuvent être affichées dans une organisation d'installation.
Les packages gérés reçoivent un espace de noms unique. Cet espace de noms est automatiquement ajouté au début du nom
de vos classes, méthodes, variables, etc., afin d'empêcher la duplication des noms dans l'organisation d'installation.
Dans une transaction unique, vous pouvez référencer uniquement 10 espaces de noms uniques. Par exemple, supposons
que vous avez un objet qui exécute une classe dans un package géré lors de la mise à jour de l'objet. Ensuite, cette classe
met à jour un deuxième objet, qui à son tour exécute une classe différente dans un package différent. Bien que le deuxième
package n'a pas été accédé directement par le premier, car il se produit dans la même transaction, il est inclus dans le nombre
d'espaces de noms accédés dans une transaction unique.
Le code inclus dans un code Apex faisant partie d'un package géré est automatiquement masqué et ne peut pas être affiché
dans une organisation d'installation. Les seules exceptions sont les méthodes déclarées comme globales, dont les signatures
peuvent être affichées dans une organisation d'installation.
Les développeurs de packages peuvent utiliser l'annotation deprecated pour identifier des méthodes, des classes, des
exceptions, des énumérations, des interfaces ou des variables qui ne peuvent plus être référencées dans les versions successives
du package géré dans lequel elles résident. Elles sont utiles pour refactoriser un code dans des packages gérés dont les
exigences évoluent.
Vous pouvez écrire des méthodes de test qui changent le contexte de version d'un package en une version de package
différente en utilisant la méthode système runAs.
Vous ne pouvez pas ajouter une méthode à une interface globale ou une méthode abstraite à une classe globale une fois
l'interface ou la classe chargée dans une version de package Géré-Publié. Si la classe du package Géré-Publié est virtuelle,
la méthode que vous pouvez lui ajouter doit également être virtuelle et avoir une mise en oeuvre.
Le code Apex contenu dans un package non géré qui référence explicitement un espace de noms ne peut pas être chargé.
Développement de code Apex dans des packages gérés
salesforce | Dépréciation du code Apex | 282
Dépréciation du code Apex
Les développeurs de packages peuvent utiliser l'annotation deprecated pour identifier des méthodes, des classes, des
exceptions, des énumérations, des interfaces ou des variables qui ne peuvent plus être référencées dans les versions successives
du package géré dans lequel elles résident. Elles sont utiles pour refactoriser un code dans des packages gérés dont les exigences
évoluent. Après avoir chargé une autre version de package Géré-Publié, les nouveaux abonnés qui installent la toute dernière
version du package ne peuvent pas afficher les éléments dépréciés, alors que les éléments continuent de fonctionner pour les
abonnés existants et les intégrations d'API. Un élément déprécié, tel qu'une méthode ou une classe, peut toujours être référencé
en interne par le développeur du package.
Remarque: Vous ne pouvez pas utiliser l'annotation deprecated dans des classes ou des déclencheurs Apex pour
des packages non gérés.
Les développeurs de package peuvent utiliser des versions Géré-Publié à des fins d'évaluation et de commentaires avec un
ensemble d'utilisateurs pilote dans des organisations Salesforce différentes. Si un développeur déprécie un identificateur Apex,
puis charge une version de package Géré-Publié, les abonnés qui installent la version du package continuent à afficher
l'identificateur déprécié dans cette version. Si le développeur du package charge ensuite une version du package Géré-Publié,
les abonnés n'affichent plus l'identificateur déprécié dans la version du package après l'avoir installée.
Comportement dans les versions de package
Un composant de package peut avoir un comportement différent selon la version d'un package. La gestion des comportements
dans les différentes versions permet d'ajouter de nouveaux composants à votre package et d'affiner vos composants existants,
tout en préservant un fonctionnement sans heurt pour les abonnés existants. Si un développeur ajoute un nouveau composant
à un package, puis charge une nouvelle version, le nouveau composant est disponible pour tous les abonnés qui installent la
nouvelle version du package.
Gestion des versions de comportement dans un code Apex
Les développeurs de package peuvent utiliser une logique conditionnelle dans des classes et des déclencheurs Apex afin d'exposer
des comportements différents d'une version à l'autre. Le développeur d'un package peut ainsi préserver la prise en charge d'un
comportement existant dans les classes et les déclencheurs de versions précédentes du package, tout en faisant évoluer le code.
Lorsque les abonnés installent plusieurs versions de votre package et écrivent un code qui référence des classes ou des déclencheurs
Apex dans votre package, ils doivent sélectionner la version qu'ils référencent. Dans le code Apex référencé dans votre package,
vous pouvez exécuter différents chemins de code conditionnels basés sur le paramètre de version du code Apex appelant qui
définit la référence. Le paramètre de version de package du code appelant peut être déterminé dans le code du package en
appelant la méthode System.requestVersion. Les développeurs d'un package peuvent ainsi déterminer le contexte de la
demande et spécifier un comportement différent pour les diverses versions du package.
L'exemple suivant utilise la méthode System.requestVersion et instancie la classe System.Version afin de définir
différents comportements dans un déclencheur Apex pour les diverses versions du package.
trigger oppValidation on Opportunity (before insert, before update) {
for (Opportunity o : Trigger.new){
Développement de code Apex dans des packages gérés
salesforce | Éléments de code Apex invariables dans les
différentes versions | 283
// Add a new validation to the package
// Applies to versions of the managed package greater than 1.0
if (System.requestVersion().compareTo(new Version(1,0)) > 0) {
if (o.Probability >= 50 && o.Description == null) {
o.addError('All deals over 50% require a description');
}
}
// Validation applies to all versions of the managed package.
if (o.IsWon == true && o.LeadSource == null) {
o.addError('A lead source must be provided for all Closed Won deals');
}
}
}
Pour consulter une liste complète de méthodes qui fonctionnent dans des versions de package, reportez-vous à Méthodes
Version et à la méthode System.requestVersion dans Méthodes System.
Le contexte de la demande est préservé si une classe dans le package installé invoque une méthode dans une autre classe de
package. Par exemple, un abonné a installé le package RapportsGeo qui contient les classes Apex UtilPays et UtilContinent.
L'abonné crée une classe RapportsGeoEx et utilise les paramètres de version pour la lier à la version 2.3 du package RapportsGeo.
Si RapportsGeoEx invoque une méthode dans UtilContinent qui invoque en interne une méthode dans UtilPays, le contexte
de la demande est propagé de UtilContinent à UtilPays, et la méthode System.requestVersion dans UtilPays renvoie la
version 2.3 du package RapportsGeo.
Éléments de code Apex invariables dans les différentes versions
Vous pouvez modifier le comportement de certains éléments Apex entre les différentes versions d'un package. Par exemple,
vous pouvez déprécier une méthode afin que les nouveaux abonnés ne puissent plus référencer le package dans une version
ultérieure.
Cependant, les modificateurs, les mots clés et les annotations de la liste ci-dessous ne peuvent pas différer d'une version à
l'autre. Si le développeur d'un package change l'un de ces modificateurs, mots clés ou annotations, les modifications sont
reflétées dans toutes les versions du package.
Les modifications que vous pouvez apporter à certains de ces éléments sont limitées lorsqu'ils sont utilisés dans un code Apex
dans des packages gérés.
Les développeurs de package peuvent ajouter ou supprimer les éléments suivants :
•
•
•
@future
@isTest
with sharing
Développement de code Apex dans des packages gérés
•
•
salesforce | Test du comportement dans les versions de
package | 284
without sharing
transient
Les développeurs de package peuvent apporter des modifications limitées aux éléments suivants :
•
•
•
•
•
private : ne peut pas être changé en global
public : ne peut pas être changé en global
protected : ne peut pas être changé en global
abstract : ne peut pas être changé en virtual, mais ne peut pas être supprimé
final : ne peut pas être supprimé, mais ne peut pas être ajouté
Les développeurs de package peuvent supprimer ou modifier les éléments suivants :
•
•
global
virtual
Les développeurs de package peuvent ajouter le mot clé webService, mais une fois ajouté, il ne peut pas être supprimé.
Remarque: Vous ne pouvez pas déprécier les méthodes ou les variables webService dans le code d'un package géré.
Test du comportement dans les versions de package
Lorsque vous modifiez le comportement dans une classe ou un déclencheur Apex pour différentes versions d'un package, il
est important de tester l'exécution de votre code dans toutes les versions. Vous pouvez écrire des méthodes de test qui changent
le contexte de version d'un package en une version de package différente en utilisant la méthode système runAs. Vous pouvez
également utiliser runAs dans une méthode de test.
L'exemple suivant présente un déclencheur dont le comportement diffère selon la version du package.
trigger oppValidation on Opportunity (before insert, before update) {
for (Opportunity o : Trigger.new){
// Add a new validation to the package
// Applies to versions of the managed package greater than 1.0
if (System.requestVersion().compareTo(new Version(1,0)) > 0) {
if (o.Probability >= 50 && o.Description == null) {
o.addError('All deals over 50% require a description');
}
}
// Validation applies to all versions of the managed package.
if (o.IsWon == true && o.LeadSource == null) {
Développement de code Apex dans des packages gérés
salesforce | Test du comportement dans les versions de
package | 285
o.addError('A lead source must be provided for all Closed Won deals');
}
}
}
La classe de test suivante utilise la méthode runAs pour vérifier le comportement du déclencheur avec et sans version spécifique
:
@isTest
private class OppTriggerTests{
static testMethod void testOppValidation(){
// Set up 50% opportunity with no description
Opportunity o = new Opportunity();
o.Name = 'Test Job';
o.Probability = 50;
o.StageName = 'Prospect';
o.CloseDate = System.today();
// Test running as latest package version
try{
insert o;
}
catch(System.DMLException e){
System.assert(
e.getMessage().contains(
'All deals over 50% require a description'),
e.getMessage());
}
// Run test as managed package version 1.0
System.runAs(new Version(1,0)){
try{
insert o;
Développement de code Apex dans des packages gérés
salesforce | Test du comportement dans les versions de
package | 286
}
catch(System.DMLException e){
System.assert(false, e.getMessage());
}
}
// Set up a closed won opportunity with no lead source
o = new Opportunity();
o.Name = 'Test Job';
o.Probability = 50;
o.StageName = 'Prospect';
o.CloseDate = System.today();
o.StageName = 'Closed Won';
// Test running as latest package version
try{
insert o;
}
catch(System.DMLException e){
System.assert(
e.getMessage().contains(
'A lead source must be provided for all Closed Won deals'),
e.getMessage());
}
// Run test as managed package version 1.0
System.runAs(new Version(1,0)){
try{
insert o;
}
catch(System.DMLException e){
System.assert(
e.getMessage().contains(
Développement de code Apex dans des packages gérés
salesforce | Test du comportement dans les versions de
package | 287
'A lead source must be provided for all Closed Won deals'),
e.getMessage());
}
}
}
}
Chapitre 10
Exposition de méthodes Apex en tant que services Web SOAP
Sujets :
•
Méthodes WebService
Vous pouvez exposer vos méthodes Apex en tant que services Web SOAP afin
de permettre à des applications externes d'accéder à votre code et à votre
application. Pour exposer vos méthodes Apex, utilisez les Méthodes WebService.
Conseil:
•
•
Les services Web SOAP Apex permettent à une application externe
d'invoquer des méthodes Apex via des services Web SOAP. Les
appels Apex permettent à un code Apex d'invoquer des services Web
ou HTTP externes.
L'API REST Apex expose vos classes et méthodes Apex en tant que
services Web REST. Reportez-vous à Exposition de classes Apex
en tant que services Web REST.
Exposition de méthodes Apex en tant que services Web SOAP
salesforce | Méthodes WebService | 289
Méthodes WebService
Les méthodes de classe Apex peuvent être exposées en tant qu'appels de services Web SOAP. Cela permet à une application
externe d'invoquer un service Web Apex pour exécuter une action dans Salesforce. Utilisez le mot clé webService pour
définir ces méthodes. Par exemple :
global class MyWebService {
webService static Id makeContact(String lastName, Account a) {
Contact c = new Contact(lastName = 'Weissman', AccountId = a.Id);
insert c;
return c.id;
}
}
Un développeur d'une application externe peut l'intégrer à une classe Apex contenant des méthodes webService en générant
un WSDL pour la classe. Pour générer un WSDL à partir d'une page de détail de la classe Apex :
1. Dans l'application, accédez à Votre nom > Configuration > Développer > Classes Apex.
2. Cliquez sur le nom de la classe qui contient les méthodes webService.
3. Cliquez sur Générer WSDL.
Exposition des données avec des méthodes WebService
L'invocation d'une méthode webService personnalisée utilise toujours le contexte système. Par conséquent, les identifiants
de l'utilisateur actif ne sont pas utilisés, et tout utilisateur ayant accès à ces méthodes peut exploiter toute leur puissance, quelles
que soient les autorisations, la sécurité au niveau du champ ou les règles de partage. Les développeurs qui exposent des méthodes
avec le mot clé webService doivent par conséquent s'assurer de ne pas révéler accidentellement des données confidentielles.
ATTENTION: Les méthodes de classe Apex exposées via l'API avec le mot clé webService n'imposent pas les
autorisations d'objet et la sécurité au niveau du champ par défaut. Nous recommandons d'utiliser l'objet approprié ou
les méthodes field describe result afin de vérifier le niveau d'accès de l'utilisateur actif sur les objets et les champs
auxquels la méthode webService a accès. Reportez-vous à Schema.DescribeSObjectResult et à
Schema.DescribeFieldResult.
De plus, les règles de partage (accès au niveau de l'enregistrement) sont appliquées uniquement lors de la déclaration
d'une classe avec le mot clé with sharing. Cette exigence s'applique à toutes les classes Apex, y compris les classes
qui contiennent des méthodes webService. Pour appliquer des règles de partage pour des méthodes webService,
déclarez la classe qui contient ces méthodes avec le mot clé with sharing. Reportez-vous à Utilisation des mots
clés with sharing ou without sharing.
Considérations sur l'utilisation du mot clé WebService
Lors de l'utilisation du mot clé webService, tenez compte des considérations suivantes :
Exposition de méthodes Apex en tant que services Web SOAP
•
•
•
•
•
•
•
•
•
Vous ne pouvez pas utiliser le mot clé webService lors de la définition d'une classe. Vous pouvez toutefois l'utiliser pour
définir des méthodes de classe externe de niveau supérieur et des méthodes de classe interne.
Vous ne pouvez pas utiliser le mot clé webService pour définir une interface, ou des méthodes et des variables d'une
interface.
Les énumérations définies par le système ne peuvent pas être utilisées dans des méthodes de service Web.
Vous ne pouvez pas utiliser le mot clé webService dans un déclencheur, car il n'est pas possible de définir une méthode
dans un déclencheur.
Toutes les classes qui contiennent des méthodes définies avec le mot clé webService doivent être déclarées global. Si
une méthode ou une classe interne est déclarée global, la classe externe de niveau supérieur doit également être définie
comme global.
Les méthodes définies avec le mot clé webService sont par nature globales. Ces méthodes peuvent être utilisées avec
n'importe quel code Apex qui a accès à la classe. Vous pouvez considérer le mot clé webService comme un type de
modificateur d'accès qui offre un accès supérieur à global.
Vous devez définir toutes les méthodes qui utilisent le mot clé webService comme static.
Vous ne pouvez pas déprécier les méthodes ou les variables webService dans le code d'un package géré.
Comme il n'existe aucun analogue SOAP à certains éléments Apex, les méthodes définies avec le mot-clé webService
ne peuvent pas accepter les éléments suivants en tant que paramètres. Ces éléments peuvent être utilisés dans une méthode,
mais ils ne peuvent pas être marqués en tant que valeur renvoyée.
◊
◊
◊
◊
◊
•
•
•
salesforce | Considérations sur l'utilisation du mot clé
WebService | 290
Maps
Sets
Objets Pattern
Objets Matcher
Objets Exception
Vous devez utiliser le mot clé webService avec toutes les variables de membre que vous souhaitez exposer dans un service
Web. Vous ne devez pas marquer ces variables de membre comme static.
Salesforce refuse l'accès à des requêtes de service Web et executeanonymous provenant d'un package AppExchange
dont l'accès est Restricted.
Les classes et les déclencheurs Apex sauvegardés (compilés) en utilisant l'API versions 15.0 et supérieures, génèrent une
erreur d'exécution si vous attribuez une valeur String trop longue pour le champ.
L'exemple suivant montre une classe avec des variables de membre de service Web ainsi qu'une méthode de service Web :
global class SpecialAccounts {
global class AccountInfo {
webService String AcctName;
webService Integer AcctNumber;
}
webService static Account createAccount(AccountInfo info) {
Account acct = new Account();
acct.Name = info.AcctName;
Exposition de méthodes Apex en tant que services Web SOAP
salesforce | Considérations sur l'utilisation du mot clé
WebService | 291
acct.AccountNumber = String.valueOf(info.AcctNumber);
insert acct;
return acct;
}
webService static Id [] createAccounts(Account parent,
Account child, Account grandChild) {
insert parent;
child.parentId = parent.Id;
insert child;
grandChild.parentId = child.Id;
insert grandChild;
Id [] results = new Id[3];
results[0] = parent.Id;
results[1] = child.Id;
results[2] = grandChild.Id;
return results;
}
testMethod static void testAccountCreate() {
AccountInfo info = new AccountInfo();
info.AcctName = 'Manoj Cheenath';
info.AcctNumber = 12345;
Account acct = SpecialAccounts.createAccount(info);
System.assert(acct != null);
}
}
Vous pouvez invoquer ce service Web en utilisant AJAX. Pour plus informations, reportez-vous à Apex dans AJAX à la page
121.
Exposition de méthodes Apex en tant que services Web SOAP
salesforce | Surcharge des méthodes WebService | 292
Surcharge des méthodes WebService
SOAP et WSDL n'offrent pas une bonne prise en charge de la surcharge des méthodes. Par conséquent, le langage Apex ne
permet pas à deux méthodes marquées avec le mot clé webService de porter le même nom. Les méthodes de service Web
qui portent le même nom dans la même classe génèrent une erreur à la compilation.
Chapitre 11
Exposition de classes Apex en tant que services Web REST
Sujets :
•
•
•
•
•
Introduction à REST Apex
Annotations REST Apex
Méthodes REST Apex
Exposition de données avec des
méthodes de services Web REST
Apex
Exemples de code REST Apex
Vous pouvez exposer vos classes et méthodes Apex pour permettre à des
applications externes d'accéder à votre code et à votre application via l'architecture
REST. Ce chapitre montre comment exposer vos classes Apex en tant que services
Web REST. Il présente également des annotations de classe et de méthode, ainsi
que des exemples de code qui montrent la mise en oeuvre cette fonctionnalité.
Exposition de classes Apex en tant que services Web REST
salesforce | Introduction à REST Apex | 294
Introduction à REST Apex
Vous pouvez exposer votre classe et vos méthodes Apex pour permettre à des applications externes d'accéder à votre code et à
votre application via l'architecture REST. Pour cela, définissez votre classe Apex avec l'annotation @RestResource pour
l'exposer en tant que ressource REST. De la même façon, ajoutez des annotations à vos méthodes pour les exposer via REST.
Pour plus informations, reportez-vous à Annotations REST Apex à la page 168
Limitations du gouverneur
Les appels aux classes REST Apex sont prises en compte dans les limitations du gouverneur API de l'organisation. Toutes les
limitations du gouverneur Apex standard s'appliquent aux classes REST Apex. Par exemple, la taille maximale de demande
de réponse est de 3 Mo. Pour plus d'informations, reportez-vous à Compréhension des limitations et des gouverneurs d'exécution.
Authentification
REST Apex prend en charge les mécanismes d'authentification suivants :
•
•
OAuth 2.0
ID de session
Reportez-vous à Step Two: Set Up Authorization dans le guide REST API Developer's Guide.
Annotations REST Apex
Six nouvelles annotations ont été ajoutées, qui permettent d'exposer une classe Apex en tant que service Web RESTful.
•
•
•
•
•
@RestResource(urlMapping='/yourUrl')
@HttpDelete
@HttpGet
@HttpPost
@HttpPut
Méthodes REST Apex
REST Apex prend en charge deux formats de représentation de ressources : JSON et XML. Les représentations JSON sont
passées par défaut dans le corps d'une demande ou d'une réponse, et le format est indiqué par la propriété Content-Type
dans l'en-tête HTTP. Vous pouvez récupérer le corps en tant que Blob dans l'objet HttpRequest si aucun paramètre n'est
défini dans la méthode Apex. Si des paramètres sont définis dans la méthode Apex, une tentative de désérialisation du corps
de la demande dans ces paramètres est effectuée. Si la méthode Apex a un type de renvoi non-void, la représentation de la
ressource est sérialisée dans le corps de la réponse. Seuls les types de renvoi et de paramètre suivants sont autorisés :
•
•
•
•
Primitifs Apex (sObject et Blob exclus).
sObjects
Listes ou mappages de primitifs ou sObjects Apex (seuls les mappages avec des clés String sont pris en charge)
Types définis par l'utilisateur qui contiennent des variables de membre des types répertoriés ci-dessus.
Exposition de classes Apex en tant que services Web REST
salesforce | Méthodes REST Apex | 295
Les méthodes annotées avec @HttpGet ou @HttpDelete ne doivent avoir aucun paramètre. Les requêtes GET et DELETE
n'ayant pas de corps de demande, il n'existe aucun élément à désérialiser.
Une classe Apex unique annotée avec @RestResource peut inclure plusieurs méthodes annotées avec la même méthode de
requête HTTP. Par exemple, la même classe ne peut pas avoir deux méthodes annotées avec @HttpGet.
Remarque: Actuellement, REST Apex ne prend pas en charge les demandes de Content-Type
multipart/form-data.
Considérations sur les méthodes REST Apex
Voici quelques points à considérer lorsque vous définissez des méthodes REST Apex.
•
Les objets RestRequest et RestResponse sont disponibles par défaut dans vos méthodes Apex via l'objet RestContext
statique. Cet exemple montre comment accéder à ces objets via RestContext :
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
•
•
•
Si la méthode Apex ne contient aucun paramètre, REST Apex copie le corps de la requête HTTP dans la propriété
RestRequest.requestBody. Si la méthode contient des paramètres, REST Apex tente de désérialiser les données dans
ces paramètres et les données ne sont pas désérialisées dans la propriété RestRequest.requestBody.
REST Apex utilise une logique de sérialisation similaire pour la réponse. Une méthode Apex avec un type de renvoi
non-void contient la valeur de renvoi sérialisée dans RestResponse.responseBody.
Les méthodes REST Apex peuvent être utilisées dans des packages gérés et non gérés. Lors de l'appel de méthodes REST
Apex contenues dans un package géré, vous devez inclure l'espace de noms du package géré dans l'URL de l'appel REST.
Par exemple, si la classe est incluse dans l'espace de noms d'un package géré appelé EspaceNomsPackage et que les
méthodes REST Apex utilisent un mappage d'URL de /MaMethode/*, l'URL utilisée via REST pour appeler ces méthodes
se présente comme suit :
https://instance.salesforce.com/services/apexrest/EspaceNomsPackage/MaMethode/. Pour plus
d'informations sur les packages gérés, reportez-vous à Développement de code Apex dans des packages gérés.
Types définis par l'utilisateur
Vous pouvez utiliser des types définis par l'utilisateur pour les paramètres dans vos méthodes REST Apex. REST Apex
désérialise les données des demandes en variables de membre de classe public, private ou global d'un type défini par
l'utilisateur, sauf si la variable est déclarée comme static ou transient. Par exemple une méthode REST Apex qui contient
un paramètre d'un type défini par l'utilisateur peut se présenter comme suit :
@RestResource(urlMapping='/user_defined_type_example/*')
global with sharing class MyOwnTypeRestResource {
@HttpPost
global static MyUserDefinedClass echoMyType(MyUserDefinedClass ic) {
return ic;
}
Exposition de classes Apex en tant que services Web REST
salesforce | Méthodes REST Apex | 296
global class MyUserDefinedClass {
global String string1;
global String string2 { get; set; }
private String privateString;
global transient String transientString;
global static String staticString;
}
}
Les données de demandes JSON et XML valides pour cette méthode se présentent comme suit :
{
"ic" : {
"string1" : "value for string1",
"string2" : "value for string2",
"privateString" : "value for privateString"
}
}
<request>
<ic>
<string1>value for string1</string1>
<string2>value for string2</string2>
<privateString>value for privateString</privateString>
</ic>
</request>
Si une valeur pour staticString ou transientString est fournie dans les données de l'exemple de demande ci-dessus,
une réponse de code d'état HTTP 400 est générée. Notez que les variables de membre de classe public, private ou global
doivent être des types autorisés par REST Apex :
•
•
•
Primitifs Apex (sObject et Blob exclus).
sObjects
Listes ou mappages de primitifs ou sObjects Apex (seuls les mappages avec des clés String sont pris en charge)
Exposition de classes Apex en tant que services Web REST
salesforce | Méthodes REST Apex | 297
Lors de la création de types définis par l'utilisateur utilisés en tant que paramètres de méthode REST Apex, évitez d'introduire
des définitions de variables de membre de classe qui entraînent des cycles (définitions interdépendantes) à l'exécution dans vos
types définis par l'utilisateur. Voici un exemple simple :
@RestResource(urlMapping='/CycleExample/*')
global with sharing class ApexRESTCycleExample {
@HttpGet
global static MyUserDef1 doCycleTest() {
MyUserDef1 def1 = new MyUserDef1();
MyUserDef2 def2 = new MyUserDef2();
def1.userDef2 = def2;
def2.userDef1 = def1;
return def1;
}
global class MyUserDef1 {
MyUserDef2 userDef2;
}
global class MyUserDef2 {
MyUserDef1 userDef1;
}
}
Le code de l'exemple précédent compile, mais lorsqu'une demande est effectuée à l'exécution, REST Apex détecte un cycle
entre les instances de def1 et def2, et génère une réponse d'erreur de code d'état HTTP 400.
Considérations sur les données de demande
Notez les points suivants sur les données de demandes pour vos méthodes REST Apex :
•
Le nom des paramètres Apex est important, mais pas leur ordre. Par exemple, les requêtes valides en XML et JSON se
présentent comme suit :
@HttpPost
global static void myPostMethod(String s1, Integer i1, Boolean b1, String s2)
{
Exposition de classes Apex en tant que services Web REST
salesforce | Méthodes REST Apex | 298
"s1" : "my first string",
"i1" : 123,
"s2" : "my second string",
"b1" : false
}
<request>
<s1>my first string</s1>
<i1>123</i1>
<s2>my second string</s2>
<b1>false</b1>
</request>
•
•
•
Certains types de paramètre et de renvoi ne peuvent pas être utilisés avec XML en tant que Content-Type pour la requête
ou en tant que format accepté pour la réponse. Par conséquent, les méthodes qui ont ces types de paramètre ou de renvoi
ne peuvent pas être utilisées avec XML. Les mappages ou collections de collections, par exemple List<List<String>>
ne sont pas pris en charge. Vous pouvez toutefois utiliser ces types avec JSON. Si la liste de paramètres inclut un type non
valide pour XML et que XML est envoyé, un code d'état HTTP 415 est renvoyé. Si le type de renvoi est un type non valide
pour XML et que XML est le format de réponse requis, un code d'état HTTP 406 est renvoyé.
Pour des données de requête en JSON ou XML, les valeurs correctes des paramètres booléens sont les suivantes : true,
false (les deux sont traités comme insensibles à la casse), 1 et 0 (les valeurs numériques, pas les chaînes de « 1 » ou « 0
»). Toute autre valeur pour des paramètres booléens génère une erreur.
Si les données de requête JSON ou XML contiennent plusieurs paramètres portant le même nom, une réponse d'erreur
de code d'état HTTP 400 est générée. Par exemple, si votre méthode spécifie un paramètre d'entrée nommé x, les données
de requête JSON suivantes génèrent une erreur :
{
"x" : "value1",
"x" : "value2"
}
De la même façon, pour des types définis par l'utilisateur, si les données de requête contiennent plusieurs données pour la
même variable de membre d'un type défini par l'utilisateur, une erreur est générée. Par exemple, avec cette méthode REST
Apex et ce type défini par l'utilisateur :
@RestResource(urlMapping='/DuplicateParamsExample/*')
global with sharing class ApexRESTDuplicateParamsExample {
@HttpPost
global static MyUserDef1 doDuplicateParamsTest(MyUserDef1 def) {
return def;
}
Exposition de classes Apex en tant que services Web REST
salesforce | Méthodes REST Apex | 299
global class MyUserDef1 {
Integer i;
}
}
Les données de requête JSON suivantes génèrent également une erreur :
{
"def" : {
"i" : 1,
"i" : 2
}
}
•
•
Si vous devez spécifier une valeur nulle pour l'un de vos paramètres dans vos données de requête, vous pouvez omettre le
paramètre ou spécifier une valeur nulle. Dans JSON, vous pouvez spécifier null en tant que valeur. Dans XML, vous
devez utiliser l'espace de noms http://www.w3.org/2001/XMLSchema-instance avec une valeur nulle.
Pour des données de requête XML, vous devez spécifier un espace de noms XML qui référence tous les espaces de noms
Apex utilisés par votre méthode. Ainsi par exemple, si vous définissez une méthode REST Apex telle que :
@RestResource(urlMapping='/namespaceExample/*')
global class MyNamespaceTest {
@HttpPost
global static MyUDT echoTest(MyUDT def, String extraString) {
return def;
}
global class MyUDT {
Integer count;
}
}
Vous pouvez utiliser les données de requête XML suivantes :
<request>
<def xmlns:MyUDT="http://soap.sforce.com/schemas/class/MyNamespaceTest">
Exposition de classes Apex en tant que services Web REST
salesforce | Méthodes REST Apex | 300
<MyUDT:count>23</MyUDT:count>
</def>
<extraString>test</extraString>
</request>
Pour plus d'informations sur les espaces de noms XML et Apex, reportez-vous à Espaces de noms XML.
Codes de statut de réponse
Le code de statut d'une réponse est défini automatiquement. Le tableau ci-dessous présente quelques codes de statut HTTP
ainsi que leur signification dans le contexte de la méthode de requête HTTP. Pour une liste complète de codes de statut de
réponse, reportez-vous à Méthodes RestResponse.
Méthode de requête
Code d'état de
réponse
Description
GET
200
La requête a réussi.
PATCH
200
La requête a réussi et le type renvoyé est non-void.
PATCH
204
La requête a réussi et le type renvoyé est void.
DELETE, GET, PATCH, POST,
PUT
400
Une exception utilisateur non gérée s'est produite.
DELETE, GET, PATCH, POST,
PUT
403
Vous n'avez pas accès à la classe Apex spécifiée.
DELETE, GET, PATCH, POST,
PUT
404
L'URL est sans mappage dans une annotation
@RestResource existante.
DELETE, GET, PATCH, POST,
PUT
404
L'extension URL n'est pas prise en charge.
DELETE, GET, PATCH, POST,
PUT
404
La classe Apex avec l'espace de noms spécifié est introuvable.
DELETE, GET, PATCH, POST,
PUT
405
La méthode de requête n'a pas de méthode Apex
correspondante.
DELETE, GET, PATCH, POST,
PUT
406
La propriété Content-Type dans l'en-tête a été définie sur
une valeur autre que JSON ou XML.
DELETE, GET, PATCH, POST,
PUT
406
L'en-tête spécifié dans la requête HTTP n'est pas pris en
charge.
GET, PATCH, POST, PUT
406
Le type de renvoi XML spécifié pour le format n'est pas pris
en charge.
DELETE, GET, PATCH, POST,
PUT
415
Le type de paramètre XML n'est pas pris en charge.
DELETE, GET, PATCH, POST,
PUT
415
Le type Content-Header spécifié dans l'en-tête de requête
HTTP n'est pas pris en charge.
DELETE, GET, PATCH, POST,
PUT
500
Une exception Apex non gérée s'est produite.
Exposition de classes Apex en tant que services Web REST
salesforce | Exposition de données avec des méthodes de
services Web REST Apex | 301
Exposition de données avec des méthodes de services Web REST Apex
L'invocation d'une méthode de service Web REST Apex personnalisée utilise toujours le contexte système. Par conséquent,
les identifiants de l'utilisateur actif ne sont pas utilisés, et tout utilisateur ayant accès à ces méthodes peut exploiter toute leur
puissance, quelles que soient les autorisations, la sécurité au niveau du champ ou les règles de partage. Les développeurs qui
exposent des méthodes en utilisant les annotations REST Apex doivent par conséquent s'assurer de ne pas révéler
accidentellement des données confidentielles.
ATTENTION: Les méthodes de classe Apex exposées via l'API REST Apex n'imposent pas les autorisations d'objet
et la sécurité au niveau du champ par défaut. Nous recommandons d'utiliser l'objet approprié ou les méthodes field
describe result afin de vérifier le niveau d'accès de l'utilisateur actif sur les objets et les champs auxquels la méthode
d'API REST Apex a accès. Reportez-vous à Schema.DescribeSObjectResult et à Schema.DescribeFieldResult.
De plus, les règles de partage (accès au niveau de l'enregistrement) sont appliquées uniquement lors de la déclaration
d'une classe avec le mot clé with sharing. Cette exigence s'applique à toutes les classes Apex, y compris aux classes
exposées via l'API REST Apex. Pour appliquer des règles de partage pour des méthodes d'API REST Apex, déclarez
la classe qui contient ces méthodes avec le mot clé with sharing. Reportez-vous à Utilisation des mots clés with
sharing ou without sharing.
Exemples de code REST Apex
Ces exemples de code montrent comment exposer des classes et des méthodes Apex via l'architecture REST, et comment
appeler ces ressources à partir d'un client.
•
•
Exemple de code de base REST Apex : Présente un exemple de classe REST Apex avec trois méthodes que vous pouvez
appeler pour supprimer, obtenir et mettre à jour un enregistrement.
Exemple de code REST Apex utilisant RestRequest : Présente un exemple de classe REST Apex qui ajoute une pièce
jointe à un enregistrement en utilisant l'objet RestRequest.
Exemple de code de base REST Apex
Cet exemple montre comment mettre en oeuvre une simple API REST dans Apex qui traite trois méthodes de requête HTTP
différentes. Pour plus d'informations sur l'authentification avec cURL, reportez-vous à la section Quick Start du guide REST
API Developer's Guide.
1. Créez une classe Apex dans votre instance, en cliquant sur Votre nom > Configuration > Développer > Classes Apex >
Nouveau, puis ajoutez ce code à votre nouvelle classe :
@RestResource(urlMapping='/Account/*')
global with sharing class MyRestResource {
@HttpDelete
global static void doDelete() {
RestRequest req = RestContext.request;
Exposition de classes Apex en tant que services Web REST
salesforce | Exemple de code de base REST Apex | 302
RestResponse res = RestContext.response;
String accountId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
Account account = [SELECT Id FROM Account WHERE Id = :accountId];
delete account;
}
@HttpGet
global static Account doGet() {
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
String accountId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
Account result = [SELECT Id, Name, Phone, Website FROM Account WHERE Id =
:accountId];
return result;
}
@HttpPost
global static String doPost(String name,
String phone, String website) {
Account account = new Account();
account.Name = name;
account.phone = phone;
account.website = website;
insert account;
return account.Id;
}
}
2. Pour appeler la méthode doGet à partir d'un client, ouvrez une fenêtre de ligne de commande, puis exécutez la commande
cURL suivante pour récupérer un compte par ID :
curl -H "Authorization: Bearer sessionId"
"https://instance.salesforce.com/services/apexrest/Account/accountId"
•
•
•
Remplacez sessionId par l'élément <sessionId> que vous avez noté dans la réponse de connexion.
Remplacez instance par votre élément <serverUrl>.
Remplacez accountId par l'ID d'un compte existant dans votre organisation.
Exposition de classes Apex en tant que services Web REST
salesforce | Exemple de code de base REST Apex | 303
Après avoir appelé la méthodedoGet, Salesforce renvoie une réponse JSON avec des données, telles que :
{
"attributes" :
{
"type" : "Account",
"url" : "/services/data/v22.0/sobjects/Account/accountId"
},
"Id" : "accountId",
"Name" : "Acme"
}
Remarque: Les exemples cURL de cette section n'utilisent pas de classe Apex dans un espace de noms, par
conséquent l'URL ne contient pas d'espace de noms.
3. Créez un fichier appelé compte.txt pour inclure les données du compte que vous allez créer à l'étape suivante.
{
"name" : "Wingo Ducks",
"phone" : "707-555-1234",
"website" : "www.wingo.ca.us"
}
4. En utilisant une fenêtre de ligne de commande, exécutez la commande cURL ci-dessous pour créer un compte :
curl -H "Authorization: Bearer sessionId" -H "Content-Type: application/json" -d
@compte.txt "https://instance.salesforce.com/services/apexrest/Account/"
Une fois la méthode doPost appelée, Salesforce renvoie une réponse avec des données, telles que :
"accountId"
L'élément accountId est l'ID du compte que vous venez de créer avec la requête POST.
5. En utilisant une fenêtre de ligne de commande, exécutez la commande cURL ci-dessous pour supprimer un compte en
spécifiant l'ID :
curl —X DELETE —H "Authorization: Bearer sessionId"
"https://instance.salesforce.com/services/apexrest/Account/accountId"
Voir aussi :
Annotations REST Apex
Exposition de classes Apex en tant que services Web REST
salesforce | Exemple de code REST Apex utilisant
RestRequest | 304
Exemple de code REST Apex utilisant RestRequest
L'exemple suivant montre comment ajouter une pièce jointe à une requête en utilisant l'objet RestRequest. Pour plus
d'informations sur l'authentification avec cURL, reportez-vous à la section Quick Start du guide REST API Developer's Guide.
Dans ce code, les données du fichier binaire sont stockées dans l'objet RestRequest et la classe du service Apex accède aux
données binaires dans l'objet RestRequest.
1. Créez une classe Apex dans votre instance, en cliquant sur Votre nom > Configuration > Développer > Classes Apex.
Cliquez sur Nouveau, puis ajoutez le code suivant à votre nouvelle classe :
@RestResource(urlMapping='/CaseManagement/v1/*')
global with sharing class CaseMgmtService
{
@HttpPost
global static String attachPic(){
RestRequest req = RestContext.request;
RestResponse res = Restcontext.response;
Id caseId = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
Blob picture = req.requestBody;
Attachment a = new Attachment (ParentId = caseId,
Body = picture,
ContentType = 'image/jpg',
Name = 'VehiclePicture');
insert a;
return a.Id;
}
}
2. Ouvrez une fenêtre de ligne de commande, puis exécutez la commande cURL suivante pour charger la pièce jointe dans
une requête :
curl -H "Authorization: Bearer sessionId" -H "X-PrettyPrint: 1" -H "Content-Type:
image/jpeg" --data-binary @file
"https://instance.salesforce.com/services/apexrest/CaseManagement/v1/caseId"
•
•
•
Remplacez sessionId par l'élément <sessionId> que vous avez noté dans la réponse de connexion.
Remplacez instance par votre élément <serverUrl>.
Remplacez caseId par l'ID de la requête à laquelle vous souhaitez ajouter la pièce jointe.
Exposition de classes Apex en tant que services Web REST
•
salesforce | Exemple de code REST Apex utilisant
RestRequest | 305
Remplacez file par le chemin et le nom du fichier que vous souhaitez joindre.
Votre commande doit se présenter comme suit (avec votre ID de session à la place de sessionId) :
curl -H "Authorization: Bearer sessionId"
-H "X-PrettyPrint: 1" -H "Content-Type: image/jpeg" --data-binary
@c:\test\vehiclephoto1.jpg
"https://na1.salesforce.com/services/apexrest/CaseManagement/v1/500D0000003aCts"
Remarque: Les exemples cURL de cette section n'utilisent pas de classe Apex dans un espace de noms, par
conséquent l'URL ne contient pas d'espace de noms.
La classe Apex renvoie une réponse JSON qui contient l'ID de la pièce jointe, telle que :
"00PD0000001y7BfMAI"
3. Pour vérifier que la pièce jointe et l'image ont été ajoutées à la requête, accédez à Requêtes, puis sélectionnez la vue Toutes
les requêtes ouvertes. Cliquez sur la requête, puis naviguez jusqu'à la liste associée Pièces jointes. La pièce jointe que vous
venez de créer doit être indiquée.
Chapitre 12
Invocation d'appels en utilisant le langage Apex
Sujets :
•
•
•
•
•
Ajout des paramètres de site distant
Services SOAP : Définition d'une
classe à partir d'un document WSDL
Invocation d'appels HTTP
Utilisation de certificats
Limitations des appels
Un appel Apex permet d'intégrer étroitement votre Apex à un service externe en
passant un appel à un service Web externe ou en envoyant une demande HTTP
via un code Apex, puis en recevant la réponse. Le langage Apex fournit
l'intégration avec les services Web qui utilisent SOAP et WSDL, ou des services
HTTP (services RESTful).
Remarque: Pour qu'un appel Apex puisse appeler un site externe, ce
site doit être enregistré dans la page Paramètres de site distant, sinon
l'appel échoue. Salesforce empêche les appels à partir d'adresses réseau
non autorisées.
Pour plus d'informations sur les types d'appel, reportez-vous à :
•
•
Services SOAP : Définition d'une classe à partir d'un document WSDL à la
page 307
Invocation d'appels HTTP à la page 322
Conseil: Les appels permettent au code Apex d'invoquer des services
Web externes ou HTTP. Les services Web Apex permettent à une
application externe d'invoquer des méthodes Apex via des services Web.
Invocation d'appels en utilisant le langage Apex
salesforce | Ajout des paramètres de site distant | 307
Ajout des paramètres de site distant
Pour qu'un appel Apex puisse appeler un site externe, ce site doit être enregistré dans la page Paramètres de site distant, sinon
l'appel échoue. Salesforce empêche les appels à partir d'adresses réseau non autorisées.
Pour ajouter un paramètre de site distant :
1.
2.
3.
4.
5.
6.
Cliquez sur Votre nom > Configuration > Contrôles de sécurité > Paramètres de site distant.
Cliquez sur Nouveau site distant.
Saisissez un terme descriptif dans Nom du site distant.
Saisissez l'URL du site distant.
Vous pouvez également saisir une description du site.
Cliquez sur Enregistrer.
Services SOAP : Définition d'une classe à partir d'un document WSDL
Des classes peuvent être générées automatiquement à partir d'un document WSDL stocké sur un disque dur local ou sur le
réseau. La création d'une classe à l'aide d'un document WSDL permet aux développeurs de passer des appels vers le service Web
externe dans leur code Apex.
Remarque: Utilisez la Messagerie sortante pour gérer les solutions d'intégration, si possible. Utilisez les appels à des
services Web tiers seulement si nécessaire.
Pour générer une classe Apex à partir d'un document WSDL :
1. Dans l'application, cliquez sur Votre nom > Configuration > Développer > Classes Apex.
2. Cliquez sur Générer à partir du WSDL.
3. Cliquez sur Parcourir pour accéder à un document WSDL situé sur votre disque dur local ou sur le réseau, ou saisissez le
chemin d'accès complet. Ce document WSDL est la base de la classe Apex que vous créez.
Remarque:
Le document WSDL que vous spécifiez peut contenir un emplacement de point de destination SOAP référençant
un port de sortie.
Pour des raisons de sécurité, Salesforce limite les ports de sortie que vous pouvez spécifier à l'un des ports suivants
:
•
•
•
80 : ce port accepte uniquement les connexions HTTP.
443 : ce port accepte uniquement les connexions HTTPS.
1024 à 66535 (inclus) : Ces ports acceptent les connexions HTTP ou HTTPS.
4. Cliquez sur Analyser le document WSDL pour vérifier le contenu du document WSDL. L'application génère un nom
de classe par défaut pour chaque espace de noms dans le document WSDL et signale les erreurs éventuelles. L'analyse
échoue si le WSDL contient des types ou des constructions de schéma non prises en charge par les classes Apex, ou si les
classes résultantes dépassent la limite de 1 million de caractères pour des classes Apex. Par exemple, le WSDL de l'API
SOAP de Salesforce ne peut pas être analysé.
Invocation d'appels en utilisant le langage Apex
salesforce | Invocation d'un service externe | 308
5. Modifiez les noms de classe, si nécessaire. Vous pouvez enregistrer plusieurs espaces de noms WSDL dans une seule classe
en utilisant le même nom de classe pour chaque espace de noms, néanmoins les classes Apex ne peuvent pas dépasser 1
million de caractères au total.
6. Cliquez sur GénérerApex. La dernière page de l'assistant indique les classes dont la génération a réussi, ainsi que les erreurs
provenant d'autres classes. La page fournit également un lien qui permet d'afficher le code généré avec succès.
La classe Apex générée avec succès comprend des classes stub et type permettant d'appeler le service Web tiers représenté par
le document WSDL. Ces classes permettent d'appeler le service Web externe à partir du code Apex.
Notez les points suivants sur le code Apex généré :
•
•
•
Si un document WSDL contient un mot réservé Apex, le suffixe _x est ajouté à ce mot lors de la génération de la classe
Apex. Par exemple, limit dans un document WSDL est converti en limit_x dans la classe Apex générée. Reportez-vous
à Mots clés réservés. Pour plus d'informations sur la gestion des caractères dans des noms d'élément d'un document WSDL
non pris en charge dans des noms de variable Apex, reportez-vous à Considérations sur l'utilisation de documents WSDL.
Si une opération dans le WSDL a un message sortant contenant plusieurs éléments, l'Apex généré incorpore les éléments
à une classe interne. La méthode Apex qui représente l'opération WSDL renvoie la classe interne au lieu des éléments
individuels.
Comme les points (.) ne sont pas autorisés dans des noms de classe Apex, les points dans des noms WSDL utilisés pour
générer des classes Apex sont remplacés par des traits de soulignement (_) dans le code Apex généré.
Après avoir généré une classe à partir du document WSDL, vous pouvez invoquer le service externe référencé par le WSDL.
Remarque: Avant de pouvoir utiliser les exemples dans le reste de cette section, vous devez copier la classe Apex
docSampleClass dans Compréhension du code généré, puis l'ajouter à votre organisation.
Invocation d'un service externe
Pour invoquer un service externe après avoir utilisé son document WSDL afin de générer une classe Apex, créez une instance
du stub dans votre code Apex, puis appelez les méthodes. Par exemple, pour invoquer le service de référence d'adresse IP
StrikeIron à partir du code Apex, vous pouvez écrire un code similaire à :
// Create the stub
strikeironIplookup.DNSSoap dns = new strikeironIplookup.DNSSoap();
// Set up the license header
dns.LicenseInfo = new strikeiron.LicenseInfo();
dns.LicenseInfo.RegisteredUser = new strikeiron.RegisteredUser();
dns.LicenseInfo.RegisteredUser.UserID = '[email protected]';
dns.LicenseInfo.RegisteredUser.Password = 'your-password';
// Make the Web service call
strikeironIplookup.DNSInfo info = dns.DNSLookup('www.myname.com');
Invocation d'appels en utilisant le langage Apex
salesforce | Prise en charge d'en-tête HTTP | 309
Prise en charge d'en-tête HTTP
Vous pouvez définir les en-têtes HTTP dans un appel de services Web. Par exemple, vous pouvez utiliser cette fonctionnalité
pour définir la valeur d'un cookie dans un en-tête d'autorisation. Pour définir des en-têtes HTTP, ajoutez
inputHttpHeaders_x et outputHttpHeaders_x au stub.
Remarque: Dans l'API versions 16.0 et supérieures, les réponses HTTP à des appels sont toujours des codées en
UTF-8, quel que soit l'en-tête Content-Type. Dans l'API versions 17.0 et supérieure, les réponses HTTP sont
décodées en utilisant le codage spécifié dans l'en-tête Content-Type.
Les exemples suivants fonctionnent avec l'exemple de fichier WSDL dans Compréhension du code généré à la page 313:
Envoi d'en-têtes HTTP dans un appel de service Web
docSample.DocSamplePort stub = new docSample.DocSamplePort();
stub.inputHttpHeaders_x = new Map<String, String>();
//Setting a basic authentication header
stub.inputHttpHeaders_x.put('Authorization', 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==');
//Setting a cookie header
stub.inputHttpHeaders_x.put('Cookie', 'name=value');
//Setting a custom HTTP header
stub.inputHttpHeaders_x.put('myHeader', 'myValue');
String input = 'This is the input string';
String output = stub.EchoString(input);
Si une valeur est spécifiée pour inputHttpHeaders_x, elle remplace l'ensemble d'en-têtes standard.
Accès à des en-têtes de réponse HTTP à partir d'une réponse d'appel de service Web
docSample.DocSamplePort stub = new docSample.DocSamplePort();
stub.outputHttpHeaders_x = new Map<String, String>();
String input = 'This is the input string';
String output = stub.EchoString(input);
Invocation d'appels en utilisant le langage Apex
salesforce | Fonctionnalités WSDL prises en charge | 310
//Getting cookie header
String cookie = stub.outputHttpHeaders_x.get('Set-Cookie');
//Getting custom header
String myHeader = stub.outputHttpHeaders_x.get('My-Header');
La valeur de outputHttpHeaders_x est nulle par défaut. Vous devez définir outputHttpHeaders_x avant d'accéder au
contenu des en-têtes dans la réponse.
Fonctionnalités WSDL prises en charge
Le langage Apex prend en charge le style de document WSDL littéral encapsulé, ainsi que les types de données primitifs et
intégrés suivants :
Type de schéma
Type Apex
xsd:anyURI
String
xsd:boolean
Boolean
xsd:date
Date
xsd:dateTime
Datetime
xsd:double
Double
xsd:float
Double
xsd:int
Integer
xsd:integer
Integer
xsd:language
String
xsd:long
Long
xsd:Name
String
xsd:NCName
String
xsd:nonNegativeInteger
Integer
xsd:NMTOKEN
String
xsd:NMTOKENS
String
xsd:normalizedString
String
xsd:NOTATION
String
xsd:positiveInteger
Integer
xsd:QName
String
xsd:short
Integer
Invocation d'appels en utilisant le langage Apex
Type de schéma
Type Apex
xsd:string
String
xsd:time
Datetime
xsd:token
String
xsd:unsignedInt
Integer
xsd:unsignedLong
Long
xsd:unsignedShort
Integer
salesforce | Fonctionnalités WSDL prises en charge | 311
Remarque: Le type de données Salesforce anyType n'est pas pris en charge dans les WSDL utilisés pour générer un
code Apex enregistré en utilisant l'API versions 15.0 et supérieures. Pour un code enregistrer en utilisant l'API versions
14.0 et supérieures, anyType est mappé avec String.
Le langage Apex prend également en charge les constructions de schéma suivantes :
•
•
•
•
•
xsd:all, dans le code Apex enregistré en utilisant l'API versions 15.0 et supérieures
xsd:annotation, dans le code Apex enregistré en utilisant l'API versions 15.0 et supérieures
xsd:attribute, dans le code Apex enregistré en utilisant l'API versions 15.0 et supérieures
xsd:choice, dans le code Apex enregistré en utilisant l'API versions 15.0 et supérieures
xsd:element. Dans le code Apex enregistré en utilisant l'API versions 15.0 et supérieures, l'attribut ref est également
pris en charge avec des restrictions suivantes :
◊ Vous ne pouvez pas appeler un ref dans un espace de noms différent.
◊ Un élément global ne peut pas utiliser ref.
◊ Si un élément contient ref, il ne peut pas non plus contenir name ou type.
•
xsd:sequence
Les types de données suivants sont pris en charge uniquement lorsqu'ils sont utilisé en tant qu'appels entrants, c.-à-d. lorsqu'un
service Web externe appel une méthode de service Web Apex. Ces types de données ne sont pas pris en charge en tant qu'appels
sortants, c.-à-d. lorsqu'une méthode de service Web Apex appelle un service Web externe.
•
•
•
blob
decimal
enum
Le langage Apex ne prend en charge aucun autre type, construction ou service WSDL, comprenant :
•
•
•
Les RPC/services encodés
Les fichiers WSDL avec plusieurs portTypes, plusieurs services ou plusieurs liaisons
Les fichiers WSDL qui importent des schémas externes. Par exemple, le fragment WSDL suivant importe un schéma
externe, qui n'est pas prise en charge :
<wsdl:types>
<xsd:schema
elementFormDefault="qualified"
Invocation d'appels en utilisant le langage Apex
salesforce | Fonctionnalités WSDL prises en charge | 312
targetNamespace="http://s3.amazonaws.com/doc/2006-03-01/">
<xsd:include schemaLocation="AmazonS3.xsd"/>
</xsd:schema>
</wsdl:types>
Cependant, une importation dans le même schéma est prise en charge. Dans l'exemple suivant, le WSDL est collé dans
le WSDL que vous convertissez :
<wsdl:types>
<xsd:schema
xmlns:tns="http://s3.amazonaws.com/doc/2006-03-01/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://s3.amazonaws.com/doc/2006-03-01/">
<xsd:element name="CreateBucket">
<xsd:complexType>
<xsd:sequence>
[...]
</xsd:schema>
</wsdl:types>
•
•
•
Tout type de schéma non documenté dans le tableau précédent
Les WSDL qui dépassent la taille limite, y compris les WSDL Salesforce
Les WSDL qui n'utilisent pas un style de document littéral encapsulé. L'extrait de WSDL suivant n'utilise pas de style de
document littéral encapsulé et génère une erreur « complexType introuvable » à l'importation.
<wsdl:types>
<xsd:schema targetNamespace="http://test.org/AccountPollInterface/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="SFDCPollAccountsResponse" type="tns:SFDCPollResponse"/>
<xsd:simpleType name="SFDCPollResponse">
<xsd:restriction base="xsd:string" />
</xsd:simpleType>
</xsd:schema>
</wsdl:types>
Invocation d'appels en utilisant le langage Apex
salesforce | Compréhension du code généré | 313
Cette version modifiée encapsule l'élément simpleType en tant que complexType qui contient une séquence d'éléments.
Elle suit le style de document littéral et est prise en charge.
<wsdl:types>
<xsd:schema targetNamespace="http://test.org/AccountPollInterface/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="SFDCPollAccountsResponse" type="tns:SFDCPollResponse" />
<xsd:complexType name="SFDCPollResponse">
<xsd:sequence>
<xsd:element name="SFDCOutput" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
Compréhension du code généré
L'exemple suivant montre la création d'une classe Apex à partir de document WSDL. La classe Apex est automatiquement
générée lorsque vous importez le WSDL. Le code suivant montre un exemple de document WSDL :
<wsdl:definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns="http://doc.sample.com/docSample"
targetNamespace="http://doc.sample.com/docSample"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<!-- Above, the schema targetNamespace maps to the Apex class name. -->
<!-- Below, the type definitions for the parameters are listed.
Each complexType and simpleType parameteris mapped to an Apex class inside the parent
class for the WSDL. Then, each element in the complexType is mapped to a public field
inside the class. -->
<wsdl:types>
Invocation d'appels en utilisant le langage Apex
salesforce | Compréhension du code généré | 314
<s:schema elementFormDefault="qualified"
targetNamespace="http://doc.sample.com/docSample">
<s:element name="EchoString">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="input" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="EchoStringResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="EchoStringResult"
type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<!--The stub below defines operations. -->
<wsdl:message name="EchoStringSoapIn">
<wsdl:part name="parameters" element="tns:EchoString" />
</wsdl:message>
<wsdl:message name="EchoStringSoapOut">
<wsdl:part name="parameters" element="tns:EchoStringResponse" />
</wsdl:message>
<wsdl:portType name="DocSamplePortType">
<wsdl:operation name="EchoString">
<wsdl:input message="tns:EchoStringSoapIn" />
<wsdl:output message="tns:EchoStringSoapOut" />
</wsdl:operation>
</wsdl:portType>
Invocation d'appels en utilisant le langage Apex
salesforce | Compréhension du code généré | 315
<!--The code below defines how the types map to SOAP. -->
<wsdl:binding name="DocSampleBinding" type="tns:DocSamplePortType">
<wsdl:operation name="EchoString">
<soap:operation soapAction="urn:dotnet.callouttest.soap.sforce.com/EchoString"
style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<!-- Finally, the code below defines the endpoint, which maps to the endpoint in the class
-->
<wsdl:service name="DocSample">
<wsdl:port name="DocSamplePort" binding="tns:DocSampleBinding">
<soap:address location="http://YourServer/YourService" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
À partir de ce document WSDL, la classe Apex suivante est automatiquement générée. Le nom de classe docSample est
spécifié lors de l'importation du WSDL.
//Generated by wsdl2apex
public class docSample {
public class EchoStringResponse_element {
Invocation d'appels en utilisant le langage Apex
salesforce | Compréhension du code généré | 316
public String EchoStringResult;
private String[] EchoStringResult_type_info = new String[]{
'EchoStringResult',
'http://www.w3.org/2001/XMLSchema',
'string','0','1','false'};
private String[] apex_schema_type_info = new String[]{
'http://doc.sample.com/docSample',
'true'};
private String[] field_order_type_info = new String[]{
'EchoStringResult'};
}
public class DocSamplePort {
public String endpoint_x = 'http://YourServer/YourService';
private String[] ns_map_type_info = new String[]{
'http://doc.sample.com/docSample',
'docSample'};
public String EchoString(String input) {
docSample.EchoString_element request_x =
new docSample.EchoString_element();
docSample.EchoStringResponse_element response_x;
request_x.input = input;
Map<String, docSample.EchoStringResponse_element> response_map_x =
new Map<String, docSample.EchoStringResponse_element>();
response_map_x.put('response_x', response_x);
WebServiceCallout.invoke(
Invocation d'appels en utilisant le langage Apex
salesforce | Compréhension du code généré | 317
this,
request_x,
response_map_x,
new String[]{endpoint_x,
'urn:dotnet.callouttest.soap.sforce.com/EchoString',
'http://doc.sample.com/docSample',
'EchoString',
'http://doc.sample.com/docSample',
'EchoStringResponse',
'docSample.EchoStringResponse_element'}
);
response_x = response_map_x.get('response_x');
return response_x.EchoStringResult;
}
}
public class EchoString_element {
public String input;
private String[] input_type_info = new String[]{
'input',
'http://www.w3.org/2001/XMLSchema',
'string','0','1','false'};
private String[] apex_schema_type_info = new String[]{
'http://doc.sample.com/docSample',
'true'};
private String[] field_order_type_info = new String[]{'input'};
}
}
Notez les mappages suivants dans le document WSDL d'origine :
•
•
•
•
L'espace de noms cible WSDL est mappé avec le nom de la classe Apex.
Chaque type complexe devient une classe. Chaque élément dans le type est un champ public dans la classe.
Le nom du port WSDL est mappé avec la classe stub.
Chaque opération dans le WSDL est mappée avec une méthode publique.
Invocation d'appels en utilisant le langage Apex
salesforce | Test des appels de service Web | 318
La classe générée ci-dessus peut être utilisée pour invoquer des services Web externes. Le code suivant montre comment appeler
la méthode echoString dans le serveur externe :
docSample.DocSamplePort stub = new docSample.DocSamplePort();
String input = 'This is the input string';
String output = stub.EchoString(input);
Test des appels de service Web
Le code généré est enregistré en tant que classe Apex contenant les méthodes que vous pouvez invoquer pour appeler le service
Web. Pour déployer ou encapsuler cette classe Apex et un autre code qui l'accompagne, 75 % du code doit avoir une couverture
de test, y compris les méthodes dans la classe générée. Par défaut, les méthodes de test ne prennent pas en charge les appels
de services Web, et les tests qui effectuent des appels de service Web sont ignorés. Pour empêcher les tests d'être ignorés et
augmenter la couverture de code, le langage Apex fournit l'interface intégrée WebServiceMock et la méthode Test.setMock
que vous pouvez utiliser pour recevoir des réponses fictives dans une méthode de test.
Spécification d'une réponse fictive pour tester les appels de service Web
Lorsque vous créez une classe Apex à partir d'un WSDL, les méthodes de la classe automatiquement générée appellent
WebServiceCallout.invoke, qui effectue l'appel au service externe. Lors du test de ces méthodes, vous pouvez instruire
l'exécution du code Apex pour générer une réponse fictive dès que WebServiceCallout.invoke est appelé. Pour cela,
mettez en oeuvre l'interface WebServiceMock et spécifier une réponse fictive que l'exécution du code Apex doit envoyer. Les
étapes sont présentées ci-dessous.
Commencer par mettre en oeuvre l'interface WebServiceMock et spécifier la réponse fictive dans la méthode doInvoke.
global class YourWebServiceMockImpl implements WebServiceMock {
global void doInvoke(
Object stub,
Object request,
Map<String, Object> response,
String endpoint,
String soapAction,
String requestName,
String responseNS,
String responseName,
String responseType) {
// Create response element from the autogenerated class.
// Populate response element.
// Add response element to the response parameter, as follows:
response.put('response_x', responseElement);
Invocation d'appels en utilisant le langage Apex
salesforce | Test des appels de service Web | 319
}
}
Remarque:
La classe qui met en oeuvre l'interface WebServiceMock peut être globale ou publique.
Vous pouvez annoter cette classe avec @isTest, car elle sera utilisée uniquement dans un contexte de test. Vous
pouvez ainsi l'exclure de la taille limite de code de 3 Mo d'une organisation.
•
•
Une fois les valeurs de la réponse fictive spécifiées, instruisez le code Apex d'envoyer cette réponse à l'exécution en appelant
Test.setMock dans votre méthode de test. Passez WebServiceMock.class pour le premier argument, puis passez une
nouvelle instance de votre mise en oeuvre d'interface de WebServiceMock pour le deuxième argument, comme suit :
Test.setMock(WebServiceMock.class, new YourWebServiceMockImpl());
À ce stade, si un appel de service Web est invoqué dans un contexte de test, l'appel n'est pas effectué et vous recevez la réponse
fictive spécifiée dans la mise en oeuvre de votre méthode doInvoke.
Remarque: Si le code effectué par l'appel est inclus dans un package géré, vous devez appeler Test.setMock à
partir d'une méthode de test dans le même package avec le même espace de noms pour feindre l'appel.
Cet exemple complet montre comment tester un appel de service Web. La mise en oeuvre de l'interface WebServiceMock
est répertoriée en premier. Cet exemple met en oeuvre la méthode doInvoke, qui renvoie la réponse que vous spécifiez. Dans
ce cas, l'élément de réponse de la classe automatiquement généré est créé et une valeur lui est attribuée. Ensuite, le paramètre
de réponse Map est renseigné avec la réponse fictive. Cet exemple est basé sur le WSDL répertorié dans Compréhension du
code généré. Importez ce WSDL, puis générez une classe appelée docSample avant d'enregistrer cette classe.
@isTest
global class WebServiceMockImpl implements WebServiceMock {
global void doInvoke(
Object stub,
Object request,
Map<String, Object> response,
String endpoint,
String soapAction,
String requestName,
String responseNS,
String responseName,
String responseType) {
docSample.EchoStringResponse_element respElement =
new docSample.EchoStringResponse_element();
respElement.EchoStringResult = 'Mock response';
Invocation d'appels en utilisant le langage Apex
salesforce | Test des appels de service Web | 320
response.put('response_x', respElement);
}
}
Cette méthode passe un appel de service Web.
public class WebSvcCallout {
public static String callEchoString(String input) {
docSample.DocSamplePort sample = new docSample.DocSamplePort();
sample.endpoint_x = 'http://api.salesforce.com/foo/bar';
// This invokes the EchoString method in the generated class
String echo = sample.EchoString(input);
return echo;
}
}
Cette classe de test contient la méthode de test qui définit le mode d'appel fictif. Elle appelle la méthode callEchoString
dans la classe précédente et vérifie qu'une réponse fictive est reçue.
@isTest
private class WebSvcCalloutTest {
@isTest static void testEchoString() {
// This causes a fake response to be generated
Test.setMock(WebServiceMock.class, new WebServiceMockImpl());
// Call the method that invokes a callout
String output = WebSvcCallout.callEchoString('Hello World!');
// Verify that a fake result is returned
System.assertEquals('Mock response', output);
}
}
Voir aussi :
Interface WebServiceMock
Invocation d'appels en utilisant le langage Apex
salesforce | Considérations sur l'utilisation de WSDL | 321
Considérations sur l'utilisation de WSDL
Notez les points suivants lors de la génération de classes Apex à partir d'un WSDL.
Mappage d'en-têtes
Les en-têtes définis dans un document WSDL deviennent des champs publics dans le stub de la classe générée. Ce
fonctionnement est similaire à AJAX Toolkit et à .NET.
Compréhension des événements à l'exécution
Les vérifications suivantes sont effectuées lorsque le code Apex passe un appel à un service externe.
•
•
•
•
•
Pour plus d'informations sur les limites d'expiration lors d'une requête HTTP ou d'un appel à des services Web, reportez-vous
à Limitations des appels à la page 325.
Les références circulaires dans les classes Apex ne sont pas autorisées.
Plusieurs connexions de rebouclage à des domaines Salesforce sont autorisées.
Pour autoriser l'accès à un point de terminaison, il doit être enregistré dans Votre nom > Configuration > Sécurité >
Paramètre du site distant.
Pour empêcher les connexions de base de données d'être attaquées, aucune transaction ne peut être ouverte.
Compréhension des caractères non pris en charge dans les noms de variables
Un fichier WSDL peut inclure un nom d'élément qui n'est pas autorisé dans un nom de variable Apex. Les règles suivantes
s'appliquent lors de la génération de noms de variables Apex à partir d'un fichier WSDL :
•
•
•
•
•
Si le premier caractère d'un nom de variable n'est pas alphabétique, le préfixe x est ajouté au nom de la variable Apex
générée.
Si le dernier caractère d'un nom de variable n'est pas autorisé dans un nom de variable Apex, le suffixe x est ajouté au nom
de la variable Apex générée.
Si un nom d'élément contient un caractère non autorisé dans un nom de variable Apex, le caractère est remplacé par un
trait de soulignement (_).
Si un nom d'élément contient deux caractères successifs non autorisés dans un nom de variable Apex, le premier caractère
est remplacé par un trait de soulignement (_) et le deuxième par un caractère x. Cela évite de générer un nom de variable
avec deux traits de soulignements successifs, ce qui est interdit dans Apex.
Supposons que vous avez une opération contenant deux paramètres, a_ et a_x. Le code Apex généré contient deux variables,
les deux nommées a_x. La classe n'est pas compilée. Vous devez modifier le code Apex manuellement et changer l'un des
noms de variable.
Débogage de classes générées à partir de fichiers WSDL
Salesforce teste le code avec l'API SOAP, .NET et Axis. Si vous utilisez d'autres outils, vous risquez de rencontrer des problèmes.
Vous pouvez utiliser l'en-tête de débogage pour renvoyer le fichier XML dans les messages de demande et de réponse SOAP
afin de faciliter le diagnostic des problèmes. Pour plus d'informations, reportez-vous à API SOAP et en-têtes SOAP pour
Apex à la page 788.
Invocation d'appels en utilisant le langage Apex
salesforce | Invocation d'appels HTTP | 322
Invocation d'appels HTTP
Le langage Apex fournit plusieurs classes intégrées pour travailler avec des services HTTP et créer des requêtes HTTP telles
que GET, POST, PUT et DELETE.
Vous pouvez utiliser ces classes HTTP pour l'intégration à des services basés sur REST. Elles permettent également d'intégrer
des services Web basés sur SOAP en tant qu'option alternative pour générer un code Apex à partir d'un WSDL. En utilisant
les classes HTTP au lieu de démarrer un WSDL, vous prenez plus de responsabilité dans la gestion de la construction du
message SOAP pour la demande et la réponse.
Pour plus d'informations et d'exemples, reportez-vous à Classes de services HTTP (RESTful). En outre, les outils Force.com
Toolkit for Google Data APIs utilise abondamment les appels HTTP.
Utilisation de certificats
Vous pouvez utiliser une authentification SSL bidirectionnelle en envoyant un certificat généré dans Salesforce ou signé par
une autorité de certification (CA) avec votre appel. Cela renforce la sécurité, car la cible de l'appel reçoit le certificat et peut
l'utiliser pour authentifier la demande avec son magasin de clés.
Pour activer l'authentification SSL bidirectionnelle pour un appel :
1. Générez un certificat.
2. Intégrez le certificat à votre code. Reportez-vous à Utilisation de certificats avec des services SOAP et à Utilisation de
certificats avec des requêtes HTTP.
3. Si vous vous connectez à un tiers et que vous utilisez un certificat auto-signé, partagez le certificat Salesforce avec ce tiers
pour lui permettre de l'ajouter à son magasin de clés. Si vous vous connectez à une autre application utilisée au sein de votre
organisation, configurez votre serveur Web ou d'applications pour demander un certificat client. Ce processus dépend du
type de serveur Web ou d'applications que vous utilisez. Pour consulter un exemple de configuration d'une authentification
SSL bidirectionnelle avec Apache Tomcat, reportez-vous à
wiki.developerforce.com/index.php/Making_Authenticated_Web_Service_Callouts_Using_Two-Way_SSL.
4. Configurez les paramètres de site distant pour l'appel. Pour qu'un appel Apex puisse appeler un site externe, ce site doit
être enregistré dans la page Paramètres de site distant, sinon l'appel échoue.
Génération de certificats
Vous pouvez utiliser un certificat auto-signé généré dans Salesforce ou un certificat signé par une autorité de certification
(CA). Pour générer un certificat pour un appel :
1. Accédez à Votre nom > Configuration > Contrôles de sécurité > Gestion des certificats et des clés.
2. Sélectionnez Créer un certificat auto-signé ou Créer un certificat signé par AC, en fonction du type de certificat accepté
par votre site Web externe. Une fois le certificat créé, vous ne pouvez pas modifier son type.
3. Saisissez une étiquette explicite pour le certificat Salesforce. Ce nom est essentiellement utilisé par les administrateurs pour
visualiser les certificats.
4. Saisissez le Nom unique. Ce nom est automatiquement renseigné en fonction de l'étiquette de certificat saisie. Ce nom
peut contenir uniquement des traits de soulignement et des caractères alphanumériques, et doit être unique dans votre
organisation. Il doit commencer par une lettre, ne pas inclure d’espace, ne pas se terminer pas un trait de soulignement et
Invocation d'appels en utilisant le langage Apex
salesforce | Utilisation de certificats avec des services
SOAP | 323
ne pas contenir deux traits de soulignement consécutifs. Utilisez le Nom unique pour référencer le certificat en utilisant
l'API des services Web Force.com ou Apex.
5. Sélectionnez une Taille de clé pour votre certificat et vos clés générés. Nous recommandons d'utiliser la clé par défaut
2048 pour des raisons de sécurité. La sélection de 2048 génère un certificat utilisant des clés 2048 bits, qui est valide
pendant deux ans. La sélection de 1024 génère un certificat utilisant des clés 1024 bits, qui est valide pendant un an.
Remarque: Une fois un certificat Salesforce enregistré, vous ne pouvez pas modifier la taille des clés.
6. Si vous créez un certificat signé par AC, vous devez également saisir les informations ci-dessous. Ces champs sont associés
pour générer un certificat unique.
Champ
Description
Nom usuel
Nom de domaine complet de la société qui demande le
certificat signé. Il se présente généralement sous la forme :
http://www.masociete.com.
Adresse e-mail
Adresse e-mail associée à ce certificat.
Société
Nom légal de votre société ou votre nom.
Département
Service de votre société qui utilise le certificat, tel que le
marketing ou la comptabilité.
Ville
Ville dans laquelle la société est implantée.
Région/Province
Région dans laquelle la société est implantée.
Code de pays
Code à deux lettres qui indique le pays dans lequel la société
est implantée. Pour la France, la valeur est FR.
7. Cliquez sur Enregistrer.
Une fois enregistré avec succès, un certificat Salesforce ainsi que les clés correspondantes sont automatiquement générés.
Après avoir créé un certificat signé par AC, vous devez le charger avant de pouvoir l'utiliser. Reportez-vous à « Chargement
de certificats signés par une autorité de certification (CA) » dans l'aide en ligne de Salesforce.
Utilisation de certificats avec des services SOAP
Après avoir généré un certificat dans Salesforce, vous pouvez l'utiliser afin de prendre en charge une authentification
bidirectionnelle pour un appel à un service Web SOAP.
Pour intégrer le certificat à votre code Apex :
1. Recevez le WSDL pour le service Web d'un tiers ou générez-le à partir de l'application à laquelle vous souhaitez vous
connecter.
2. Générez des classes Apex à partir du WSDL pour le service Web. Reportez-vous à Services SOAP : Définition d'une
classe à partir d'un document WSDL.
3. La classe Apex générée inclut une classe stub pour appeler le service Web tiers représenté par le document WSDL. Modifiez
les classes Apex, puis attribuez une valeur à une variable clientCertName_x dans une instance de la classe stub. La valeur
Invocation d'appels en utilisant le langage Apex
salesforce | Utilisation de certificats avec des requêtes
HTTP | 324
doit correspondre au Nom unique du certificat que vous générez dans Votre nom > Configuration > Contrôles de
sécurité > Gestion des certificats et des clés.
L'exemple ci-dessous illustre la dernière étape de la procédure précédente et fonctionne avec l'exemple de fichier WSDL de
la section Compréhension du code généré. Il suppose que vous avez déjà généré un certificat portant un Nom unique de
DocSampleCert.
docSample.DocSamplePort stub = new docSample.DocSamplePort();
stub.clientCertName_x = 'DocSampleCert';
String input = 'This is the input string';
String output = stub.EchoString(input);
Il existe un processus hérité permettant d'utiliser un certificat provenant d'un tiers pour votre organisation. Encodez votre clé
de certificat client en base64, puis attribuez-la à la variable clientCert_x de la classe stub. Par nature, ce processus est moins
sûr que l'utilisation d'un certificat Salesforce, car il ne suit pas les meilleures pratiques de sécurité relatives à la protection des
clés privées. Lorsque vous utilisez un certificat Salesforce, la clé privée n'est pas partagée hors de Salesforce.
Remarque: N'utilisez pas un certificat généré dans Votre nom > Configuration > Développer > API > Générer
Certificat client. Vous devez utiliser un certificat émis par un tiers pour votre organisation si vous suivez le processus
hérité.
L'exemple ci-dessous illustre le processus hérité et fonctionne avec l'exemple de fichier WSDL de la section Compréhension
du code généré à la page 313.
docSample.DocSamplePort stub = new docSample.DocSamplePort();
stub.clientCert_x =
'MIIGlgIBAzCCBlAGCSqGSIb3DQEHAaCCBkEEggY9MIIGOTCCAe4GCSqGSIb3DQEHAaCCAd8EggHb'+
'MIIB1zCCAdMGCyqGSIb3DQEMCgECoIIBgjCCAX4wKAYKKoZIhvcNAQwBAzAaBBSaUMlXnxjzpfdu'+
'6YFwZgJFMklDWFyvCnQeuZpN2E+Rb4rf9MkJ6FsmPDA9MCEwCQYFKw4DAhoFAAQU4ZKBfaXcN45w'+
'9hYm215CcA4n4d0EFJL8jr68wwKwFsVckbjyBz/zYHO6AgIEAA==';
// Password for the keystore
stub.clientCertPasswd_x = 'passwd';
String input = 'This is the input string';
String output = stub.EchoString(input);
Utilisation de certificats avec des requêtes HTTP
Après avoir généré un certificat dans Salesforce, vous pouvez l'utiliser afin de prendre en charge une authentification
bidirectionnelle pour un appel à une requête HTTP.
Invocation d'appels en utilisant le langage Apex
salesforce | Limitations des appels | 325
Pour intégrer le certificat à votre code Apex :
1. Générez un certificat. Notez le Nom unique du certificat.
2. Dans votre code Apex, utilisez la méthode setClientCertificateName de la classe HttpRequest. La valeur utilisée
pour l'argument de cette méthode doit correspondre au Nom unique du certificat que vous avez généré à l'étape précédente.
L'exemple ci-dessous illustre la dernière étape de la procédure précédente. Il suppose que vous avez déjà généré un certificat
portant un Nom unique de DocSampleCert.
HttpRequest req = new HttpRequest();
req.setClientCertificateName('DocSampleCert');
Limitations des appels
Les limitations suivantes s'appliquent lorsque le code Apex effectue un appel à une requête HTTP ou à des services Web.
L'appel de services Web peut être un appel d'API SOAP ou n'importe quel appel de service Web externe.
•
•
•
•
Une transaction Apex unique peut effectuer jusqu'à 10 appels à une requête HTTP ou un appel d'API.
L'expiration par défaut est de 10 secondes. Une expiration personnalisée peut être définie pour chaque appel. La valeur
minimale est 1 milliseconde et la valeur maximale est 120 secondes. Pour définir une expiration personnalisée pour des
appels de services Web ou HTTP, reportez-vous à l'exemple ci-dessous.
L'expiration cumulée maximale pour des appels effectués par une transaction Apex unique est de 120 secondes. Cette valeur
s'ajoute à tous les appels invoqués par la transaction Apex.
Vous ne pouvez pas effectuer un appel lorsque des opérations sont en attente dans la même transaction. Les éléments qui
génèrent des opérations en attente sont des instructions DML, un code Apex asynchrone (tel que des méthodes futures et
des tâches Apex par lot), un code Apex planifié ou l'envoi d'un e-mail. Vous pouvez effectuer des appels avant d'exécuter
ces types d'opération.
Définition d'expirations d'appels
L'exemple suivant définit une expiration personnalisée pour des appels de service Web. Il fonctionne avec l'exemple de fichier
WSDL et la classe DocSamplePort générée présentés dans Compréhension du code généré à la page 313. Définissez la valeur
d'expiration en millisecondes en attribuant une valeur à la variable timeout_x de la classe stub.
docSample.DocSamplePort stub = new docSample.DocSamplePort();
stub.timeout_x = 2000; // timeout in milliseconds
L'exemple suivant définit une expiration personnalisée pour des appels HTTP :
HttpRequest req = new HttpRequest();
req.setTimeout(2000); // timeout in milliseconds
Chapitre 13
Référence
Sujets :
La référence Apex présente des informations sur le langage Apex.
•
•
•
•
•
Opérations DML (langage de
manipulation de données) Apex
Méthodes et classes standard Apex
Classes Apex
Interfaces Apex
•
•
•
Opérations DML (langage de manipulation de données) : utilisées pour
manipuler des données dans la base de données
SiClasses et méthodes standard : disponibles pour des types de données
primitifs, des collections, des sObjects et d'autres parties du code Apex
Classes Apex : classes prédéfinies qui peuvent être utilisées
Interfaces Apex : interfaces que vous pouvez mettre en oeuvre
De plus, les méthodes et les objets API SOAP sont disponibles pour le langage
Apex. Reportez-vous à API SOAP et en-têtes SOAP pour Apex à la page 788
en annexe.
Référence
salesforce | Opérations DML (langage de manipulation de
données) Apex | 327
Opérations DML (langage de manipulation de données) Apex
Les opérations DML (langage de manipulation de données) permettent d'insérer, de mettre à jour, de supprimer et de restaurer
des données dans une base de données.
Vous pouvez exécuter des opérations à l'aide de deux formats différents :
Des instructions DML Apex, telles que :
•
insert SObject[]
Des méthodes de base de données DML Apex, telles que :
•
Database.SaveResult[] result = Database.Insert(SObject[])
La plupart des opérations DML sont disponibles dans les deux formats, mais certaines existent sous un seul format.
Les deux formats d'opération DML permettent de traiter différents types d'exception :
Utilisez des instructions DML pour renvoyer les erreurs qui se produisent durant un traitement DML en masse en tant
qu'exceptions Apex qui suspendent immédiatement le flux de contrôle (en utilisant des blocs try. . .catch). Ce
comportement est semblable au traitement des exceptions dans la plupart des langages de procédure de base de données.
Utilisez des méthodes de base de données DML pour autoriser le succès partiel d'une opération DML en masse. Si un
enregistrement échoue, le reste de l'opération DML peut réussir. Votre application peut ensuite inspecter les éléments
refusés et recommencer l'opération. Ce format permet d'écrire un code qui ne renvoie jamais d'erreur d'exception DML.
À la place, votre code peut utiliser le tableau de résultats approprié pour déterminer un succès ou un échec. Notez que les
méthodes de base de données DML incluent également une syntaxe qui prend en charge les exceptions renvoyées, de la
même façon que les instructions DML.
•
•
Les opérations DML Apex suivantes sont disponibles :
convertLead1
•
•
•
•
•
•
•
delete
insert
merge2
undelete
update
upsert
Contexte système et règles de partage
La plupart des opérations DML sont exécutées dans un contexte système, en ignorant les autorisations de l'utilisateur actif, la
sécurité au niveau du champ, les paramètres par défaut de l'organisation, la position dans la hiérarchie des rôles et les règles
de partage. Cependant lorsqu'une opération DML est appelée dans une classe définie avec les mots clés with sharing, les
règles de partage de l'utilisateur actif sont prises en compte. Pour plus d'informations, reportez-vous à Utilisation des mots
clés with sharing ou without sharing à la page 156.
1
2
convertLead est disponible uniquement en tant que méthode de base de données.
merge est disponible en tant qu'instruction DML Apex.
Référence
salesforce | Opération ConvertLead | 328
Troncature du champ String et version API
Les classes et les déclencheurs Apex sauvegardés (compilés) en utilisant l'API versions 15.0 et supérieures, génèrent une erreur
d'exécution si vous attribuez une valeur String trop longue pour le champ.
Opération ConvertLead
L'opération DML convertLead convertit une piste en compte et en contact, et (facultatif) en opportunité.
Remarque: convertLead est disponible uniquement en tant que méthode de base de données.
Syntaxe de la méthode de base de données
•
•
LeadConvertResult Database.convertLead(LeadConvert leadToConvert, Boolean opt_allOrNone)
LeadConvertResult[] Database.convertLead(LeadConvert[] leadsToConvert, Boolean opt_allOrNone)
Le paramètre facultatif opt_allOrNone indique si l'opération autorise le succès partiel. Si vous spécifiez false pour ce
paramètre et qu'un enregistrement échoue, le reste de l'opération DML peut réussir. Cette méthode renvoie un objet de résultat
qui permet de déterminer quels enregistrements ont réussi, quels enregistrements ont échoué, et pour quelles raisons.
Règles et consignes
Lors de la conversion de pistes, tenez compte des règles et des consignes suivantes :
•
Mappages de champs : le système mappe automatiquement les champs de piste standard avec des champs de compte, de
contact et d'opportunité standard. Votre administrateur Salesforce peut spécifier le mappage des champs de pistes
personnalisés avec des champs de compte, de contact et d'opportunité personnalisés. Pour plus d'informations sur les
mappages, reportez-vous à l'aide en ligne de Salesforce.
Si vous n'avez pas activé la validation et les déclencheurs à partir de la piste convertie, la conversion de piste échoue si les
données d'un champ de piste personnalisé ne sont pas prises en charge dans le champ de contact personnalisé correspondant.
Par exemple, si un champ de piste personnalisé est mappé avec un champ de liste de sélection de contact, la valeur de la
piste doit être explicitement définie en tant que valeur de liste de sélection de contact. Sinon, la piste n'est pas convertie.
Pour résoudre cette erreur, assurez-vous que les valeurs du champ sont déjà définies. Pour éviter cette erreur, nous
recommandons d'activer la validation et les déclencheurs à partir de la piste convertie dans les paramètres de piste de votre
organisation.
•
•
•
•
Champs de fusion : si des données sont fusionnées dans des objets de compte et de contact existants, seuls les champs vides
de l'objet cible sont remplacés, les données existantes (y compris les ID) ne sont pas remplacées. Il existe une exception si
vous définissez setOverwriteLeadSource dans l'objet LeadConvert sur true. Dans ce cas, le champ LeadSource de
l'objet de contact cible est remplacé par le contenu du champ LeadSource dans l'objet LeadConvert source.
Types d'enregistrement : si l'organisation utilise des types d'enregistrement, le type d'enregistrement par défaut du nouveau
propriétaire est attribué aux enregistrements créés pendant la conversion de pistes. Le type d'enregistrement par défaut de
l'utilisateur qui convertit la piste détermine les valeurs sources de la piste disponibles durant la conversion. Si les valeurs
sources de la piste souhaitées ne sont pas disponibles, ajoutez les valeurs au type d'enregistrement par défaut de l'utilisateur
qui convertit la piste. Pour plus d'informations sur les types d'enregistrement, reportez-vous à l'aide en ligne de Salesforce.
Valeurs de liste de sélection : le système associe des valeurs de liste de sélection par défaut au compte, au contact et à
l'opportunité lors du mappage de n'importe quel champ vide dans une liste de sélection de piste standard. Si votre organisation
utilise des types d'enregistrement, les valeurs vides sont remplacées par les valeurs de liste de sélection par défaut du nouveau
propriétaire de l'enregistrement.
Abonnements automatiques à un fil : lors de la conversion d'une liste en nouveau compte, contact et opportunité, le
propriétaire de la piste est désabonné du compte de la piste. Le propriétaire de la piste, le propriétaire des enregistrements
générés et les utilisateurs désabonnés de la piste ne sont pas automatiquement abonnés aux enregistrements générés, sauf
Référence
salesforce | Opération ConvertLead | 329
si les abonnements automatiques sont activés dans leurs paramètres de fil Chatter. Ils doivent avoir les abonnements
automatiques activés pour pouvoir afficher les modifications des enregistrements de compte, de contact et d'opportunité
dans leur fil d'actualité. Les utilisateurs doivent activer les abonnements automatiques en sélectionnant la case Suivre
automatiquement les enregistrements que je crée dans Votre nom > Configuration > Mes paramètres
Chatter > Mes fils pour s'abonner aux enregistrements qu'ils créent. Un utilisateur peut s'abonner à un enregistrement
pour pouvoir consulter les modifications apportées à un enregistrement dans le fil d'actualité de sa page d'accueil. Il peut
ainsi rester informé des modifications apportées aux enregistrements dans Salesforce.
Étapes de base de conversion des pistes
La conversion des pistes inclut les étapes de base suivantes :
1. Votre application détermine si les ID de la ou des pistes doivent être convertis.
2. En option, votre application peut déterminer l'ID du ou des comptes dans lesquels la piste doit être fusionnée. Votre
application peut utiliser une requête SOQL pour rechercher les comptes qui correspondent au nom de la piste, comme
dans l'exemple suivant :
SELECT Id, Name FROM Account WHERE Name='CompanyNameOfLeadBeingMerged'
3. En option, votre application peut déterminer l'ID du ou des contacts dans lesquels la piste doit être fusionnée. Votre
application peut utiliser une requête SOQL pour rechercher les contacts qui correspondent au nom de contact de la piste,
comme dans l'exemple suivant :
SELECT Id, Name FROM Contact WHERE FirstName='FirstName' AND LastName='LastName' AND
AccountId = '001...'
4. En option, l'application détermine si des opportunités doivent être créées à partir de pistes.
5. L'application interroge le tableau LeadSource pour obtenir toutes les options possibles de statut converti (SELECT ...
FROM LeadStatus WHERE IsConverted='1'), puis sélectionne la valeur pour le statut converti.
6. L'application appelle convertLead.
7. L'application itère le ou les résultats renvoyés et examine chaque objet LeadConvertResult afin de déterminer si la conversion
a réussi pour chaque piste.
8. En option, lors de la conversion de pistes appartenant à une file d'attente, le propriétaire doit être spécifié, car les comptes
et les contacts ne peuvent pas appartenir à une file d'attente. Même si vous spécifiez un compte ou un contact existant,
vous devez préciser le propriétaire.
Méthodes d'objet LeadConvert
La méthode de base de données convertLead accepte jusqu'à 100 objets LeadConvert. Un objet LeadConvert prend en
charge les méthodes suivantes :
Nom
Arguments
Type de
renvoi
Description
getAccountId
ID
Obtient l'ID du compte dans lequel la piste va être fusionnée.
getContactId
ID
Obtient l'ID du contact dans lequel la piste va être fusionnée.
getConvertedStatus
String
Obtient la valeur de statut d'une piste convertie.
getLeadID
ID
Obtient l'ID de la piste à convertir.
getOpportunityName
String
Obtient le nom de l'opportunité à créer.
Référence
Nom
salesforce | Opération ConvertLead | 330
Arguments
Type de
renvoi
Description
getOwnerID
ID
Obtient l'ID de la personne qui doit être propriétaire de tout
nouveau compte, contact ou opportunité créé.
isDoNotCreateOpportunity
Boolean
Indique si une opportunité est créée durant la conversion de
piste (false, par défaut) ou (true).
isOverWriteLeadSource
Boolean
Indique si le champ LeadSource dans l'objet Contact cible
est remplacé par le contenu du champ LeadSource dans l'objet
Piste source (true) ou (false, par défaut).
isSendNotificationEmail
Boolean
Indique si un e-mail de notification est envoyé au propriétaire
spécifié par setOwnerId (true) ou (false, par défaut).
setAccountId
ID ID
Void
Définit l'ID du compte dans lequel la piste va être fusionnée.
Cette valeur est requise uniquement lors de la mise à jour d'un
compte existant, y compris les comptes personnels. Sinon, si
setAccountID est spécifié, un compte est créé.
setContactId
ID ID
Void
Définit l'ID du contact dans lequel la piste est fusionnée (ce
contact doit être associé au compte spécifié avec
setAccountId, et setAccountId doit être spécifié). Cette
valeur est requise uniquement lors de la mise à jour d'un contact
existant.
Important: Si vous convertissez une piste en compte
personnel, ne spécifiez pas setContactId, qui
entraînerait une erreur. Spécifiez uniquement la
méthode setAccountId du compte personnel.
Si setContactID est spécifié, l'application crée un contact
qui est implicitement associé au compte. Le nom du contact et
les autres données existantes ne sont pas remplacées (sauf si
setOverwriteLeadSource est défini sur true, auquel cas
seul le champ LeadSource est remplacé).
setConvertedStatus
String Status Void
setDoNotCreateOpportunity Boolean
Void
CreateOpportunity
setLeadId
ID ID
Void
setOpportunityName
String OppName Void
Définit la valeur de statut d'une piste convertie. Ce champ est
obligatoire.
Spécifie la création ou non d'une opportunité durant la
conversion de piste. La valeur par défaut est false : des
opportunités sont créées par défaut. Définissez cet indicateur
sur true uniquement si vous ne souhaitez pas créer une
opportunité à partir de la piste.
Définit l'ID de la piste à convertir. Ce champ est obligatoire.
Définit le nom de l'opportunité à créer. Si aucun nom n'est
spécifié, cette valeur applique par défaut le nom de société de
la piste. La longueur maximale de ce champ est de 80 caractères.
Si setDoNotCreateOpportunity est true, aucune
Opportunité n'est créée et ce champ doit rester vide, sinon une
erreur est renvoyée.
Référence
Nom
salesforce | Opération ConvertLead | 331
Arguments
Type de
renvoi
setOverwriteLeadSource Boolean
Void
OverwriteLeadSource
setOwnerId
ID ID
setSendNotificationEmail Boolean
SendEmail
Description
Spécifie le remplacement ou non du champ LeadSource de
l'objet de contact cible par le contenu du champ LeadSource
de l'objet de piste source. La valeur par défaut est false, qui
indique de ne pas remplacer le champ. Si vous le définissez sur
true, vous devez également spécifier setContactId pour le
contact cible.
Void
Spécifie l'ID de la personne qui doit être propriétaire de tout
nouveau compte, contact ou opportunité créé. Si l'application
ne spécifie pas cette valeur, le propriétaire du nouvel objet est
le propriétaire de la piste. Cette méthode ne s'applique pas lors
d'une fusion avec des objets existants : si setOwnerId est
spécifié, le champ ownerId n'est pas remplacé dans un compte
ou contact existant.
Void
Spécifie l'envoi ou non d'un e-mail de notification au
propriétaire désigné par setOwnerId. La valeur par défaut est
false, qui indique de ne pas envoyer d'e-mail.
Objet LeadConvertResult
Un tableau d'objets LeadConvertResult est renvoyé avec la méthode de base de données convertLead. Chaque élément du
tableau LeadConvertResult correspond au tableau SObject transmis en tant que paramètre SObject[] dans la méthode de
base de données convertLead, c.-à-d. que le premier élément du tableau LeadConvertResult correspond au premier élément
transmis dans le tableau SObject, le deuxième élément correspond deuxième élément, etc. Si un seul SObject est transmis, le
tableau LeadConvertResults contient un seul élément.
Un objet LeadConvertResult contient les méthodes suivantes :
Nom
Type
Description
getAccountId
ID
L'ID du nouveau compte (si un nouveau compte a été spécifié)
ou l'ID du compte spécifié lors de l'invocation de
convertLead.
getContactId
ID
L'ID du nouveau contact (si un nouveau contact a été spécifié)
ou l'ID du contact spécifié lors de l'invocation de
convertLead.
getErrors
Database.Error
Si une erreur s'est produite, un tableau d'un ou de plusieurs
[]Database.Error [] objets d'erreur de base de données indiquant le code et la
description de l'erreur. Pour plus d'informations, reportez-vous
à Méthodes d'objet d'erreur de base de données à la page 489.
getLeadId
ID
L'ID de la piste convertie.
getOpportunityId
ID
L'ID de la nouvelle opportunité, si elle a été créée lors de
l'invocation de convertLead.
isSuccess
Boolean
Une valeur booléenne définie sur true si l'opération DML a
réussi pour cet objet, sinon définie sur false.
Référence
salesforce | Opération Delete | 332
Exemple de méthode de base de données
Lead myLead = new Lead(LastName = 'Fry', Company='Fry And Sons');
insert myLead;
Database.LeadConvert lc = new database.LeadConvert();
lc.setLeadId(myLead.id);
LeadStatus convertStatus = [SELECT Id, MasterLabel FROM LeadStatus WHERE IsConverted=true
LIMIT 1];
lc.setConvertedStatus(convertStatus.MasterLabel);
Database.LeadConvertResult lcr = Database.convertLead(lc);
System.assert(lcr.isSuccess());
Opération Delete
L'opération DML delete supprime un ou plusieurs enregistrements sObject existants, tels que des comptes ou des contacts
individuels, des données de votre organisation. delete est semblable à l'instruction delete() dans l'API SOAP.
Syntaxe de l'instruction DML
delete sObject | Record.ID
Syntaxe de la méthode de base de données
•
•
DeleteResult Database.Delete((sObject recordToDelete | RecordID ID), Boolean opt_allOrNone)
DeleteResult[] Database.Delete((sObject[] recordsToDelete | RecordIDs LIST<>IDs{}), Boolean opt_allOrNone)
Le paramètre facultatif opt_allOrNone indique si l'opération autorise le succès partiel. Si vous spécifiez false pour ce
paramètre et qu'un enregistrement échoue, le reste de l'opération DML peut réussir. Cette méthode renvoie un objet de résultat
qui permet de déterminer quels enregistrements ont réussi, quels enregistrements ont échoué, et pour quelles raisons.
Règles et consignes
Lors de la suppression d'enregistrements sObject, tenez compte des règles et des consignes suivantes :
•
Pour assurer l'intégrité de référence, delete prend en charge les suppressions en cascade. Si vous supprimez un objet
parent, vous supprimez automatiquement ses enfants, si chaque enregistrement enfant peut être supprimé.
Par exemple, si vous supprimez un enregistrement de requête, Apex supprime automatiquement tout enregistrement
CaseComment, CaseHistory et CaseSolution associé à cette requête. Cependant, si un enregistrement enfant particulier
ne peut pas être supprimé ou est actuellement utilisé, l'opération delete sur l'enregistrement de requête parent échoue.
•
•
Certains sObjects ne peuvent pas être supprimés. Pour supprimer un enregistrement sObject, sa propriété deletable
doit être définie sur true. Reportez-vous également à sObjects qui ne prennent pas en charge les opérations DML à la page
351.
Vous pouvez passer jusqu'à 10 000 enregistrements sObject à une méthode delete unique.
Référence
salesforce | Opération Delete | 333
Objet DeleteResult
Un tableau d'objets Database.DeleteResult est renvoyé avec la méthode de base de données delete. Chaque élément du
tableau DeleteResult correspond au tableau sObject transmis en tant que paramètre sObject[] dans la méthode de base de
données delete, c.-à-d. que le premier élément du tableau DeleteResult correspond au premier élément transmis dans le
tableau sObject, le deuxième élément correspond deuxième élément, etc. Si un seul sObject est transmis, le tableau DeleteResults
contient un seul élément.
Un objet Database.DeleteResult contient les méthodes suivantes :
Nom
Type
Description
getErrors
Database.Error Si une erreur s'est produite, un tableau d'un ou de plusieurs objets
[]
d'erreur de base de données indiquant le code et la description
de l'erreur. Pour plus d'informations, reportez-vous à Méthodes
d'objet d'erreur de base de données à la page 489.
getId
ID
L'ID du sObject que vous avez essayé de supprimer. Si ce champ
contient une valeur, l'objet a été supprimé avec succès. Si ce
champ est vide, l'opération n'a pas réussi pour cet objet.
isSuccess
Boolean
Une valeur booléenne définie sur true si l'opération DML a réussi
pour cet objet, sinon définie sur false.
Exemple d'instruction DML
L'exemple suivant supprime tous les comptes nommés 'DotCom' :
Account[] doomedAccts = [SELECT Id, Name FROM Account
WHERE Name = 'DotCom'];
try {
delete doomedAccts;
} catch (DmlException e) {
// Process exception here
}
Remarque: Pour plus d'informations sur le traitement des exceptions DmlException, reportez-vous à Gestion des
exceptions DML en masse à la page 353.
Exemple de méthode de base de données
L'exemple suivant supprime un compte nommé 'DotCom' :
Account[] doomedAccts = [SELECT Id, Name FROM Account WHERE Name = 'DotCom'];
Database.DeleteResult[] DR_Dels = Database.delete(doomedAccts);
Référence
salesforce | Opération Insert | 334
Opération Insert
L'opération DML insert ajoute un ou plusieurs sObjects, tels que des comptes ou des contacts, aux données de votre
organisation. insert est semblable à l'instruction INSERT dans SQL.
Syntaxe de l'instruction DML
insert sObject
insert sObject[]
Syntaxe de la méthode de base de données
•
•
SaveResult Database.insert(sObject recordToInsert, Boolean opt_allOrNone | database.DMLOptions
opt_DMLOptions)
SaveResult[] Database.insert(sObject[] recordsToInsert, Boolean opt_allOrNone | database.DMLOptions
opt_DMLOptions)
Le paramètre facultatif opt_allOrNone indique si l'opération autorise le succès partiel. Si vous spécifiez false pour ce
paramètre et qu'un enregistrement échoue, le reste de l'opération DML peut réussir. Cette méthode renvoie un objet de résultat
qui permet de déterminer quels enregistrements ont réussi, quels enregistrements ont échoué, et pour quelles raisons.
Par exemple :
Database.SaveResult[] MySaveResult = Database.Insert(MyAccounts, false);
Le paramètre facultatif opt_DMLOptions spécifique des données supplémentaires pour la transaction, telles que des informations
sur une règle d'attribution ou un comportement d'annulation lorsque des erreurs se produisent durant l'insertion
d'enregistrements.
Par exemple :
//AssignmentRuleHeader
//UseDefaultRule
Database.DMLOptions dmo = new database.DMLOptions();
dmo.AssignmentRuleHeader.UseDefaultRule= true;
Lead l = new Lead(Company='ABC', LastName='Smith');
l.setOptions(dmo);
insert l;
Pour plus d'informations, reportez-vous à Propriétés d'options DML de base de données à la page 485.
Règles et consignes
Lors de l'insertion d'enregistrements sObject, tenez compte des règles et des consignes suivantes :
•
Certains sObjects ne peuvent pas être créés. Pour créer un enregistrement sObject, sa propriété createable doit être
définie sur true.
Référence
•
•
•
•
•
•
•
salesforce | Opération Insert | 335
Vous devez saisir une valeur non null dans tous les champs obligatoires.
Vous pouvez passer jusqu'à 10 000 enregistrements sObject à une méthode insert unique.
L'instruction insert définit automatiquement la valeur ID de tous les nouveaux enregistrements sObject. L'insertion
d'un enregistrement qui inclut déjà un ID (existe déjà dans les données de votre organisation) génère une erreur. Pour plus
d'informations, reportez-vous à Listes.
Pour certains sObjects qui incluent des champs avec des contraintes uniques, l'insertion d'enregistrements sObject dupliqués
génère une erreur. Par exemple, l'insertion de sObjects CollaborationGroup portant le même nom entraîne une erreur, car
les enregistrements CollaborationGroup doivent avoir des noms uniques.
L'instruction insert peut définir uniquement l'ID de clé étrangère d'enregistrements sObject. Les champs des
enregistrements associés ne peuvent pas être mis à jour avec insert. Par exemple, lors de l'insertion d'un nouveau contact,
vous pouvez spécifier l'enregistrement du compte associé du contact en définissant la valeur du champ AccountId.
Cependant, vous ne pouvez pas modifier le nom du compte sans mettre à jour le compte lui-même dans un appel DML
séparé.
L'instruction insert n'est pas prise en charge avec certains sObjects. Reportez-vous à sObjects qui ne prennent pas en
charge les opérations DML à la page 351.
Cette opération examine chaque lot d'enregistrements pour vérifier s'ils contiennent des valeurs ID dupliquées. Si des
doublons sont détectés, les cinq premiers sont traités. À partir du sixième ID dupliqué, l'objet SaveResult de ces entrées
est marqué avec une erreur similaire à la suivante : Maximum number of duplicate updates in one batch
(5 allowed). Attempt to update Id more than once in this API call: number_of_attempts.
Objet SaveResult
Un tableau d'objets SaveResult est renvoyé avec les méthodes de base de données insert et update. Chaque élément du
tableau SaveResult correspond au tableau sObject transmis en tant que paramètre sObject[] dans la méthode de base de
données, c.-à-d. que le premier élément du tableau SaveResult correspond au premier élément transmis dans le tableau sObject,
le deuxième élément correspond deuxième élément, etc. Si un seul sObject est transmis, le tableau SaveResults contient un
seul élément.
Un objet SaveResult contient les méthodes suivantes :
Nom
Type
Description
getErrors
Database.Error []
Si une erreur s'est produite, un tableau
d'un ou de plusieurs objets d'erreur de
base de données indiquant le code et la
description de l'erreur. Pour plus
d'informations, reportez-vous à
Méthodes d'objet d'erreur de base de
données à la page 489.
getId
ID
L'ID du sObject que vous avez essayé
d'insérer ou de mettre à jour. Si ce champ
contient une valeur, l'objet a été inséré
ou mis à jour avec succès. Si ce champ
est vide, l'opération n'a pas réussi pour
cet objet.
isSuccess
Boolean
Une valeur booléenne définie sur true si
l'opération DML a réussi pour cet objet,
sinon définie sur false.
Référence
salesforce | Opération Insert | 336
Exemple d'instruction DML
L'exemple suivant insère un compte nommé 'Acme' :
Account newAcct = new Account(name = 'Acme');
try {
insert newAcct;
} catch (DmlException e) {
// Process exception here
}
Remarque: Pour plus d'informations sur le traitement des exceptions DmlException, reportez-vous à Gestion des
exceptions DML en masse à la page 353.
Exemple de méthode de base de données
L'exemple suivant insère un compte nommé 'Acme' :
Account a = new Account(name = 'Acme');
Database.SaveResult[] lsr = Database.insert(new Account[]{a, new Account(Name = 'Acme')},
false);
// Iterate through the Save Results
for(Database.SaveResult sr:lsr){
if(!sr.isSuccess())
Database.Error err = sr.getErrors()[0];
}
Création d'enregistrements parents et enfants dans une instruction unique en utilisant des clés
étrangères
Vous pouvez utiliser des champs ID externes en tant que clés étrangères afin de créer en seule une étape des enregistrements
parents et enfants pour différents types de sObject, au lieu de créer le parent, de demander ensuite son ID, puis de créer
l'enregistrement enfant. Pour cela :
•
•
•
•
•
Créez le sObject enfant, puis renseignez ses champs obligatoires et les champs facultatifs de votre choix.
Créez le sObject parent de référence utilisé uniquement pour définir la référence de clé étrangère du parent dans le sObject
enfant. Seul le champ ID externe est défini pour cet sObject (aucun autre champ).
Définissez le champ de clé étrangère du sObject enfant sur le sObject parent de référence que vous venez de créer.
Créez un autre sObject parent à transmettre à l'instruction insert. Les champs obligatoires de cet sObject doivent être
définis (et éventuellement d'autres champs facultatifs) en plus du champ ID externe.
Appelez insert en lui passant un tableau de sObjects à créer. Le sObject parent doit précéder le sObject enfant dans le
tableau, c.-à-d. que l'index de tableau du parent doit être inférieur à l'index de l'enfant.
Référence
salesforce | Opération Insert | 337
Les enregistrements parent et ses enfants sont associés via une relation prédéfinie telle qu'une relation principal-détails ou une
relation de référence. Vous pouvez créer jusqu'à 10 niveaux d'enregistrements associés. De plus, les enregistrements associés
créés dans un même appel doivent avoir des types Object différents. Pour plus d'informations, reportez-vous à Creating Records
for Different Object Types dans le guide SOAP API Developer's Guide.
L'exemple suivant montre comment créer une opportunité avec un compte parent utilisant la même instruction insert. Cet
exemple crée un sObject Opportunity et renseigne certains de ses champs, puis crée deux objets Account. Le premier compte
sert uniquement à la relation de clé étrangère. Le deuxième sert à la création du compte et les champs du compte sont définis.
Les deux comptes incluent le champ ID externe, MyExtID__c, défini. Ensuite, l'exemple appelle Database.insert en lui
passant un tableau de sObjects. Le premier élément du tableau est le sObject parent et le deuxième est le sObject opportunité.
L'instruction Database.insert crée l'opportunité avec son compte parent en une seule étape. Pour terminer, l'exemple
vérifie les résultats, puis écrit les ID des enregistrements créés dans le journal de débogage, ou la première erreur si la création
de l'enregistrement échoue. Cet exemple nécessite un champ de texte d'ID externe dans le compte appelé MyExtID.
public class ParentChildSample {
public static void InsertParentChild() {
Date dt = Date.today();
dt = dt.addDays(7);
Opportunity newOpportunity = new Opportunity(
Name='OpportunityWithAccountInsert',
StageName='Prospecting',
CloseDate=dt);
// Create the parent reference.
// Used only for foreign key reference
// and doesn't contain any other fields.
Account accountReference = new Account(
MyExtID__c='SAP111111');
newOpportunity.Account = accountReference;
// Create the Account object to insert.
// Same as above but has Name field.
// Used for the insert.
Account parentAccount = new Account(
Name='Hallie',
MyExtID__c='SAP111111');
// Create the account and the opportunity.
Database.SaveResult[] results = Database.insert(new SObject[] {
Référence
salesforce | Instruction Merge | 338
parentAccount, newOpportunity });
// Check results.
for (Integer i = 0; i < results.size(); i++) {
if (results[i].isSuccess()) {
System.debug('Successfully created ID: '
+ results[i].getId());
} else {
System.debug('Error: could not create sobject '
+ 'for array element ' + i + '.');
System.debug('
The error reported was: '
+ results[i].getErrors()[0].getMessage() + '\n');
}
}
}
}
Instruction Merge
L'instruction merge fusionne jusqu'à trois enregistrements du même type de sObject dans l'un des enregistrements, en
supprimant les autres et en réapparentant tous les enregistrements associés.
Remarque: Cette instruction DML n'a pas de méthode de base de données système de mappage.
Syntaxe
merge sObject sObject
merge sObject sObject[]
merge sObject ID
merge sObject ID[]
Le premier paramètre représente l'enregistrement principal dans lequel les autres enregistrements sont fusionnés. Le deuxième
paramètre représente le ou les enregistrements qui doivent être fusionnés, puis supprimés. Vous pouvez passer ces autres
enregistrements dans l'instruction merge en tant qu'enregistrement sObject ou ID unique, ou dans une liste de deux
enregistrements sObject ou ID.
Règles et consignes
Lors de la fusion d'enregistrements sObject, tenez compte des règles et des consignes suivantes :
Référence
salesforce | Opération Undelete | 339
Seuls des contacts, des pistes et des comptes peuvent être fusionnés. Reportez-vous à sObjects qui ne prennent pas en
charge les opérations DML à la page 351.
Vous pouvez passer un enregistrement principal et jusqu'à deux enregistrements sObject supplémentaires à une seule
méthode merge.
•
•
Pour plus d'informations sur la fusion de pistes, de contacts et de comptes, reportez-vous à l'aide en ligne de Salesforce.
Exemple
L'exemple suivant fusionne deux comptes nommés 'Acme Inc.' et 'Acme' dans un seul enregistrement :
List<Account> ls = new List<Account>{new Account(name='Acme Inc.'),new Account(name='Acme')};
insert ls;
Account masterAcct = [SELECT Id, Name FROM Account WHERE Name = 'Acme Inc.' LIMIT 1];
Account mergeAcct = [SELECT Id, Name FROM Account WHERE Name = 'Acme' LIMIT 1];
try {
merge masterAcct mergeAcct;
} catch (DmlException e) {
// Process exception here
}
Remarque: Pour plus d'informations sur le traitement des exceptions DmlException, reportez-vous à Gestion des
exceptions DML en masse à la page 353.
Opération Undelete
L'opération DML undelete restaure un ou plusieurs sObjects existants, tels que des comptes ou des contacts, depuis la
Corbeille de votre organisation. undelete est semblable à l'instruction UNDELETE dans SQL.
Syntaxe de l'instruction DML
undelete sObject | Record.ID
undelete sObject[] | LIST<>ID[]
Syntaxe de la méthode de base de données
•
•
UndeleteResult Database.Undelete((sObject recordToUndelete | RecordID ID), Boolean opt_allOrNone)
UndeleteResult[] Database.Undelete((sObject[] recordsToUndelete | RecordIDs LIST<>IDs{}), Boolean
opt_allOrNone)
Le paramètre facultatif opt_allOrNone indique si l'opération autorise le succès partiel. Si vous spécifiez false pour ce
paramètre et qu'un enregistrement échoue, le reste de l'opération DML peut réussir. Cette méthode renvoie un objet de résultat
qui permet de déterminer quels enregistrements ont réussi, quels enregistrements ont échoué, et pour quelles raisons.
Règles et consignes
Lors de la restauration d'enregistrements sObject, tenez compte des règles et des consignes suivantes :
Référence
•
salesforce | Opération Undelete | 340
Pour garantir l'intégrité référentielle, undelete restaure les associations d'enregistrements pour les types de relations
suivants :
◊ Les comptes parents (comme indiqué dans le champ Compte principal d'un compte)
◊ Les requêtes parentes (comme indiqué dans le champ Requête principale d'une requête)
◊ Les solutions parentes pour les solutions traduites (comme indiqué dans le champ Solution principale d'une
solution)
◊ Les responsables de contacts (comme indiqué dans le champ Rattachement hiérarchique)
◊ Les produits associés à des actifs (comme indiqué dans le champ Produit d'un actif)
◊ Opportunités associées à des devis (comme indiqué dans le champ Opportunité d'un devis)
◊ Toutes les relations de référence personnalisées
◊ Les membres de groupe de relations dans les comptes et les groupes de relations, avec certaines exceptions
◊ Les balises
◊ Les catégories, le statut de publication et les attributions d'un article
Remarque: Salesforce restaure uniquement les relations de référence qui n'ont pas été remplacées. Par exemple,
si un actif est associé à un produit différent avant l'enregistrement d'un produit d'origine restauré, la relation
actif-produit n'est pas restaurée.
•
•
•
•
•
Certains sObjects ne peuvent pas être restaurés. Pour déterminer si un enregistrement sObject peut être restauré, vérifiez
si la propriété undeletable du sObject est définie sur true.
Vous pouvez passer jusqu'à 10 000 enregistrements sObject à une méthode undelete unique.
Vous pouvez restaurer des enregistrements qui ont été supprimés suite à une fusion, mais les objets enfants doivent être
réapparentés, car ils ne peuvent pas être restaurés.
Utilisez les paramètres ALL ROWS dans une requête SOQL pour identifier les enregistrements supprimés, notamment lors
d'une fusion. Reportez-vous à Demande de tous les enregistrements avec une instruction SOQL à la page 90.
La restauration n'est pas prise en charge avec certains sObjects. Reportez-vous à sObjects qui ne prennent pas en charge
les opérations DML à la page 351.
Objet UndeleteResult
Un tableau d'objets Database.UndeleteResult est renvoyé avec la méthode de base de données undelete. Chaque élément
du tableau UndeleteResult correspond au tableau sObject transmis en tant que paramètre sObject[] dans la méthode de
base de données undelete, c.-à-d. que le premier élément du tableau UndeleteResult correspond au premier élément transmis
dans le tableau sObject, le deuxième élément correspond deuxième élément, etc. Si un seul sObject est transmis, le tableau
UndeleteResults contient un seul élément.
Un objet undeleteResult contient les méthodes suivantes :
Nom
Type
Description
getErrors
Database.Error []
Si une erreur s'est produite, un tableau
d'un ou de plusieurs objets d'erreur de
base de données indiquant le code et la
description de l'erreur. Pour plus
d'informations, reportez-vous à
Méthodes d'objet d'erreur de base de
données à la page 489.
getId
ID
L'ID du sObject que vous avez essayé de
restaurer. Si ce champ contient une
valeur, l'objet a été restauré avec succès.
Référence
salesforce | Opération Undelete | 341
Nom
Type
Description
Si ce champ est vide, l'opération n'a pas
réussi pour cet objet.
Boolean
isSuccess
Une valeur booléenne définie sur true si
l'opération DML a réussi pour cet objet,
sinon définie sur false.
Exemple d'instruction DML
L'exemple suivant restaure un compte nommé 'Trump' : Les mots clés ALL ROWS interrogent toutes les lignes sur les relations
de niveau supérieur et agrégés, y compris les enregistrements supprimés et les activités archivées.
Account a = new Account(Name='AC1');
insert(a);
insert(new Contact(LastName='Carter',AccountId=a.Id));
Account[] savedAccts = [SELECT Id, Name FROM Account WHERE Name = 'Trump' ALL ROWS];
try {
undelete savedAccts;
} catch (DmlException e) {
// Process exception here
}
Remarque: Pour plus d'informations sur le traitement des exceptions DmlException, reportez-vous à Gestion des
exceptions DML en masse à la page 353.
Exemple de méthode de base de données
L'exemple suivant restaure un compte nommé 'Trump' : Les mots clés ALL ROWS interrogent toutes les lignes sur les relations
de niveau supérieur et agrégés, y compris les enregistrements supprimés et les activités archivées.
public class DmlTest2 {
public void undeleteExample() {
Account[] SavedAccts = [SELECT Id, Name FROM Account WHERE Name = 'Trump' ALL ROWS];
Database.UndeleteResult[] UDR_Dels = Database.undelete(SavedAccts);
for(integer i =0; i< 10; i++)
if(UDR_Dels[i].getErrors().size()>0){
// Process any errors here
}
Référence
salesforce | Opération Update | 342
}
}
Opération Update
L'opération DML update modifie un ou plusieurs sObjects existants, tels que des relevés de comptes ou de contacts individuels,
dans les données de votre organisation. update est semblable à l'instruction UPDATE dans SQL.
Syntaxe de l'instruction DML
update sObject
update sObject[]
Syntaxe de la méthode de base de données
•
•
UpdateResult Update(sObject recordToUpdate, Boolean opt_allOrNone | database.DMLOptions opt_DMLOptions)
UpdateResult[] Update(sObject[] recordsToUpdate[], Boolean opt_allOrNone | database.DMLOptions
opt_DMLOptions)
Le paramètre facultatif opt_allOrNone indique si l'opération autorise le succès partiel. Si vous spécifiez false pour ce
paramètre et qu'un enregistrement échoue, le reste de l'opération DML peut réussir. Cette méthode renvoie un objet de résultat
qui permet de déterminer quels enregistrements ont réussi, quels enregistrements ont échoué, et pour quelles raisons.
Le paramètre facultatif opt_DMLOptions spécifique des données supplémentaires pour la transaction, telles que des informations
sur une règle d'attribution ou un comportement d'annulation lorsque des erreurs se produisent durant l'insertion
d'enregistrements.
Pour plus d'informations, reportez-vous à Propriétés d'options DML de base de données à la page 485.
Règles et consignes
Lors de la mise à jour d'enregistrements sObject, tenez compte des règles et des consignes suivantes :
•
•
•
•
•
•
•
Certains sObjects ne peuvent pas être mis à jour. Pour mettre à jour un enregistrement sObject, sa propriété updateable
doit être définie sur true.
Lors de la mise à jour de champs obligatoires, vous devez saisir une valeur non null.
Contrairement à l'API SOAP, le langage Apex permet de changer les valeurs de champ en null sans mettre à jour le
tableau fieldsToNull dans l'enregistrement sObject. L'API nécessite une mise à jour pour ce tableau en raison du
traitement incohérent des valeurs null par les nombreux fournisseurs SOAP. Puisque le langage Apex est exécuté
exclusivement sur la plate-forme Force.com, cette précaution est inutile.
L'ID d'un enregistrement sObject mis à jour ne peut pas être modifié, mais l'ID des enregistrements associés peut être
modifié.
Cette opération examine chaque lot d'enregistrements pour vérifier s'ils contiennent des valeurs ID dupliquées. Si des
doublons sont détectés, les cinq premiers sont traités. À partir du sixième ID dupliqué, l'objet SaveResult de ces entrées
est marqué avec une erreur similaire à la suivante : Maximum number of duplicate updates in one batch
(5 allowed). Attempt to update Id more than once in this API call: number_of_attempts.
L'instruction update modifie automatiquement les valeurs de certains champs tels que LastModifiedDate,
LastModifiedById et SystemModstamp. Vous ne pouvez pas spécifier explicitement ces valeurs dans votre code Apex.
Vous pouvez passer jusqu'à 10 000 enregistrements sObject à une méthode update unique.
Référence
•
salesforce | Opération Update | 343
Une instruction update unique peut modifier un seul type de sObject à la fois. Par exemple, lors de la mise à jour d'un
champ de compte via un contact existant qui n'a pas été modifié, deux instructions update sont requises :
// Use a SOQL query to access data for a contact
Contact c = [SELECT Account.Name FROM Contact
WHERE LastName = 'Carter' LIMIT 1];
// Now we can change fields for both the contact and its
// associated account
c.Account.Name = 'salesforce.com';
c.LastName = 'Roth';
// To update the database, the two types of records must be
// updated separately
update c;
// This only changes the contact's last name
update c.Account; // This updates the account name
•
La mise à jour n'est pas prise en charge avec certains sObjects. Reportez-vous à sObjects qui ne prennent pas en charge les
opérations DML à la page 351.
Objet SaveResult
Un tableau d'objets SaveResult est renvoyé avec les méthodes de base de données insert et update. Chaque élément du
tableau SaveResult correspond au tableau sObject transmis en tant que paramètre sObject[] dans la méthode de base de
données, c.-à-d. que le premier élément du tableau SaveResult correspond au premier élément transmis dans le tableau sObject,
le deuxième élément correspond deuxième élément, etc. Si un seul sObject est transmis, le tableau SaveResults contient un
seul élément.
Un objet SaveResult contient les méthodes suivantes :
Nom
Type
Description
getErrors
Database.Error []
Si une erreur s'est produite, un tableau
d'un ou de plusieurs objets d'erreur de
base de données indiquant le code et la
description de l'erreur. Pour plus
d'informations, reportez-vous à
Méthodes d'objet d'erreur de base de
données à la page 489.
getId
ID
L'ID du sObject que vous avez essayé
d'insérer ou de mettre à jour. Si ce champ
contient une valeur, l'objet a été inséré
ou mis à jour avec succès. Si ce champ
est vide, l'opération n'a pas réussi pour
cet objet.
Référence
salesforce | Opération Update | 344
Nom
Type
Description
isSuccess
Boolean
Une valeur booléenne définie sur true si
l'opération DML a réussi pour cet objet,
sinon définie sur false.
Exemple d'instruction DML
L'exemple suivant met à jour le champ BillingCity dans un compte unique nommé 'Acme' :
Account a = new Account(Name='Acme2');
insert(a);
Account myAcct = [SELECT Id, Name, BillingCity FROM Account WHERE Id = :a.Id];
myAcct.BillingCity = 'San Francisco';
try {
update myAcct;
} catch (DmlException e) {
// Process exception here
}
Remarque: Pour plus d'informations sur le traitement des exceptions DmlException, reportez-vous à Gestion des
exceptions DML en masse à la page 353.
Exemple de méthode de base de données
L'exemple suivant met à jour le champ BillingCity dans un compte unique nommé 'Acme' :
Account a = new Account(Name='Acme2');
insert(a);
Account myAcct = [SELECT Id, Name, BillingCity FROM Account WHERE Id = :a.Id];
myAcct.BillingCity = 'San Francisco';
Database.SaveResult SR = database.update(myAcct);
for(Database.Error err: SR.getErrors())
{
// process any errors here
Référence
salesforce | Opération Upsert | 345
}
Opération Upsert
L'opération DML upsert crée des enregistrements sObject et met à jour les enregistrements sObject existants dans une seule
instruction, en utilisant un champ personnalisé facultatif pour déterminer la présence d'objets existants.
Syntaxe de l'instruction DML
upsert sObject opt_external_id
upsert sObject[] opt_external_id
opt_external_id est une variable facultative qui spécifie le champ personnalisé à utiliser pour mapper les enregistrements
qui existent déjà dans les données de votre organisation. Ce champ personnalisé doit être créé avec l'attribut External Id
sélectionné. De plus, si l'attribut Unique n'est pas sélectionné pour le champ, l'utilisateur contextuel doit avoir l'autorisation
au niveau de l'objet « Afficher tout » pour l'objet cible ou l'autorisation « Afficher toutes les données » afin d'empêcher upsert
d'insérer accidentellement un enregistrement double.
Si opt_external_id n'est pas spécifié, le champ ID de l'enregistrement sObject est utilisé par défaut.
Remarque: Le mappage de champs personnalisés est insensible à la casse uniquement si les attributs Unique et
Considérer « ABC » et « abc » comme des valeurs en double (insensible à la casse) sont sélectionnés dans la définition
du champ personnalisé. S'ils sont sélectionnés, « ABC123 » est mappé avec « abc123 ». Pour plus d'informations,
reportez-vous à Création de champs personnalisés.
Syntaxe de la méthode de base de données
•
•
UpsertResult Database.Upsert(sObject recordToUpsert, Schema.SObjectField External_ID_Field, Boolean
opt_allOrNone)
UpsertResult[] Database.Upsert(sObject[] recordsToUpsert, Schema.SObjectField External_ID_Field, Boolean
opt_allOrNone)
Le paramètre facultatif External_ID_Field est une variable qui spécifie le champ personnalisé à utiliser pour mapper les
enregistrements qui existent déjà dans les données de votre organisation. Ce champ personnalisé doit être créé avec l'attribut
External Id sélectionné. De plus, si l'attribut Unique n'est pas sélectionné pour le champ, l'utilisateur contextuel doit avoir
l'autorisation au niveau de l'objet « Afficher tout » pour l'objet cible ou l'autorisation « Afficher toutes les données » afin
d'empêcher upsert d'insérer accidentellement un enregistrement double.
Le paramètre External_ID_Field est de type Schema.SObjectField, c.-à-d. un jeton de champ. Recherchez le jeton du
champ en utilisant la méthode spéciale fields. Par exemple, Schema.SObjectField f =
Account.Fields.MyExternalId.
Si External_ID_Field n'est pas spécifié, le champ ID de l'enregistrement sObject est utilisé par défaut.
Remarque: Le mappage de champs personnalisés est insensible à la casse uniquement si les attributs Unique et
Considérer « ABC » et « abc » comme des valeurs en double (insensible à la casse) sont sélectionnés dans la définition
du champ personnalisé. S'ils sont sélectionnés, « ABC123 » est mappé avec « abc123 ». Pour plus d'informations,
reportez-vous à Création de champs personnalisés.
Le paramètre facultatif opt_allOrNone indique si l'opération autorise le succès partiel. Si vous spécifiez false pour ce
paramètre et qu'un enregistrement échoue, le reste de l'opération DML peut réussir. Cette méthode renvoie un objet de résultat
qui permet de déterminer quels enregistrements ont réussi, quels enregistrements ont échoué, et pour quelles raisons.
Référence
salesforce | Opération Upsert | 346
Comment l'opération Upsert choisit Insert ou Update
L'opération Upsert utilise la clé primaire de l'enregistrement sObject (ou l'ID externe, si spécifié) pour déterminer si elle doit
créer un objet ou mettre à jour un objet existant :
•
•
•
Si la clé n'est pas mappée, un nouvel enregistrement d'objet est créé.
Si la clé est mappée une fois, l'enregistrement d'objet existant est mis à jour.
Si la clé est mappée plusieurs fois, une erreur est générée et l'enregistrement d'objet n'est ni inséré ni mis à jour.
Règles et consignes
Lors de la mise à jour ou l'insertion d'enregistrements sObject, tenez compte des règles et des consignes suivantes :
•
•
•
•
•
•
•
•
Certains sObjects ne peuvent pas être insérés ou mis à jour. Pour insérer un enregistrement sObject, sa propriété createable
doit être définie sur true. Pour mettre à jour un enregistrement sObject, sa propriété updateable doit être définie sur
true.
Vous devez saisir une valeur non null dans les champs obligatoires de tous les enregistrements insérés.
L'ID d'un enregistrement sObject ne peut pas être modifié, mais l'ID des enregistrements associés peut être modifié. Cette
action est interprétée en tant que mise à jour.
L'instruction upsert modifie automatiquement les valeurs de certains champs tels que LastModifiedDate,
LastModifiedById et SystemModstamp. Vous ne pouvez pas spécifier explicitement ces valeurs dans votre code Apex.
Chaque instruction upsert est formée de deux opérations, l'une pour l'insertion d'enregistrements et l'autre pour la mise
à jour des enregistrements. Chacune de ces opérations est soumise à des limitations d'exécution, respectivement pour
insert et update. Par exemple, si vous insérez/mettez à jour plus de 10 000 enregistrements, et qu'ils sont tous mis à
jour, vous recevez une erreur (reportez-vous à Compréhension des limitations et des gouverneurs d'exécution à la page 273).
L'instruction upsert peut définir uniquement l'ID d'enregistrements sObject associés. Les champs des enregistrements
associés ne peuvent pas être modifiés avec upsert. Par exemple, lors de la mise à jour d'un contact existant, vous pouvez
spécifier l'enregistrement du compte associé du contact en définissant la valeur du champ AccountId. Cependant, vous
ne pouvez pas modifier le nom du compte sans mettre à jour le compte lui-même dans une instruction DML séparée.
L'opération Upsert n'est pas prise en charge avec certains sObjects. Reportez-vous à sObjects qui ne prennent pas en charge
les opérations DML à la page 351.
Vous pouvez utiliser des clés étrangères pour insérer/mettre à jour des enregistrements sObject s'ils ont été définis en tant
que champs de référence. Pour plus d'informations, reportez-vous à Field Types dans le guide Object Reference for Salesforce
and Force.com.
Objet UpsertResult
Un tableau d'objets Database.UpsertResult est renvoyé avec la méthode de base de données upsert. Chaque élément du
tableau UpsertResult correspond au tableau sObject transmis en tant que paramètre sObject[] dans la méthode de base de
données upsert, c.-à-d. que le premier élément du tableau UpsertResult correspond au premier élément transmis dans le
tableau sObject, le deuxième élément correspond deuxième élément, etc. Si un seul sObject est transmis, le tableau UpsertResults
contient un seul élément.
Un objet UpsertResult contient les méthodes suivantes :
Nom
Type
Description
getErrors
Database.Error []
Si une erreur s'est produite, un tableau
d'un ou de plusieurs objets d'erreur de
base de données indiquant le code et la
description de l'erreur. Pour plus
d'informations, reportez-vous à
Méthodes d'objet d'erreur de base de
données à la page 489.
Référence
salesforce | Opération Upsert | 347
Nom
Type
Description
getId
ID
L'ID du sObject que vous avez essayé de
mettre à jour ou d'insérer. Si ce champ
contient une valeur, l'objet a été mis à
jour ou inséré avec succès. Si ce champ
est vide, l'opération n'a pas réussi pour
cet objet.
isCreated
Boolean
Une valeur booléenne est définie sur true
si l'enregistrement a été créé, sur false si
l'enregistrement a été mis à jour.
isSuccess
Boolean
Une valeur booléenne définie sur true si
l'opération DML a réussi pour cet objet,
sinon définie sur false.
Exemples d'instructions DML
L'exemple suivant met à jour le nom de la ville de tous les comptes existants situés à Bombay, puis insère un nouveau compte
situé à San Francisco :
Account[] acctsList = [SELECT Id, Name, BillingCity
FROM Account WHERE BillingCity = 'Bombay'];
for (Account a : acctsList) {
a.BillingCity = 'Mumbai';
}
Account newAcct = new Account(Name = 'Acme', BillingCity = 'San Francisco');
acctsList.add(newAcct);
try {
upsert acctsList;
} catch (DmlException e) {
// Process exception here
}
Remarque: Pour plus d'informations sur le traitement des exceptions DmlException, reportez-vous à Gestion des
exceptions DML en masse à la page 353.
Utilisez upsert avec un ID externe pour réduire le nombre d'instructions DML dans votre code et ne pas atteindre les
limitations du gouverneur (reportez-vous à Compréhension des limitations et des gouverneurs d'exécution). L'exemple suivant
utilise upsert et le champ ID externe Line_Item_Id__c dans l'objet Asset pour maintenir une relation un-à-un entre un
actif et un élément de ligne d'opportunité.
Référence
salesforce | Opération Upsert | 348
Remarque: Avant d'exécuter cet exemple, créez un champ de texte personnalisé dans l'objet Asset nommé
Line_Item_Id__c, puis marquez-le en tant qu'ID externe. Pour plus d'informations sur les champs personnalisés,
reportez-vous à l'aide en ligne de Salesforce.
public void upsertExample() {
Opportunity opp = [SELECT Id, Name, AccountId,
(SELECT Id, PricebookEntry.Product2Id, PricebookEntry.Name
FROM OpportunityLineItems)
FROM Opportunity
WHERE HasOpportunityLineItem = true
LIMIT 1];
Asset[] assets = new Asset[]{};
// Create an asset for each line item on the opportunity
for (OpportunityLineItem lineItem:opp.OpportunityLineItems) {
//This code populates the line item Id, AccountId, and Product2Id for each asset
Asset asset = new Asset(Name = lineItem.PricebookEntry.Name,
Line_Item_ID__c = lineItem.Id,
AccountId = opp.AccountId,
Product2Id = lineItem.PricebookEntry.Product2Id);
assets.add(asset);
}
try {
upsert assets Line_Item_ID__c;
// This line upserts the assets list with
// the Line_Item_Id__c field specified as the
// Asset field that should be used for matching
// the record that should be upserted.
} catch (DmlException e) {
System.debug(e.getMessage());
}
}
Référence
salesforce | Opération Upsert | 349
Exemple de méthode de base de données
L'exemple suivant utilise la méthode de base de données upsert pour insérer/mettre à jour une collection de pistes passées.
Cet exemple autorise le traitement partiel des enregistrements, c.-à-d. que si le traitement de certains enregistrements échoue,
les autres enregistrements sont insérés ou mis à jour. Il itère dans les résultats et ajoute une nouvelle tâche à chaque enregistrement
dont le traitement a réussi. Les sObjects de la tâche sont enregistrés dans une liste, qui est ensuite insérée en masse. Cet exemple
contient également une méthode de test qui permet d'évaluer l'exemple.
/* This class demonstrates and tests the use of the
* partial processing DML operations */
public class dmlSamples {
/* This method accepts a collection of lead records and
creates a task for the owner(s) of any leads that were
created as new, that is, not updated as a result of the upsert
operation */
public static List<Database.upsertResult> upsertLeads(List<Lead> leads)
{
/* Perform the upsert. In this case the unique identifier for the
insert or update decision is the Salesforce record ID. If the
record ID is null the row will be inserted, otherwise an update
will be attempted. */
List<Database.upsertResult> uResults = Database.upsert(leads,false);
/* This is the list for new tasks that will be inserted when new
leads are created. */
List<Task> tasks = new List<Task>();
for(Database.upsertResult result:uResults) {
if (result.isSuccess() && result.isCreated())
tasks.add(new Task(Subject = 'Follow-up', WhoId = result.getId()));
}
/* If there are tasks to be inserted, insert them */
Database.insert(tasks);
return uResults;
Référence
salesforce | Opération Upsert | 350
}
public static testMethod void testUpsertLeads() {
/* We only need to test the insert side of upsert */
List<Lead> leads = new List<Lead>();
/* Create a set of leads for testing */
for(Integer i = 0;i < 100; i++) {
leads.add(new Lead(LastName = 'testLead', Company = 'testCompany'));
}
/* Switch to the runtime limit context */
Test.startTest();
/* Exercise the method */
List<Database.upsertResult> results = DmlSamples.upsertLeads(leads);
/* Switch back to the test context for limits */
Test.stopTest();
/* ID set for asserting the tasks were created as expected */
Set<Id> ids = new Set<Id>();
/* Iterate over the results, asserting success and adding the new ID
to the set for use in the comprehensive assertion phase below. */
for(Database.upsertResult result:results) {
System.assert(result.isSuccess());
ids.add(result.getId());
}
/* Assert that exactly one task exists for each lead that was inserted. */
for(Lead l:[SELECT Id, (SELECT Subject FROM Tasks) FROM Lead WHERE Id IN :ids]) {
System.assertEquals(1,l.tasks.size());
Référence
salesforce | sObjects qui ne prennent pas en charge les
opérations DML | 351
}
}
}
sObjects qui ne prennent pas en charge les opérations DML
Les opérations DML ne sont pas prises en charge avec les objets suivants sObjects dans le langage Apex :
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
AccountTerritoryAssignmentRule
AccountTerritoryAssignmentRuleItem
ApexComponent
ApexPage
BusinessHours
BusinessProcess
CategoryNode
CurrencyType
DatedConversionRate
ProcessInstance*
Profile
RecordType
SelfServiceUser
StaticResource
UserAccountTeamMember
UserTerritory
WebLink
* Vous ne pouvez pas créer, mettre à jour ou supprimer ProcessInstance dans l'API SOAP.
sObjects non utilisables dans des opérations DML
Certains sObjects nécessitent l'exécution d'opérations DML d'un seul type par transaction. Par exemple, vous ne pouvez pas
insérer un compte, puis insérer un utilisateur ou un membre de groupe dans la même transaction. Les sObjects suivants ne
peuvent pas être utilisés ensemble dans une transaction :
•
•
FieldPermissions
Group
Vous pouvez uniquement insérer ou mettre un jour un groupe dans une transaction avec d'autres sObjects. Les autres
opérations DML ne sont pas autorisées.
•
GroupMember
Vous pouvez uniquement insérer et mettre à jour un membre de groupe dans une transaction avec d'autres sObjects dans
un code Apex enregistré en utilisant l'API Salesforce.com versions 14.0 et supérieures.
Référence
•
•
•
•
•
•
salesforce | sObjects non utilisables dans des opérations
DML | 352
ObjectPermissions
PermissionSet
PermissionSetAssignment
QueueSObject
SetupEntityAccess
User
Vous pouvez insérer un utilisateur dans une transaction avec d'autres sObjects dans un code Apex enregistré en utilisant
l'API Salesforce.com versions 14.0 et supérieures.
Vous pouvez insérer un utilisateur dans une transaction avec d'autres sObjects dans un code Apex enregistré en utilisant
l'API Salesforce.com versions 15.0 et supérieures si UserRoleId est spécifié comme null.
Vous pouvez mettre à jour un utilisateur dans une transaction avec d'autres sObjects dans un code Apex enregistré en
utilisant l'API Salesforce.com versions 14.0 et supérieures.
Vous pouvez mettre à jour un utilisateur dans une transaction avec d'autres sObjects dans un code Apex enregistré en
utilisant l'API Salesforce.com versions 15.0 et supérieures si les champs suivants sont également mis à jour :
◊
◊
◊
◊
◊
◊
•
•
•
•
UserRoleId
IsActive
ForecastEnabled
IsPortalEnabled
Username
ProfileId
UserRole
UserTerritory
Territory
Les paramètres personnalisés dans un code Apex sont enregistrés en utilisant l'API Salesforce.com versions 17.0 et
supérieures.
Ces sObjects ne font l'objet d'aucune restriction pour les opérations DML delete.
Si vous utilisez une page Visualforce avec un contrôleur personnalisé, vous pouvez effectuer des opérations DML uniquement
sur un seul type de sObject dans une requête ou une action unique. Vous pouvez toutefois effectuer des opérations DML sur
différents types de sObjects dans les requêtes successives, par exemple pour créer un compte avec un bouton Enregistrer, puis
créer un utilisateur avec un bouton Soumettre.
Vous pouvez effectuer des opérations DML sur plusieurs types de sObject dans une classe unique en utilisant le processus
suivant :
1. Créez une méthode qui effectue une opération DML sur un type de sObject.
2. Créez une deuxième méthode qui utilise l'annotation future pour manipuler un deuxième type de sObject.
Opérations DML autorisées dans des méthodes de test dans des blocs System.RunAs()
Les méthodes de test permettent d'effectuer des opérations DML mixtes entre les sObjects répertoriés ci-dessus et d'autres
sObjects si le code qui effectue les opérations DML est inclus entre des blocs de méthode System.runAs. Vous pouvez par
exemple créer un utilisateur avec un rôle et d'autres sObjects dans le même test.
L'exemple suivant montre comment inclure des opérations DML mixtes dans des blocs System.runAs pour éviter l'erreur
de DML mixtes. Le premier bloc est exécuté dans le contexte de l'utilisateur actif. Il crée un utilisateur test et un compte test.
Référence
salesforce | Gestion des exceptions DML en masse | 353
Le deuxième bloc est exécuté dans le contexte de l'utilisateur test et met à jour le compte. Avant d'exécuter cet exemple,
remplacez la valeur du rôle utilisateur dans la requête par un rôle utilisateur existant dans votre organisation.
@isTest
private class MixedDML {
static testMethod void MixedDMLExample() {
User u;
Account a;
User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];
// Insert account as current user
System.runAs (thisUser) {
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
UserRole r = [SELECT Id FROM UserRole WHERE Name='SalesRep'];
u = new User(alias = 'jsmtih', email='[email protected]',
emailencodingkey='UTF-8', lastname='Smith',
languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, userroleid = r.Id,
timezonesidkey='America/Los_Angeles',
username='[email protected]');
insert u;
a = new Account(name='Acme');
insert a;
}
// Update account as the new user
System.runAs(u) {
a.website = 'www.salesforce.com';
update a;
}
}
}
Gestion des exceptions DML en masse
La gestion des exceptions générées par un appel DML en masse (y compris les opérations DML récursives dans des déclencheurs
activés suite à l'appel) diffère selon l'origine de l'appel :
Référence
•
•
salesforce | Méthodes et classes standard Apex | 354
Lorsque des erreurs se produisent suite à un appel DML en masse provenant directement d'instructions DML Apex ou si
le paramètre all_or_none d'une méthode de base de données DML a été spécifié comme true, le moteur d'exécution
suit la règle « tout ou rien » : durant une opération unique, tous les enregistrements doivent être mis à jour avec succès,
sinon l'opération entière revient au point précédant immédiatement l'instruction DML.
Lorsque des erreurs se produisent suite à un appel DML en masse provenant de l'API SOAP, le moteur d'exécution tente
au moins un enregistrement partiel :
1. Lors de la première tentative, le moteur d'exécution traite tous les enregistrements. Tous les enregistrements qui génèrent
une erreur, due à des problèmes de règles de validation ou de violations d'index unique, sont mis de côté.
2. Si des erreurs se sont produites lors de la première tentative, le moteur d'exécution effectue une deuxième tentative qui
inclut uniquement les enregistrements qui n'ont pas généré d'erreur. Tous les enregistrements qui n'ont pas généré
d'erreur lors de la première tentative sont traités. Si parmi ces enregistrements certains entraînent une erreur (peu
probable), ils sont également mis de côté.
3. Si des erreurs supplémentaires se sont produites lors de la deuxième tentative, le moteur d'exécution effectue une
troisième tentative qui inclut uniquement les enregistrements qui n'ont pas généré d'erreur lors des première et deuxième
tentatives. Si un enregistrement génère une erreur, l'opération entière échoue avec le message « Too many batch retries
in the presence of Apex triggers and partial failures ».
Remarque: Lors des deuxième et troisième tentatives, les limitations du gouverneur sont réinitialisées à leur état
d'origine avant la première tentative. Reportez-vous à Compréhension des limitations et des gouverneurs d'exécution
à la page 273.
Méthodes et classes standard Apex
Apex fournit des classes standard qui contiennent des méthodes statiques et d'instance pour des expressions de type de données
primitif, ainsi que des objets plus complexes.
Les méthodes statiques standard sont similaires à Java et se présentent toujours sous la forme :
Class.method(args)
Les méthodes statiques standard de type de données primitif n'ont pas de paramètre implicite et sont invoquées sans aucun
contexte d'objet. Par exemple, l'expression suivante arrondi la valeur de 1,75 au nombre entier le plus proche sans utiliser une
autre valeur.
Math.roundToLong(1.75);
Toutes les méthodes d'instance se présentent dans des expressions d'un type de données particulier, tel qu'une liste, un ensemble
ou une chaîne. Par exemple :
String s = 'Hello, world';
Integer i = s.length();
Référence
salesforce | Méthodes Primitives Apex | 355
Remarque: Si une méthode est appelée avec une expression d'objet qui évalue à null, le moteur d'exécution Apex
lève une exception d'indicateur null.
Certaines classes utilisent un espace de noms en tant que mécanisme de regroupement de leurs méthodes. Par exemple, la
classe message utilise l'espace de noms ApexPages.
ApexPages.Message myMsg = new ApexPages.Message(ApexPages.FATAL, 'My Error Message');
Les classes standard Apex sont regroupées dans les catégories suivantes :
•
•
•
•
•
•
Primitives
Collections
Enums
sObjects
System
Exceptions
Méthodes Primitives Apex
Dans le langage Apex, de nombreux types de données primitifs contiennent des méthodes qui peuvent être utilisées des
manipulations supplémentaires de données. Les primitifs disposant de méthodes sont les suivants :
•
•
•
•
•
•
•
•
•
•
Blob
Boolean
Date
Datetime
Decimal
Double
ID
Long
String
Time
Méthodes Blob
La méthode ci-dessous est une méthode statique système pour Blob.
Nom
Arguments
Type de renvoi
Description
toPdf
String S
Blob
Crée un objet binaire hors de la chaîne donnée en le
codant en tant que fichier PDF.
valueOf
String S
Blob
Convertit la chaîne String S spécifiée en Blob. Par
exemple :
String myString = 'StringToBlob';
Blob myBlob = Blob.valueof(myString);
Référence
salesforce | Méthodes Primitives Apex | 356
Les méthodes ci-dessous sont les méthodes d'instance pour Blob.
Nom
Arguments
size
Type de renvoi
Description
Integer
Renvoie le nombre de caractères du blob. Par exemple :
String myString = 'StringToBlob';
Blob myBlob = Blob.valueof(myString);
Integer size = myBlob.size();
String
toString
Convertit le blob en chaîne.
Pour plus d'informations sur les blobs, reportez-vous à Types de données Primitif à la page 29.
Méthodes Boolean
Les méthodes ci-dessous sont les méthodes statiques pour Boolean.
Nom
Arguments
Type de renvoi
Description
valueOf
String s
Boolean
Convertit la chaîne spécifiée en une valeur booléenne et
renvoie true si la valeur de la chaîne spécifiée est 'true'.
Sinon, renvoie false.
Si l'argument spécifié est null, cette méthode lève une
exception.
Exemple :
Boolean b = Boolean.valueOf('true');
System.assertEquals(true, b);
valueOf
Object fieldValue Boolean
Convertit la valeur de champ de suivi d'historique
spécifiée en une valeur booléenne.
Utilisez cette méthode avec les champs OldValue ou
NewValue de sObjects historiques, tels que
AccountHistory, lorsque le type de champ correspond
à Boolean, par exemple un champ de case à cocher.
Exemple :
List<AccountHistory> ahlist =
[SELECT Field,OldValue,NewValue
FROM AccountHistory];
for(AccountHistory ah : ahlist) {
System.debug('Field: ' + ah.Field);
Référence
Nom
salesforce | Méthodes Primitives Apex | 357
Arguments
Type de renvoi
Description
if (ah.field == 'IsPlatinum__c') {
Boolean oldValue =
Boolean.valueOf(ah.OldValue);
Boolean newValue =
Boolean.valueOf(ah.NewValue);
}
Pour plus d'informations sur le type Boolean, reportez-vous à Types de données Primitive à la page 29.
Méthodes Date
Les méthodes ci-dessous sont les méthodes statiques système pour Date.
Nom
Arguments
Type de renvoi
Description
daysInMonth
Integer year
Integer
Renvoie le nombre de jours du mois de year et month
spécifiés (1=Jan). L'exemple suivant récupère le nombre
de jours du mois de février de l'année 1960 :
Integer month
Integer numberDays =
date.daysInMonth(1960, 2);
isLeapYear
Integer year
Boolean
Renvoie true si year spécifié est une année bissextile.
newInstance
Integer year
Date
Construit une date à partir des représentations d'entier
de year, month (1=Jan) et day. L'exemple suivant crée
la date du 17 février 1960 :
Integer month
Integer date
Date myDate =
date.newinstance(1960, 2, 17);
parse
String Date
Date
Construit une date à partir d'une chaîne. Le format de
la chaîne dépend du format de la date locale. L'exemple
suivant fonctionne dans certains paramètres régionaux :
date mydate = date.parse('12/27/2009');
today
Date
Renvoie la date actuelle dans le fuseau horaire de
l'utilisateur actuel.
Référence
salesforce | Méthodes Primitives Apex | 358
Nom
Arguments
Type de renvoi
Description
valueOf
String s
Date
Renvoie une date qui contient la valeur de la chaîne
spécifiée. La chaîne doit utiliser le format de date
standard « aaaa-MM-jj HH:mm:ss » dans le fuseau
horaire local. Par exemple :
string year = '2008';
string month = '10';
string day = '5';
string hour = '12';
string minute = '20';
string second = '20';
string stringDate = year + '-' + month
+ '-' + day + ' ' + hour + ':' +
minute + ':' + second;
Date myDate = date.valueOf(stringDate);
valueOf
Object fieldValue Date
Convertit la valeur du champ de suivi d'historique
spécifiée en date.
Utilisez cette méthode avec les champs OldValue ou
NewValue de sObjects historiques, tels que
AccountHistory, lorsque le champ est un champ de
date.
Exemple :
List<AccountHistory> ahlist =
[SELECT Field,OldValue,NewValue
FROM AccountHistory];
for(AccountHistory ah : ahlist) {
System.debug('Field: ' + ah.Field);
if (ah.field == 'MyDate__c') {
Date oldValue =
Date.valueOf(ah.OldValue);
Date newValue =
Date.valueOf(ah.NewValue);
Référence
Nom
salesforce | Méthodes Primitives Apex | 359
Arguments
Type de renvoi
Description
}
Les méthodes ci-dessous sont les méthodes d'instance pour Date.
Nom
Arguments
Type de renvoi
Description
addDays
Integer addlDays
Date
Ajoute le nombre spécifié de addlDays à une date. Par
exemple :
date myDate =
date.newInstance(1960, 2, 17);
date newDate = mydate.addDays(2);
addMonths
Integer addlMonths Date
Ajoute le nombre spécifié de addlMonths à une date.
addYears
Integer addlYears
Date
Ajoute le nombre spécifié de addlYears à une date.
day
Integer
Renvoie le composant jour-du-mois d'une date. Par
exemple, 5 février 1999 est jour 5.
dayOfYear
Integer
Renvoie le composant jour-de-l'année d'une date. Par
exemple, 5 février 1999 est jour 36.
Integer
Renvoie le nombre de jours entre la date qui a appelé la
méthode et le compDate. Si la date qui appelle la
méthode se situe après le compDate, la valeur renvoyée
est négative. Par exemple :
daysBetween
Date compDate
date startDate =
date.newInstance(2008, 1, 1);
date dueDate =
date.newInstance(2008, 1, 30);
integer numberDaysDue =
startDate.daysBetween(dueDate);
format
isSameDay
Date compDate
String
Renvoie la date sous forme de chaîne en utilisant les
paramètres régionaux de l'utilisateur actif.
Boolean
Renvoie true si la date qui a appelé la méthode est
identique à compDate. Par exemple :
date myDate = date.today();
date dueDate =
Référence
Nom
salesforce | Méthodes Primitives Apex | 360
Arguments
Type de renvoi
Description
date.newInstance(2008, 1, 30);
boolean dueNow =
myDate.isSameDay(dueDate);
Integer
Renvoie le composant mois d'une date (1=Jan).
Integer
Renvoie le nombre de mois entre la date qui a appelé la
méthode et le compDate. Par exemple, 1er mars et 30
mars de la même année ont 0 mois qui les sépare.
toStartOfMonth
Date
Renvoie le premier du mois de la date qui a appelé la
méthode. Par exemple, 14 juillet 1999 renvoie 1er juillet
1999.
toStartOfWeek
Date
Renvoie le début de la semaine de la date qui a appelé
la méthode, en fonction des paramètres régionaux de
l'utilisateur actif. Par exemple, le début d'une semaine
est dimanche dans les paramètres régionaux des
États-Unis et lundi dans les paramètres régionaux
européens. Par exemple :
month
monthsBetween
Date compDate
date myDate = date.today();
date weekStart = myDate.toStartofWeek();
Integer
year
Renvoie le composant année d'une date
Pour plus d'informations sur le type Date, reportez-vous à Types de données Primitive à la page 29.
Méthodes Datetime
Les méthodes ci-dessous sont les méthodes statiques système pour Datetime.
Nom
Arguments
Type de renvoi
Description
newInstance
Long l
Datetime
Construit une date/heure et l'initialise pour représenter
le nombre de millisecondes spécifié depuis le 1er janvier
1970, 00:00:00 GMT. La date est renvoyée dans le
fuseau horaire GMT.
newInstance
Date Date
Datetime
Construit une date/heure à partir des date et time
spécifiées dans le fuseau horaire local. La date est
renvoyée dans le fuseau horaire GMT.
Datetime
Construit une date/heure à partir des représentations
d'entier year, month (1=Jan) et day à minuit dans le
fuseau horaire local. La date est renvoyée dans le fuseau
horaire GMT.
Time Time
newInstance
Integer year
Integer month
Référence
Nom
salesforce | Méthodes Primitives Apex | 361
Arguments
Type de renvoi
Integer day
Description
Par exemple :
datetime myDate =
datetime.newInstance(2008, 12, 1);
newInstance
Integer year
Datetime
Integer day
Construit une date/heure à partir des représentations
d'entier de year, month (1=Jan), day, hour, minute
et second dans le fuseau horaire local. La date est
renvoyée dans le fuseau horaire GMT.
Integer hour
Par exemple :
Integer month
Integer minute
Datetime myDate =
Integer second
newInstanceGmt
Date date
datetime.newInstance(2008, 12, 1, 12,
30, 2);
Datetime
Construit une date/heure à partir des date et time
spécifiées dans le fuseau horaire GMT.
Datetime
Construit une date/heure à partir des représentations
d'entier de year, month (1=Jan) et day à minuit dans
le fuseau horaire GMT.
Datetime
Construit une date/heure à partir des représentations
d'entier de year, month (1=Jan), day, hour, minute
et second dans le fuseau horaire GMT.
Datetime
Renvoie la date/heure actuelle basée sur un calendrier
GMT.
Time time
newInstanceGmt
Integer year
Integer month
Integer date
newInstanceGmt
Integer year
Integer month
Integer date
Integer hour
Integer minute
Integer second
now
Par exemple :
datetime myDateTime = datetime.now();
Le format de la date/heure renvoyée est le suivant :
'MM/DD/YYYY HH:MM PERIOD'
parse
String datetime
Datetime
Construit une date/heure à partir de la chaîne datetime
dans le fuseau horaire local et en fonction des paramètres
régionaux de l'utilisateur. La date est renvoyée dans le
fuseau horaire GMT.
Référence
Nom
salesforce | Méthodes Primitives Apex | 362
Arguments
Type de renvoi
Description
Cet exemple utilise parse pour créer une date/heure à
partir d'une date passée sous forme de chaîne et mise en
forme pour les paramètres régionaux Anglais
(États-Unis). Vous devez modifier le format de la chaîne
de date si vous avez des paramètres régionaux différents.
Datetime dt = DateTime.parse(
'10/14/2011 11:46 AM');
String myDtString = dt.format();
system.assertEquals(
myDtString,
'10/14/2011 11:46 AM');
valueOf
String s
Datetime
Renvoie une date/heure qui contient la valeur de la
chaîne spécifiée. La chaîne doit utiliser le format de date
standard « aaaa-MM-jj HH:mm:ss » dans le fuseau
horaire local. La date est renvoyée dans le fuseau horaire
GMT.
Par exemple :
string year = '2008';
string month = '10';
string day = '5';
string hour = '12';
string minute = '20';
string second = '20';
string stringDate = year + '-' + month
+ '-' + day + ' ' + hour + ':' +
minute +
':' + second;
Datetime myDate =
datetime.valueOf(stringDate);
valueOf
Object fieldValue Datetime
Convertit la valeur du champ de suivi d'historique
spécifiée en date/heure.
Utilisez cette méthode avec les champs OldValue ou
NewValue de sObjects historiques, tels que
Référence
Nom
salesforce | Méthodes Primitives Apex | 363
Arguments
Type de renvoi
Description
AccountHistory, lorsque le champ est un champ de
date/heure.
Exemple :
List<AccountHistory> ahlist =
[SELECT Field,OldValue,NewValue
FROM AccountHistory];
for(AccountHistory ah : ahlist) {
System.debug('Field: ' + ah.Field);
if (ah.field == 'MyDatetime__c') {
Datetime oldValue =
Datetime.valueOf(ah.OldValue);
Datetime newValue =
Datetime.valueOf(ah.NewValue);
}
valueOfGmt
String s
Datetime
Renvoie une date/heure qui contient la valeur de la
chaîne spécifiée. La chaîne doit utiliser le format de date
standard « aaaa-MM-jj HH:mm:ss » dans le fuseau
horaire GMT.
Les méthodes ci-dessous sont les méthodes d'instance pour Datetime.
Nom
Arguments
Type de
renvoi
Description
addDays
Integer addlDays
Datetime
Ajoute le nombre spécifié de addlDays à une date/heure. Par
exemple :
datetime myDate =
datetime.newInstance
(1960, 2, 17);
datetime newDate = mydate.addDays(2);
addHours
Integer addlHours
Datetime
addMinutes
Integer addlMinutes Datetime
Ajoute le nombre spécifié de addlMinutes à une date/heure.
addMonths
Integer addlMonths
Ajoute le nombre spécifié de addlMonths à une date/heure.
Datetime
Ajoute le nombre spécifié de addlHours à une date/heure.
Référence
salesforce | Méthodes Primitives Apex | 364
Nom
Arguments
Type de
renvoi
Description
addSeconds
Integer addlSeconds Datetime
Ajoute le nombre spécifié de addlSeconds à une date/heure.
addYears
Integer addlYears
Datetime
Ajoute le nombre spécifié de addlYears à une date/heure.
date
Date
Renvoie le composant date d'une date/heure dans le fuseau
horaire local de l'utilisateur actif.
dateGMT
Date
Renvoie le composant date d'une date/heure dans le fuseau
horaire GMT.
day
Integer
Renvoie le composant date-du-mois d'une date/heure dans le
fuseau horaire local de l'utilisateur actif. Par exemple, 5 février
1999 08:30:12 est jour 5.
dayGmt
Integer
Renvoie le composant date-du-mois d'une date/heure dans le
fuseau horaire GMT. Par exemple, 5 février 1999 08:30:12
est jour 5.
dayOfYear
Integer
Renvoie le composant date-de-l'année d'une date/heure dans
le fuseau horaire local de l'utilisateur actif. Par exemple, le 5
février 2008 08:30:12 est jour 36.
Datetime myDate =
datetime.newInstance
(2008, 2, 5, 8, 30, 12);
system.assertEquals
(myDate.dayOfYear(), 36);
dayOfYearGmt
Integer
Renvoie le composant date-de-l'année d'une date/heure dans
le fuseau horaire GMT. Par exemple, 5 février 1999 08:30:12
est jour 36.
format
String
Convertit la date dans le fuseau horaire local et renvoie la date
convertie sous forme de chaîne mise en forme en utilisant les
paramètres régionaux de l'utilisateur actif. Si le fuseau horaire
ne peut pas être déterminé, GMT est utilisé.
String
Convertit la date dans le fuseau horaire local et renvoie la date
convertie sous forme de chaîne mise en forme en utilisant le
format de date simple Java fourni. Si le fuseau horaire ne peut
pas être déterminé, GMT est utilisé. Par exemple :
format
String dateFormat
Datetime myDT = Datetime.now();
String myDate = myDT.format('h:mm a');
Pour plus d'informations sur le format de date simple Java,
reportez-vous à Java SimpleDateFormat.
Référence
salesforce | Méthodes Primitives Apex | 365
Nom
Arguments
Type de
renvoi
Description
format
String dateFormat
String
Convertit la date dans le fuseau horaire spécifié et renvoie la
date convertie sous forme de chaîne mise en forme en utilisant
le format de date simple Java fourni. Si le format du fuseau
horaire fourni est incorrect, GMT est utilisé.
String timezone
Pour plus d'informations sur le format de date simple Java,
reportez-vous à Java SimpleDateFormat.
Les valeurs de fuseau horaire correctes pour l'argument
timezone sont les fuseaux horaires de la classe Java TimeZone
qui correspondent aux fuseaux horaires renvoyés par la méthode
TimeZone.getAvailableIDs dans Java. Nous recommandons
d'utiliser les noms de fuseau horaire complets, pas les
abréviations en trois lettres.
Cet exemple utilise format pour convertir une date GMT
en fuseau horaire Amérique/New_York, et met en forme la
date en utilisant le format de date spécifié.
Datetime GMTDate =
Datetime.newInstanceGmt(2011,6,1,12,1,5);
String strConvertedDate =
GMTDate.format('MM/dd/yyyy HH:mm:ss',
'America/New_York');
// Date is converted to
// the new time zone and is adjusted
// for daylight saving time.
System.assertEquals(
'06/01/2011 08:01:05', strConvertedDate);
formatGmt
StringdateFormat
String
Renvoie une date/heure sous forme de chaîne en utilisant le
format de date simple Java fourni et le fuseau horaire GMT.
Pour plus d'informations sur le format de date simple Java,
reportez-vous à Java SimpleDateFormat.
formatLong
String
Convertit la date dans le fuseau horaire local et renvoie la date
convertie sous le format de date longue.
Par exemple :
// Passing local date based on the PST
//
time zone
Référence
Nom
salesforce | Méthodes Primitives Apex | 366
Arguments
Type de
renvoi
Description
Datetime dt = DateTime.newInstance(
2012,12,28,10,0,0);
// Writes 12/28/2012 10:00:00 AM PST
System.debug('dt.formatLong()='
+ dt.formatLong());
getTime
Long
Renvoie le nombre de millisecondes depuis le 1er janvier 1970,
00:00:00 GMT représenté par cet objet Date/heure.
hour
Integer
Renvoie le composant heure d'une date/heure dans le fuseau
horaire local de l'utilisateur actif.
hourGmt
Integer
Renvoie le composant heure d'une date/heure dans le fuseau
horaire GMT.
Boolean
Renvoie true si la date/heure qui a appelé la méthode est
identique à compDt dans le fuseau horaire local de l'utilisateur
actif. Par exemple :
isSameDay
Datetime compDt
datetime myDate = datetime.now();
datetime dueDate =
datetime.newInstance(2008, 1, 30);
boolean dueNow = myDate.isSameDay(dueDate);
millisecond
Integer
Renvoie le composant milliseconde d'une date/heure dans le
fuseau horaire local de l'utilisateur actif.
millisecondGmt
Integer
Renvoie le composant milliseconde d'une date/heure dans le
fuseau horaire GMT.
minute
Integer
Renvoie le composant minute d'une date/heure dans le fuseau
horaire local de l'utilisateur actif.
minuteGmt
Integer
Renvoie le composant minute d'une date/heure dans le fuseau
horaire GMT.
month
Integer
Renvoie le composant mois d'une date/heure dans le fuseau
horaire local de l'utilisateur actif (1=Jan).
monthGmt
Integer
Renvoie le composant mois d'une date/heure dans le fuseau
horaire GMT (1=Jan).
second
Integer
Renvoie le composant seconde d'une date/heure dans le fuseau
horaire local de l'utilisateur actif.
Référence
Nom
salesforce | Méthodes Primitives Apex | 367
Arguments
Type de
renvoi
Description
secondGmt
Integer
Renvoie le composant seconde d'une date/heure dans le fuseau
horaire GMT.
time
Time
Renvoie le composant heure d'une date/heure dans le fuseau
horaire local de l'utilisateur actif.
timeGmt
Time
Renvoie le composant heure d'une date/heure dans le fuseau
horaire GMT.
year
Integer
Renvoie le composant année d'une date/heure dans le fuseau
horaire local de l'utilisateur actif.
yearGmt
Integer
Renvoie le composant année d'une date/heure dans le fuseau
horaire GMT.
Pour plus d'informations sur Datetime, reportez-vous à Types de données Primitive à la page 29.
Méthodes Decimal
Les méthodes ci-dessous sont les méthodes statiques système pour Decimal.
Nom
Arguments
Type de renvoi
Description
valueOf
Double d
Decimal
Renvoie une décimale qui contient la valeur de la double
spécifiée.
valueOf
Long l
Decimal
Renvoie une décimale qui contient la valeur de la
longueur spécifiée.
valueOf
String s
Decimal
Renvoie une décimale qui contient la valeur de la chaîne
spécifiée. Comme dans Java, la chaîne est interprétée en
tant que décimale signée. Par exemple :
String temp = '12.4567';
Decimal myDecimal =
decimal.valueOf(temp);
Les méthodes ci-dessous sont les méthodes d'instance pour Decimal.
Nom
Arguments
abs
divide
Decimal divisor,
Integer scale
Type de renvoi
Description
Decimal
Renvoie la valeur absolue de la décimale.
Decimal
Divise cette décimale par divisor et définit l'échelle,
c.-à-d. le nombre de décimales du résultat, en utilisant
Référence
Nom
salesforce | Méthodes Primitives Apex | 368
Arguments
Type de renvoi
Description
scale. Dans l'exemple suivant, D a la valeur de 0.190
:
Decimal D = 19;
D.Divide(100, 3);
divide
Decimal divisor,
Integer scale,
Object
Decimal
roundingMode
Divise cette décimale par divisor, définit l'échelle,
c.-à-d. le nombre de décimales du résultat, en utilisant
scale et, si nécessaire, arrondi la valeur en utilisant
roundingMode. Pour plus d'informations sur les valeurs
valides pour roundingMode, reportez-vous à Mode
d'arrondi. Par exemple :
Decimal myDecimal = 12.4567;
Decimal divDec = myDecimal.divide
(7, 2, System.RoundingMode.UP);
system.assertEquals(divDec, 1.78);
doubleValue
Double
Renvoie la valeur double de cette décimale.
format
String
Renvoie la valeur de chaîne de cette décimale en utilisant
les paramètres régionaux de l'utilisateur contextuel.
La notation scientifique est utilisée si un exposant est
requis.
intValue
Integer
Renvoie la valeur de l'entier de cette décimale.
longValue
Long
Renvoie la valeur de longueur de cette décimale.
Decimal
Renvoie la valeur de cette décimale élevée à la puissance
de exponent. La valeur de exponent doit être comprise
entre 0 and 32 767. Par exemple :
pow
Integer exponent
Decimal myDecimal = 4.12;
Decimal powDec = myDecimal.pow(2);
system.assertEquals(powDec, 16.9744);
Référence
Nom
salesforce | Méthodes Primitives Apex | 369
Arguments
Type de renvoi
Description
Si vous utilisez MyDecimal.pow(0), 1 est renvoyé.
La Méthode Math pow n'accepte pas les valeurs
négatives.
precision
Integer
Renvoie le nombre total de chiffres de la décimale. Par
exemple, si la valeur de la décimale est 123,45,
precision renvoie 5. Si la valeur de la décimale est
123,123, precision renvoie 6. Par exemple :
Decimal D1 = 123.45;
Integer precision1 = D1.precision();
system.assertEquals(precision1, 5);
Decimal D2 = 123.123;
Integer precision2 = D2.precision();
system.assertEquals(precision2, 6);
round
Long
Renvoie l'approximation arrondie de cette décimale. Le
chiffre est arrondi à zéro décimale en utilisant le mode
d'arrondi au dixième supérieur, c.-à-d. qu'il arrondit au
« plus proche voisin », sauf si les deux voisins sont
équidistants, auquel cas ce mode arrondit au voisin pair.
Notez que statistiquement ce mode d'arrondi réduit les
erreurs cumulées lorsqu'il est régulièrement appliqué
dans une séquence de calculs. Pour plus d'informations
sur le mode d'arrondi au dixième supérieur, reportez-vous
à Mode d'arrondi. Par exemple :
Decimal D1 = 5.5;
Long L1 = D1.round();
system.assertEquals(L1, 6);
Référence
Nom
salesforce | Méthodes Primitives Apex | 370
Arguments
Type de renvoi
Description
Decimal D2= 5.2;
Long L2= D2.round();
system.assertEquals(L2, 5);
Decimal D3= -5.7;
Long L3= D3.round();
system.assertEquals(L3, -6);
round
System.RoundingMode Long
roundingMode
scale
setScale
Integer scale
Renvoie l'approximation arrondie de cette décimale. Le
nombre est arrondi à zéro décimale en utilisant le mode
d'arrondi spécifié par roundingMode. Pour plus
d'informations sur les valeurs valides pour
roundingMode, reportez-vous à Mode d'arrondi.
Integer
Renvoie l'échelle de la décimale, c.-à-d. le nombre de
décimales.
Decimal
Définit l'échelle de la décimale du nombre donné de
décimales à l'aide de l'arrondi au dixième supérieur, si
nécessaire. Le mode d'arrondi au dixième supérieur
arrondit au « plus proche voisin », sauf si les deux voisins
sont équidistants, auquel cas ce mode arrondit au voisin
pair. Pour plus d'informations sur le mode d'arrondi au
dixième supérieur, reportez-vous à Mode d'arrondi. La
valeur de scale doit être comprise entre -33 and 33.
Si vous ne définissez pas explicitement l'échelle d'une
décimale, elle est déterminée par l'élément à partir duquel
la décimale est créée :
Référence
Nom
salesforce | Méthodes Primitives Apex | 371
Arguments
Type de renvoi
Description
•
•
•
setScale
Integer scale,
Decimal
System.RoundingMode
roundingMode
Si la décimale est créée dans le cadre d'une requête,
l'échelle est basée sur l'échelle du champ renvoyé
depuis la requête.
Si la décimale est créée depuis une chaîne, l'échelle
est le nombre de caractères après le point décimal de
la chaîne.
Si la décimale est créée à partir d'un nombre
non-décimal, l'échelle est déterminée en convertissant
le nombre en chaîne, puis en utilisant le nombre de
caractères après le point décimal.
Définit l'échelle de la décimale du nombre donné de
décimales, en utilisant le mode d'arrondi spécifié par
roundingMode, si nécessaire. Pour plus d'informations
sur les valeurs valides pour roundingMode,
reportez-vous à Mode d'arrondi. La valeur de scale
doit être comprise entre -32 768 and 32 767.
Si vous ne définissez pas explicitement l'échelle d'une
décimale, elle est déterminée par l'élément à partir duquel
la décimale est créée :
•
•
•
Si la décimale est créée dans le cadre d'une requête,
l'échelle est basée sur l'échelle du champ renvoyé
depuis la requête.
Si la décimale est créée depuis une chaîne, l'échelle
est le nombre de caractères après le point décimal de
la chaîne.
Si la décimale est créée à partir d'un nombre
non-décimal, l'échelle est déterminée en convertissant
le nombre en chaîne, puis en utilisant le nombre de
caractères après le point décimal.
stripTrailingZeros
Decimal
Renvoie la décimale avec tous les zéros de fin supprimés.
toPlainString
String
Renvoie la valeur de chaîne de cette décimale, sans
utiliser la notation scientifique.
Pour plus d'informations sur la décimale, reportez-vous à Types de données Primitive à la page 29.
Mode d'arrondi
Le mode d'arrondi spécifie le comportement de l'arrondi des opérations numériques capables d'ignorer la précision. Chaque
mode d'arrondi indique comment le chiffre renvoyé le moins significatif d'un résultat arrondi doit être calculé. Les valeurs
valides sont les suivantes pour roundingMode.
Référence
salesforce | Méthodes Primitives Apex | 372
Nom
Description
CEILING
Arrondit à l'infini positif. Si le résultat est positif, ce mode se comporte comme le mode
d'arrondi UP. Si le résultat est négatif, il se comporte comme le mode d'arrondi DOWN.
Notez que ce mode d'arrondi ne diminue jamais la valeur calculée. Par exemple :
• Nombre saisi 5,5 : résultat du mode d'arrondi CEILING : 6
• Nombre saisi 1,1 : résultat du mode d'arrondi CEILING : 2
• Nombre saisi -1,1 : résultat du mode d'arrondi CEILING : -1
• Nombre saisi -2,7 : résultat du mode d'arrondi CEILING : -2
DOWN
Arrondit à zéro. Ce mode d'arrondi diminue toujours les fractions (point décimal) avant
l'exécution. Notez que ce mode d'arrondi n'augmente jamais la magnitude de la valeur
calculée. Par exemple :
• Nombre saisi 5,5 : résultat du mode d'arrondi DOWN : 5
• Nombre saisi 1,1 : résultat du mode d'arrondi DOWN : 1
• Nombre saisi -1,1 : résultat du mode d'arrondi DOWN : -1
• Nombre saisi -2,7 : résultat du mode d'arrondi DOWN : -2
FLOOR
Arrondit à l'infini négatif. Si le résultat est positif, ce mode se comporte comme le mode
d'arrondi DOWN. S'il est négatif, il se comporte comme le mode d'arrondi UP. Notez que
ce mode d'arrondi n'augmente jamais la valeur calculée. Par exemple :
• Nombre saisi 5,5 : résultat du mode d'arrondi FLOOR : 5
• Nombre saisi 1,1 : résultat du mode d'arrondi FLOOR : 1
• Nombre saisi -1,1 : résultat du mode d'arrondi FLOOR : -2
• Nombre saisi -2,7 : résultat du mode d'arrondi FLOOR : -3
HALF_DOWN
Arrondit au « plus proche voisin », sauf si les deux voisins sont équidistants, auquel cas ce
mode arrondit à un nombre inférieur. Ce mode d'arrondi se comporte comme le mode
d'arrondi UP si la fraction ignorée (point décimal) est > 0,5, sinon il se comporte comme
le mode d'arrondi DOWN. Par exemple :
• Nombre saisi 5,5 : résultat du mode d'arrondi HALF_DOWN : 5
• Nombre saisi 1,1 : résultat du mode d'arrondi HALF_DOWN : 1
• Nombre saisi -1,1 : résultat du mode d'arrondi HALF_DOWN : -1
• Nombre saisi -2,7 : résultat du mode d'arrondi HALF_DOWN : -2
HALF_EVEN
Arrondit au « plus proche voisin », sauf si les deux voisins sont équidistants, auquel cas ce
mode arrondit au voisin pair. Ce mode d'arrondi se comporte comme le mode d'arrondi
HALF_UP si le chiffre de gauche de la fraction ignorée (virgule) est impair. Il se comporte
comme le mode d'arrondi HALF_DOWN s'il est pair. Par exemple :
• Nombre saisi 5,5 : résultat du mode d'arrondi HALF_EVEN : 6
• Nombre saisi 1,1 : résultat du mode d'arrondi HALF_EVEN : 1
• Nombre saisi -1,1 : résultat du mode d'arrondi HALF_EVEN : -1
• Nombre saisi -2,7 : résultat du mode d'arrondi HALF_EVEN : -3
Notez que statistiquement ce mode d'arrondi réduit les erreurs cumulées lorsqu'il est
régulièrement appliqué dans une séquence de calculs.
HALF_UP
Arrondit au « plus proche voisin » sauf si les deux voisins sont équidistants, auquel cas ce
mode arrondit à un nombre supérieur. Cette méthode d'arrondi se comporte comme la
Référence
salesforce | Méthodes Primitives Apex | 373
Nom
Description
méthode d'arrondi UP si la fraction ignorée (virgule) est >= 0,5, sinon elle se comporte
comme la méthode d'arrondi DOWN. Par exemple :
• Nombre saisi 5,5 : résultat du mode d'arrondi HALF_UP : 6
• Nombre saisi 1,1 : résultat du mode d'arrondi HALF_UP : 1
• Nombre saisi -1,1 : résultat du mode d'arrondi HALF_UP : -1
• Nombre saisi -2,7 : résultat du mode d'arrondi HALF_UP : -3
UNNECESSARY
Affirme que l'opération demandée a un résultat exact, ce qui signifie qu'aucun arrondi
n'est nécessaire. Si ce mode d'arrondi est spécifié dans une opération qui génère un résultat
inexact, une exception est levée. Par exemple :
• Nombre saisi 5,5 : résultat du mode d'arrondi UNNECESSARY : Exception
• Nombre saisi 1,0 : résultat du mode d'arrondi UNNECESSARY : 1
UP
Arrondit en s'écartant de zéro. Ce mode d'arrondi tronque toujours les fractions (point
décimal) avant l'exécution. Notez que ce mode d'arrondi ne diminue jamais la magnitude
de la valeur calculée. Par exemple :
• Nombre saisi 5,5 : résultat du mode d'arrondi UP : 6
• Nombre saisi 1,1 : résultat du mode d'arrondi UP : 2
• Nombre saisi -1,1 : résultat du mode d'arrondi UP : -2
• Nombre saisi -2,7 : résultat du mode d'arrondi UP : -3
Méthodes Double
Les méthodes ci-dessous sont les méthodes statiques système pour Double.
Nom
Arguments
Type de renvoi Description
valueOf
String s
Double
Renvoie une double qui contient la valeur de la chaîne spécifiée.
Comme dans Java, la chaîne est interprétée en tant que
décimale signée. Par exemple :
Double DD1 = double.valueOf('3.14159');
valueOf
Object fieldValue Double
Convertit la valeur du champ de suivi d'historique spécifiée en
une valeur double.
Utilisez cette méthode avec les champs OldValue ou
NewValue de sObjects historiques, tels que
AccountHistory, lorsque le type de champ correspond à un
type Double, par exemple un champ numérique.
Exemple :
List<AccountHistory> ahlist =
[SELECT Field,OldValue,NewValue
Référence
Nom
salesforce | Méthodes Primitives Apex | 374
Arguments
Type de renvoi Description
FROM AccountHistory];
for(AccountHistory ah : ahlist) {
System.debug('Field: ' + ah.Field);
if (ah.field == 'NumberOfEmployees') {
Double oldValue =
Double.valueOf(ah.OldValue);
Double newValue =
Double.valueOf(ah.NewValue);
}
Les méthodes ci-dessous sont les méthodes d'instance pour Double.
Nom
Arguments
Type de renvoi
Description
format
String
Renvoie la valeur de chaîne pour cette double en utilisant
les paramètres régionaux de l'utilisateur actif.
intValue
Integer
Renvoie la valeur de nombre entier de cette double la
convertissant en nombre entier. Par exemple :
Double DD1 = double.valueOf('3.14159');
Integer value = DD1.intValue();
system.assertEquals(value, 3);
longValue
Long
Renvoie la valeur de longueur de cette double.
round
Long
Renvoie la valeur arrondie de cette double. Le chiffre
est arrondi à zéro décimale en utilisant le mode d'arrondi
au dixième supérieur, c.-à-d. qu'il arrondit au « plus
proche voisin », sauf si les deux voisins sont équidistants,
auquel cas ce mode arrondit au voisin pair. Notez que
statistiquement ce mode d'arrondi réduit les erreurs
cumulées lorsqu'il est régulièrement appliqué dans une
séquence de calculs. Pour plus d'informations sur le mode
d'arrondi au dixième supérieur, reportez-vous à Mode
d'arrondi. Par exemple :
Double D1 = 5.5;
Long L1 = D1.round();
system.assertEquals(L1, 6);
Référence
Nom
salesforce | Méthodes Primitives Apex | 375
Arguments
Type de renvoi
Description
Double D2= 5.2;
Long L2= D2.round();
system.assertEquals(L2, 5);
Double D3= -5.7;
Long L3= D3.round();
system.assertEquals(L3, -6);
Pour plus d'informations sur le type Double, reportez-vous à Types de données Primitive à la page 29.
Méthodes ID
Les méthodes suivantes sont les méthodes statiques pour ID.
Méthode
Arguments
Type de renvoi
Description
valueOf
String s
ID
Convertit la chaîne spécifiée en ID et
renvoie l'ID.
Les méthodes suivantes sont les méthodes d'instance pour ID.
Méthode
Arguments
addError
String errorMsg
Type de renvoi
Description
Marque un enregistrement avec un message
d'erreur personnalisé et empêche toute
opération DML de se produire.
L'argument errorMsg est le message
d'erreur avec lequel marquer
l'enregistrement.
Cette méthode est similaire à la méthode de
sObject addError.
addError
Exception exception
Marque un enregistrement avec un message
d'erreur personnalisé et empêche toute
opération DML de se produire.
L'argument exception est un objet
Exception ou un objet d'exception
personnalisé contenant le message d'erreur
avec lequel marquer l'enregistrement.
Cette méthode est similaire à la méthode de
sObject addError.
Référence
salesforce | Méthodes Primitives Apex | 376
Méthode
Arguments
getSObjectType
Type de renvoi
Description
Schema.SObjectType
Renvoie le jeton du sObject correspondant
à cet ID. Cette méthode est utilisée
principalement avec des informations de
description.
Pour plus d'informations sur l'information
describe, reportez-vous à Compréhension
de l'information Describe Apex.
Pour un exemple, reportez-vous à Exemple
: Obtention d'un jeton de sObject à partir
d'un ID.
Exemple : Obtention d'un jeton de sObject à partir d'un ID
Cet exemple montre comment utiliser la méthode getSObjectType pour obtenir un jeton de sObject à partir d'un ID. La
méthode updateOwner dans cet exemple accepte une liste d'ID de sObjects pour mettre à jour le champ ID de propriétaire
(ownerId). Cette liste contient les ID de sObjects de même type. Le deuxième paramètre est le nouvel ID du propriétaire.
Notez qu'il s'agit d'une méthode future, par conséquent, elle n'accepte pas les types de sObject en tant que paramètres. Elle
accepte les ID de sObjects. Cette méthode obtient le jeton de sObject à partir du premier ID de la liste, exécute describe pour
obtenir le nom d'objet, puis construit une requête de façon dynamique. Elle demande ensuite tous les sObjects et met à jour
leur champ ID de propriétaire avec le nouvel ID de propriétaire.
public class MyDynamicSolution {
@future
public static void updateOwner(List<ID> objIds, ID newOwnerId) {
// Validate input
System.assert(objIds != null);
System.assert(objIds.size() > 0);
System.assert(newOwnerId != null);
// Get the sObject token from the first ID
// (the List contains IDs of sObjects of the same type).
Schema.SObjectType token = objIds[0].getSObjectType();
// Using the token, do a describe
// and construct a query dynamically.
Schema.DescribeSObjectResult dr = token.getDescribe();
String queryString = 'SELECT ownerId FROM ' + dr.getName() +
' WHERE ';
for(ID objId : objIds) {
Référence
salesforce | Méthodes Primitives Apex | 377
queryString += 'Id=\'' + objId + '\' OR ';
}
// Remove the last ' OR'
queryString = queryString.subString(0, queryString.length() - 4);
sObject[] objDBList = Database.query(queryString);
System.assert(objDBList.size() > 0);
// Update the owner ID on the sObjects
for(Integer i=0;i<objDBList.size();i++) {
objDBList[i].put('ownerId', newOwnerId);
}
Database.SaveResult[] srList = Database.update(objDBList, false);
for(Database.SaveResult sr : srList) {
if (sr.isSuccess()) {
System.debug('Updated owner ID successfully for ' +
dr.getName() + ' ID ' + sr.getId());
}
else {
System.debug('Updating ' + dr.getName() + ' returned the following errors.');
for(Database.Error e : sr.getErrors()) {
System.debug(e.getMessage());
}
}
}
}
}
Méthodes Integer
Les méthodes ci-dessous sont les méthodes statiques système pour Integer.
Référence
salesforce | Méthodes Primitives Apex | 378
Nom
Arguments
Type de
renvoi
Description
valueOf
String s
Integer
Renvoie un nombre entier qui contient la valeur de la chaîne
spécifiée. Comme dans Java, la chaîne est interprétée en tant
que nombre entier décimal signé. Par exemple :
Integer myInt = integer.valueOf('123');
valueOf
Object fieldValue Integer
Convertit la valeur du champ de suivi d'historique spécifiée en
nombre entier.
Utilisez cette méthode avec les champs OldValue ou NewValue
de sObjects historiques, tels que AccountHistory, lorsque le
type correspond à Integer, tel qu'un champ numérique.
Exemple :
List<AccountHistory> ahlist =
[SELECT Field,OldValue,NewValue
FROM AccountHistory];
for(AccountHistory ah : ahlist) {
System.debug('Field: ' + ah.Field);
if (ah.field == 'NumberOfEmployees') {
Integer oldValue =
Integer.valueOf(ah.OldValue);
Integer newValue =
Integer.valueOf(ah.NewValue);
}
Les méthodes ci-dessous sont les méthodes d'instance pour Integer.
Nom
format
Arguments
Type de renvoi
Description
String
Renvoie le nombre entier sous forme de chaîne en
utilisant les paramètres régionaux de l'utilisateur actif
Pour plus d'informations sur le type Integer, reportez-vous à Types de données Primitive à la page 29.
Méthodes Long
La méthode ci-dessous est la méthode statique système pour Long.
Référence
salesforce | Méthodes Primitives Apex | 379
Nom
Arguments
Type de renvoi
Description
valueOf
String s
Long
Renvoie une longueur qui contient la valeur de la chaîne
spécifiée. Comme dans Java, la chaîne est interprétée en
tant que longueur de décimale signée. Par exemple :
Long L1 = long.valueOf('123456789');
Les méthodes ci-dessous sont les méthodes d'instance pour Long.
Nom
Arguments
Type de renvoi
Description
format
String
Renvoie le format de chaîne pour cette longueur en
utilisant les paramètres régionaux de l'utilisateur actif.
intValue
Integer
Renvoie la valeur de nombre entier pour cette longueur.
Pour plus d'informations sur le type Long, reportez-vous à Types de données Primitive à la page 29.
Méthodes String
Les méthodes ci-dessous sont les méthodes statiques système pour une chaîne.
Nom
Type de renvoi
Description
escapeSingleQuotes String s
String
Renvoie une chaîne avec le caractère d'échappement (\)
ajouté avant tous les guillemets simples dans la chaîne
s. Cette méthode est utile lors de la création d'une
instruction SOQL dynamique, afin d'éviter une injection
SOQL. Pour plus d'informations sur SOQL dynamique,
reportez-vous à SOQL dynamique. Reportez-vous
également à Exemple de fractionnement de chaîne.
String s
String
Traite la chaîne actuelle en tant que modèle pouvant être
utilisé pour une substitution de la même façon que
apex:outputText.
String
Renvoie une chaîne à partir des valeurs de la liste de
nombres entiers.
String
Renvoie une séquence initiale de caractères sous forme
de chaîne qui est commune à toutes les chaînes spécifiées.
format
Arguments
List<String>
arguments
fromCharArray
List<Integer>
charArray
getCommonPrefix List<String>
strings
Exemple :
List<String> ls =
new List<String>
{'SFDCApex',
Référence
Nom
salesforce | Méthodes Primitives Apex | 380
Arguments
Type de renvoi
Description
'SFDCVisualforce'};
String prefix =
String.getCommonPrefix(
ls);
System.assertEquals(
'SFDC', prefix);
isBlank
String s
Boolean
Renvoie true si la chaîne spécifiée est un espace blanc,
vide ('') ou null, sinon renvoie false.
isEmpty
String s
Boolean
Renvoie true si la chaîne spécifiée est vide ('') ou null,
sinon renvoie false.
isNotBlank
String s
Boolean
Renvoie true si la chaîne spécifiée n'est pas un espace,
n'est pas vide ('') et n'est pas null, sinon renvoie false.
isNotEmpty
String s
Boolean
Renvoie true si la chaîne spécifiée n'est pas vide ('') et
n'est pas null, sinon renvoie false.
join
Object
String
Joint les éléments de l'objet itérable spécifié, tel qu'une
liste, dans une chaîne unique séparée par le délimiteur
spécifié.
iterableObj
String separator
Exemple :
List<Integer> li = new
List<Integer>
{10, 20, 30};
String s = String.join(
li, '/');
System.assertEquals(
'10/20/30', s);
valueOf
Date d
String
Renvoie une chaîne qui représente la date spécifiée sous
format standard « aaaa-MM-jj ». Par exemple :
Date myDate = Date.Today();
String sDate = String.valueOf(myDate);
valueOf
Datetime dt
String
Renvoie une chaîne qui représente la date/heure spécifiée
sous format standard « aaaa-MM-jj HH:mm:ss » dans
le fuseau horaire local.
Référence
salesforce | Méthodes Primitives Apex | 381
Nom
Arguments
Type de renvoi
Description
valueOf
Decimal d
String
Renvoie une chaîne qui représente la décimale spécifiée.
valueOf
Double d
String
Renvoie une chaîne qui représente le double spécifié.
Exemple :
Double myDouble = 12.34;
String myString =
String.valueOf(myDouble);
System.assertEquals(
'12.34', myString);
valueOf
Integer I
String
Renvoie une chaîne qui représente le nombre entier
spécifié.
valueOf
Long l
String
Renvoie une chaîne qui représente la longueur spécifiée.
valueOf
Object x
String
Renvoie une représentation de chaîne de l'argument
d'objet spécifié.
Exemple :
List<Integer> ls =
new List<Integer>();
ls.add(10);
ls.add(20);
String strList =
String.valueOf(ls);
System.assertEquals(
'(10, 20)', strList);
Si l'argument n'est pas une chaîne, la méthode valueOf
le convertit en chaîne en appelant la méthode toString
dans l'argument, si disponible, ou toute méthode
toString remplacée si l'argument est un type défini
par l'utilisateur. Sinon, si aucune méthode toString
n'est disponible, elle renvoie une représentation de chaîne
de l'argument.
valueOfGmt
Datetime dt
String
Renvoie une chaîne qui représente la date/heure spécifiée
sous format standard « aaaa-MM-jj HH:mm:ss » dans
le fuseau horaire GMT.
Référence
salesforce | Méthodes Primitives Apex | 382
Les méthodes ci-dessous sont les méthodes d'instance pour une chaîne.
Nom
Arguments
Type de renvoi
Description
abbreviate
Integer maxWidth
String
Renvoie une version abrégée de la chaîne, de la longueur
spécifiée et avec des ellipses ajoutées si la chaîne actuelle
est plus longue que la longueur spécifiée, sinon renvoie
la chaîne d'origine sans ellipse.
Si maxWidth est inférieur à quatre, cette méthode lève
une exception d'exécution.
Exemple :
String s = 'Hello Maximillian';
String s2 =
s.abbreviate(8);
System.assertEquals(
'Hello...', s2);
System.assertEquals(
8, s2.length());
abbreviate
Integer maxWidth
Integer offset
String
Renvoie une version abrégée de la chaîne en commençant
par le décalage de caractère spécifié et de la longueur
spécifiée. Des ellipses sont ajoutées à la chaîne renvoyée,
au début et à la fin si des caractères ont été supprimés à
ces emplacements.
Notez que le décalage n'est pas obligatoirement le
caractère le plus à gauche de la chaîne renvoyée ou le
premier caractère qui suit les ellipses, mais il figure
quelque part dans le résultat. Dans tous les cas,
abbreviate ne renvoie pas une chaîne de longueur
supérieure à maxWidth.
Si maxWidth est trop petit, cette méthode lève une
exception d'exécution.
Cette méthode est basée sur son équivalent abbreviate
dans la bibliothèque Apache Commons Lang
StringUtils.
Exemple :
String s =
'Hello Maximillian';
// Start at M
String s2 =
Référence
Nom
salesforce | Méthodes Primitives Apex | 383
Arguments
Type de renvoi
Description
s.abbreviate(9,6);
System.assertEquals(
'...Max...', s2);
System.assertEquals(
9, s2.length());
String
capitalize
Renvoie la chaîne actuelle avec la première lettre
modifiée en initiale majuscule, comme la méthode Java
Character.toTitleCase(char).
Exemple :
String s =
'hello maximillian';
String s2 =
s.capitalize();
System.assertEquals(
'Hello maximillian',
s2);
center
Integer size
String
Renvoie une version de la chaîne actuelle de la taille
spécifiée, remplie avec des espaces à gauche et à droite
pour figurer au centre. Si la taille spécifiée est plus petite
que la taille de la chaîne actuelle, la chaîne entière est
renvoyée sans espaces ajoutés.
Exemple :
String s = 'hello';
String s2 =
s.center(9);
System.assertEquals(
'
hello
',
s2);
center
Integer size
String padStr
String
Renvoie une version de la chaîne actuelle à la taille
spécifiée, remplie avec la chaîne spécifiée à gauche et à
droite pour figurer au centre. Si la taille spécifiée est plus
Référence
Nom
salesforce | Méthodes Primitives Apex | 384
Arguments
Type de renvoi
Description
petite que la taille de la chaîne actuelle, la chaîne entière
est renvoyée sans remplissage.
Exemple :
String s = 'hello';
String s2 =
s.center(9);
System.assertEquals(
'--hello--',
s2);
compareTo
String compString Integer
Compare deux chaînes d'un point de vue
lexicographique, en fonction de la valeur Unicode de
chaque caractère des chaînes. Le résultat est le suivant :
• Un nombre entier négatif si la chaîne qui a appelé la
méthode de façon lexicographique précède
compString
•
•
Un nombre entier positif si la chaîne qui a appelé la
méthode de façon lexicographique suit compString
Zéro si les chaînes sont égales
S'il n'existe aucune position d'index à laquelle les chaînes
diffèrent, la chaîne la plus courte précède de façon
lexicographique la plus longue. Par exemple :
String myString1 = 'abcde';
String myString2 = 'abcd';
Integer result =
myString1.compareTo(myString2);
System.assertEquals(result, 1);
Notez que cette méthode renvoie 0 chaque fois que la
méthode equals renvoie true.
contains
String compString Boolean
Renvoie true si et seulement si la chaîne qui a appelé
la méthode contient la séquence spécifiée de caractères
dans compString. Par exemple :
String myString1 = 'abcde';
String myString2 = 'abcd';
Boolean result =
Référence
Nom
salesforce | Méthodes Primitives Apex | 385
Arguments
Type de renvoi
Description
myString1.contains(myString2);
System.assertEquals(result, true);
containsAny
String compString Boolean
Renvoie true si la chaîne actuelle contient l'un des
caractères de la chaîne spécifiée, sinon renvoie false.
Exemple :
String s = 'hello';
Boolean b1 =
s.containsAny('hx');
Boolean b2 =
s.containsAny('x');
System.assertEquals(
true,
b1);
System.assertEquals(
false,
b2);
containsIgnoreCase String compString Boolean
Renvoie true si la chaîne actuelle contient la séquence
de caractères spécifiée, quelle que soit la casse, sinon
renvoie false.
Exemple :
String s = 'hello';
Boolean b =
s.containsIgnoreCase('HE');
System.assertEquals(
true,
b);
containsNone
String compString Boolean
Renvoie true si la chaîne actuelle ne contient pas la
séquence de caractères spécifiée, sinon renvoie false.
Si compString est une chaîne vide ou si la chaîne
actuelle est vide, cette méthode renvoie true.
Si compString est null, cette méthode renvoie une
exception d'exécution.
Référence
salesforce | Méthodes Primitives Apex | 386
Nom
Arguments
Type de renvoi
containsOnly
String compString Boolean
Description
Renvoie true si la chaîne actuelle contient uniquement
des caractères de la séquence de caractères spécifiée, et
aucun autre, sinon renvoie false.
Exemple :
String s1 = 'abba';
String s2 = 'abba xyz';
Boolean b1 =
s1.containsOnly('abcd');
System.assertEquals(
true,
b1);
Boolean b2 =
s2.containsOnly('abcd');
System.assertEquals(
false,
b2);
containsWhitespace
countMatches
deleteWhitespace
difference
Boolean
String compString Integer
String
String compString String
Renvoie true si la chaîne spécifiée contient des
caractères d'espacement, sinon renvoie false.
Renvoie le nombre d'occurrences de la sous-chaîne dans
la chaîne actuelle.
Renvoie une version de la chaîne actuelle avec tous les
caractères d'espacement supprimés.
Renvoie la différence entre la chaîne actuelle et la chaîne
spécifiée.
Si compString est une chaîne vide, cette méthode
renvoie une chaîne vide.
Si compString est null, cette méthode lève une
exception d'exécution.
Exemple :
String s = 'Hello Jane';
String d1 =
s.difference('Hello Max');
System.assertEquals(
Référence
Nom
salesforce | Méthodes Primitives Apex | 387
Arguments
Type de renvoi
Description
'Max',
d1);
String d2 =
s.difference('Goodbye');
System.assertEquals(
'Goodbye',
d2);
String suffix
Boolean
Renvoie true si la chaîne qui a appelé la méthode se
termine par le suffix spécifié.
endsWithIgnoreCase String suffix
Boolean
Renvoie true si la chaîne spécifiée se termine par le
suffixe spécifié, sinon renvoie false.
endsWith
equals
String compString Boolean
Renvoie true si compString n'est pas nul et représente
la même séquence binaire de caractères que la chaîne qui
a appelé la méthode. Cette méthode est true chaque fois
que la méthode compareTo renvoie 0. Par exemple :
String myString1 = 'abcde';
String myString2 = 'abcd';
Boolean result =
myString1.equals(myString2);
System.assertEquals(result, false);
Notez que l'opérateur == exécute également une
comparaison de chaîne, mais il n'est pas sensible à la
casse pour se conformer aux sémantiques Apex. (== est
sensible à la casse pour une comparaison d'ID pour la
même raison).
equalsIgnoreCase String compString Boolean
Renvoie true si le compString n'est pas null et
représente la même séquence de caractères que la chaîne
qui a appelé la méthode, en ignorant la casse. Par
exemple :
String myString1 = 'abcd';
String myString2 = 'ABCD';
Boolean result =
myString1.equalsIgnoreCase(myString2);
System.assertEquals(result, true);
Référence
Nom
escapeCsv
salesforce | Méthodes Primitives Apex | 388
Arguments
Type de renvoi
Description
String
Renvoie une chaîne d'une colonne CSV placée entre
guillemets doubles, si nécessaire.
Si la chaîne contient une virgule, un saut de ligne ou un
guillemet double, la chaîne est renvoyée entre guillemets
doubles. De même, tout caractère guillemet double de
la chaîne est échappé avec un autre guillemet double.
Si la chaîne ne contient pas de virgule, de saut de ligne
ou de guillemet double, elle est renvoyée sans
modification.
Cette méthode est basée sur son équivalent escapeCsv
dans la bibliothèque Apache Commons Lang
StringEscapeUtils.
Exemple :
String s1 =
'Max1, "Max2"';
String s2 =
s1.escapeCsv();
System.assertEquals(
'"Max1, ""Max2"""',
s2);
escapeEcmaScript
String
Échappe les caractères de la chaîne à l'aide des règles de
chaîne EcmaScript.
À la différence des chaînes Apex, dans les chaînes
EcmaScript un guillemet unique et une barre oblique (/)
sont échappés.
Cette méthode est basée sur son équivalent
escapeEcmaScript dans la bibliothèque Apache
Commons Lang StringEscapeUtils.
Exemple :
String s1 = '"grade": 3.9/4.0';
String s2 = s1.escapeEcmaScript();
System.debug(s2);
// Output is:
// \"grade\": 3.9\/4.0
System.assertEquals(
Référence
Nom
salesforce | Méthodes Primitives Apex | 389
Arguments
Type de renvoi
Description
'\\"grade\\": 3.9\\/4.0',
s2);
escapeHtml3
String
Échappe les caractères d'une chaîne à l'aide des entités
HTML 3.0.
Cette méthode est basée sur son équivalent
escapeHtml3 dans la bibliothèque Apache Commons
Lang StringEscapeUtils.
Exemple :
String s1 =
'"<Black&White>"';
String s2 =
s1.escapeHtml3();
System.debug(s2);
// Output:
// &quot;&lt;Black&amp;
// White&gt;&quot;
escapeHtml4
String
Échappe les caractères d'une chaîne à l'aide des entités
HTML 4.0.
Cette méthode est basée sur son équivalent
escapeHtml4 dans la bibliothèque Apache Commons
Lang StringEscapeUtils.
Exemple :
String s1 =
'"<Black&White>"';
String s2 =
s1.escapeHtml4();
System.debug(s2);
// Output:
// &quot;&lt;Black&amp;
// White&gt;&quot;
Référence
Nom
salesforce | Méthodes Primitives Apex | 390
Arguments
escapeXml
Type de renvoi
Description
String
Échappe les caractères d'une chaîne à l'aide des entités
XML.
Prend en charge uniquement les cinq entités XML de
base (gt, lt, quot, amp, apos). Ne prend pas en charge
les DTD ou les entités externes. Les caractères Unicode
supérieurs à 0x7f ne sont pas échappés.
Cette méthode est basée sur son équivalent escapeXml
dans la bibliothèque Apache Commons Lang
StringEscapeUtils.
Exemple :
String s1 =
'"<Black&White>"';
String s2 =
s1.escapeXml();
System.debug(s2);
// Output:
// &quot;&lt;Black&amp;
// White&gt;&quot;
getLevenshtein
Distance
String s
Integer
Renvoie la distance Levenshtein entre la chaîne actuelle
et la chaîne spécifiée.
La distance Levenshtein est le nombre de modifications
nécessaires pour changer une chaîne en une autre chaîne.
Chaque changement est une modification de caractère
unique (suppression, insertion ou substitution).
Exemple :
String s = 'Hello Joe';
Integer i =
s.getLevenshteinDistance(
'Hello Max');
System.assertEquals(
3, i);
Référence
salesforce | Méthodes Primitives Apex | 391
Nom
Arguments
Type de renvoi
Description
getLevenshtein
Distance
String s
Integer
Renvoie la distance Levenshtein entre la chaîne actuelle
et la chaîne spécifiée si elle est inférieure ou égale au seuil
donné, sinon renvoie -1.
Integer threshold
La distance Levenshtein est le nombre de modifications
nécessaires pour changer une chaîne en une autre chaîne.
Chaque changement est une modification de caractère
unique (suppression, insertion ou substitution).
Exemple :
Dans cet exemple, la distance Levenshtein est 3, mais
l'argument de seuil est 2, qui est inférieur à la distance,
donc cette méthode renvoie -1.
String s = 'Hello Jane';
Integer i =
s.getLevenshteinDistance(
'Hello Max', 2);
System.assertEquals(
-1, i);
indexOf
String subString
Integer
Renvoie l'index de la première occurrence de la
sous-chaîne spécifiée. Si la sous-chaîne ne se présente
pas, cette méthode renvoie -1.
indexOf
String substring
Integer
Renvoie l'index basé sur zéro de la première occurrence
de la sous-chaîne spécifiée à partir du point d'index i.
Si la sous-chaîne ne se présente pas, cette méthode
renvoie -1. Par exemple :
Integer i
String myString1 = 'abcd';
String myString2 = 'bc';
Integer result =
myString1.indexOf(myString2, 0);
System.assertEquals(1, result);
indexOfAny
String substring
Integer
Renvoie l'index basé sur zéro de la première occurrence
de tout caractère spécifié dans la sous-chaîne. Si aucun
des caractères ne se présente, cette méthode renvoie -1.
Exemple :
String s1 = 'abcd';
Référence
Nom
salesforce | Méthodes Primitives Apex | 392
Arguments
Type de renvoi
Description
String s2 = 'xc';
Integer result =
s1.indexOfAny(s2);
System.assertEquals(
2, result);
indexOfAnyBut
String substring
Integer
Renvoie l'index basé sur zéro de la première occurrence
d'un caractère qui n'est pas dans la sous-chaîne spécifiée.
Sinon, cette méthode renvoie -1.
Exemple :
String s1 = 'abcd';
String s2 = 'xc';
Integer result =
s1.indexOfAnyBut(s2);
System.assertEquals(
0, result);
indexOfDifference String s
Integer
Renvoie l'index basé sur zéro du caractère auquel la
chaîne actuelle commence à être différente de la chaîne
spécifiée.
Exemple :
String s1 = 'abcd';
String s2 = 'abxc';
Integer result =
s1.indexOfDifference(s2);
System.assertEquals(
2, result);
indexOfIgnoreCase String substring
Integer
Renvoie l'index basé sur zéro de la première occurrence
de la sous-chaîne spécifiée, quelle que soit la casse. Si la
sous-chaîne ne se présente pas, cette méthode renvoie
-1. Par exemple :
String s1 = 'abcd';
String s2 = 'BC';
Integer result =
Référence
Nom
salesforce | Méthodes Primitives Apex | 393
Arguments
Type de renvoi
Description
s1.indexOfIgnoreCase(s2, 0);
System.assertEquals(1, result);
indexOfIgnoreCase String substring
Integer
Renvoie l'index basé sur zéro de la première occurrence
de la sous-chaîne spécifiée à partir du point d'index i,
quelle que soit la casse. Si la sous-chaîne ne se présente
pas, cette méthode renvoie -1.
isAllLowerCase
Boolean
Renvoie true si tous les caractères de la chaîne actuelle
sont en minuscules, sinon renvoie false.
isAllUpperCase
Boolean
Renvoie true si tous les caractères de la chaîne actuelle
sont en majuscules, sinon renvoie false.
isAlpha
Boolean
Renvoie true si tous les caractères de la chaîne actuelle
sont uniquement des lettres Unicode, sinon renvoie
false.
Integer
startPosition
Exemple :
// Letters only
String s1 = 'abc';
// Returns true
Boolean b1 =
s1.isAlpha();
System.assertEquals(
true, b1);
// Letters and numbers
String s2 = 'abc 21';
// Returns false
Boolean b2 =
s2.isAlpha();
System.assertEquals(
false, b2);
isAlphaSpace
Boolean
Renvoie true si tous les caractères de la chaîne actuelle
sont uniquement des lettres Unicode ou des espaces,
sinon renvoie false.
Référence
Nom
isAlphanumeric
salesforce | Méthodes Primitives Apex | 394
Arguments
Type de renvoi
Description
Boolean
Renvoie true si tous les caractères de la chaîne actuelle
sont uniquement des lettres Unicode ou des nombres,
sinon renvoie false.
Exemple :
// Letters only
String s1 = 'abc';
// Returns true
Boolean b1 =
s1.isAlphanumeric();
System.assertEquals(
true, b1);
// Letters and numbers
String s2 = 'abc021';
// Returns true
Boolean b2 =
s2.isAlphanumeric();
System.assertEquals(
true, b2);
isAlphanumericSpace
Boolean
Renvoie true si tous les caractères de la chaîne actuelle
sont uniquement des lettres Unicode, des chiffres ou des
espaces, sinon renvoie false.
isAsciiPrintable
Boolean
Renvoie true si la chaîne spécifiée contient uniquement
des caractères imprimables ASCII, sinon renvoie false.
isNumeric
Boolean
Renvoie true si la chaîne spécifiée contient uniquement
des chiffres Unicode, sinon renvoie false.
Un point décimal (1.2) n'est pas un chiffre Unicode.
isNumericSpace
Boolean
Renvoie true si la chaîne spécifiée contient uniquement
des chiffres Unicode ou des espaces, sinon renvoie
false.
Un point décimal (1.2) n'est pas un chiffre Unicode.
isWhitespace
Boolean
Renvoie true si la chaîne spécifiée uniquement des
caractères d'espacement, sinon renvoie false.
Référence
salesforce | Méthodes Primitives Apex | 395
Nom
Arguments
Type de renvoi
Description
lastIndexOf
String substring
Integer
Renvoie l'index de la dernière occurrence de la
sous-chaîne spécifiée. Si la sous-chaîne ne se présente
pas, cette méthode renvoie -1.
lastIndexOf
String substring
Integer
Renvoie l'index de la dernière occurrence de la
sous-chaîne spécifiée, en commençant à partir du
caractère à l'index 0 et en terminant à l'index spécifié.
Integer
endPosition
Si la sous-chaîne ne se présente pas ou si endPosition
est négatif, cette méthode renvoie -1. Si endPosition
est supérieur au dernier index de la chaîne actuelle, la
chaîne entière est recherchée.
Exemple :
String s1 = 'abcdaacd';
Integer i1 =
s1.lastIndexOf('c', 7);
System.assertEquals(
6, i1);
Integer i2 =
s1.lastIndexOf('c', 3);
System.assertEquals(
2, i2);
lastIndexOfIgnore String substring
Case
Integer
Renvoie l'index de la dernière occurrence de la
sous-chaîne spécifiée, quelle que soit la casse.
Si la sous-chaîne ne se présente pas, cette méthode
renvoie -1.
Exemple :
String s1 = 'abcdaacd';
Integer i1 =
s1.lastIndexOfIgnoreCase('DAAC');
System.assertEquals(
3, i1);
lastIndexOfIgnore String substring
Case
Integer
endPosition
Integer
Renvoie l'index de la dernière occurrence de la
sous-chaîne spécifiée, quelle que soit la casse, en
Référence
Nom
salesforce | Méthodes Primitives Apex | 396
Arguments
Type de renvoi
Description
commençant à partir du caractère à l'index 0 et en
terminant à l'index spécifié.
Si la sous-chaîne ne se présente pas ou si endPosition
est négatif, cette méthode renvoie -1. Si endPosition
est supérieur au dernier index de la chaîne actuelle, la
chaîne entière est recherchée.
Exemple :
String s1 = 'abcdaacd';
Integer i1 =
s1.lastIndexOfIgnoreCase('C', 7);
System.assertEquals(
6, i1);
left
Integer length
String
Renvoie les caractères les plus à gauche de la chaîne
actuelle de la longueur spécifiée.
Si length est supérieur à la taille de la chaîne, la chaîne
entière est renvoyée.
Exemple :
String s1 = 'abcdaacd';
String s2 =
s1.left(3);
System.assertEquals(
'abc', s2);
leftPad
Integer length
String
Renvoie la chaîne actuelle remplie d'espaces à gauche et
de la longueur spécifiée.
Si length est inférieur ou égal à la taille de la chaîne
actuelle, la chaîne entière est renvoyée sans remplissage.
Exemple :
String s1 = 'abc';
String s2 =
s1.leftPad(5);
System.assertEquals(
'
abc', s2);
Référence
Nom
salesforce | Méthodes Primitives Apex | 397
Arguments
length
Type de renvoi
Description
Integer
Renvoie le nombre de caractères Unicode 16 bits
contenus dans la chaîne. Par exemple :
String myString = 'abcd';
Integer result = myString.length();
System.assertEquals(result, 4);
mid
Integer startIndex String
Integer length
Renvoie une nouvelle chaîne commençant par le caractère
au startIndex basé sur zéro spécifié, avec le nombre
de caractères spécifié par length.
Si startIndex est négatif, il est considéré comme étant
égal à zéro.
Si length est négatif ou zéro, une chaîne vide est
renvoyée. Si length est supérieur aux caractères restants,
le reste de la chaîne est renvoyé.
Cette méthode est similaire aux méthodes
substring(startIndex) et
substring(startIndex, endIndex), à l'exception
du deuxième argument qui correspond au nombre de
caractères à renvoyer.
Exemple :
String s = 'abcde';
String s2 = s.mid(2, 3);
System.assertEquals(
'cde', s2);
normalizeSpace
String
Renvoie la chaîne actuelle avec les caractères
d'espacement de tête, de fin et répétés supprimés.
Cette méthode est basée sur son équivalent
normalizeSpace dans la bibliothèque Apache
Commons Lang StringUtils.
Exemple :
String s1 =
'Salesforce \t
force.com';
String s2 =
s1.normalizeSpace();
System.assertEquals(
Référence
Nom
salesforce | Méthodes Primitives Apex | 398
Arguments
Type de renvoi
Description
'Salesforce force.com', s2);
remove
String substring
String
Supprime toutes les occurrences de la sous-chaîne
spécifiée et renvoie le résultat de la chaîne.
Exemple :
String s1 = 'Salesforce and force.com';
String s2 =
s1.remove('force');
System.assertEquals(
'Sales and .com', s2);
removeEnd
String substring
String
Supprime la sous-chaîne spécifiée uniquement si elle se
présente à la fin de la chaîne.
Exemple :
String s1 = 'Salesforce and force.com';
String s2 =
s1.removeEnd('.com');
System.assertEquals(
'Salesforce and force', s2);
removeEndIgnoreCase String substring
String
Supprime la sous-chaîne spécifiée uniquement si elle se
présente à la fin de la chaîne en utilisant une
correspondance insensible à la casse.
Exemple :
String s1 = 'Salesforce and force.com';
String s2 =
s1.removeEndIgnoreCase('.COM');
System.assertEquals(
'Salesforce and force', s2);
Référence
salesforce | Méthodes Primitives Apex | 399
Nom
Arguments
Type de renvoi
Description
removeStart
String substring
String
Supprime la sous-chaîne spécifiée uniquement si elle se
présente au début de la chaîne.
Exemple :
String s1 = 'Salesforce and force.com';
String s2 =
s1.removeStart('Sales');
System.assertEquals(
'force and force.com', s2);
removeStartIgnore String substring
Case
String
Supprime la sous-chaîne spécifiée uniquement si elle se
présente au début de la chaîne en utilisant une
correspondance insensible à la casse.
Exemple :
String s1 = 'Salesforce and force.com';
String s2 =
s1.removeStartIgnoreCase('SALES');
System.assertEquals(
'force and force.com', s2);
repeat
Integer numTimes
String
Renvoie la chaîne actuelle répétée le nombre de fois
spécifié.
Exemple :
String s1 = 'SFDC';
String s2 =
s1.repeat(2);
System.assertEquals(
'SFDCSFDC', s2);
repeat
String separator
Integer numTimes
String
Renvoie la chaîne actuelle répétée le nombre de fois
spécifié, en utilisant le séparateur spécifié pour séparer
les chaînes répétées.
Exemple :
String s1 = 'SFDC';
String s2 =
Référence
Nom
salesforce | Méthodes Primitives Apex | 400
Arguments
Type de renvoi
Description
s1.repeat('-', 2);
System.assertEquals(
'SFDC-SFDC', s2);
replace
String target
String
Remplace chaque sous-chaîne d'une chaîne
correspondant à la séquence cible littérale target par
la séquence de remplacement littérale replacement
spécifiée.
String
Remplace chaque sous-chaîne d'une chaîne
correspondant à l'expression régulière regExp par la
séquence de remplacement replacement. Pour plus
d'informations sur les expressions régulières,
reportez-vous à la classe Java Pattern.
String
Remplace la première sous-chaîne d'une chaîne
correspondant à l'expression régulière regExp par la
séquence de remplacement replacement. Pour plus
d'informations sur les expressions régulières,
reportez-vous à la classe Java Pattern.
String
Renvoie une chaîne avec tous les caractères inversés.
String
Renvoie les caractères les plus à droite de la chaîne
actuelle de la longueur spécifiée.
String replacement
replaceAll
String regExp
String replacement
replaceFirst
String regExp
String replacement
reverse
right
Integer length
Si length est supérieur à la taille de la chaîne, la chaîne
entière est renvoyée.
Exemple :
String s1 = 'Hello Max';
String s2 =
s1.right(3);
System.assertEquals(
'Max', s2);
rightPad
Integer length
String
Renvoie la chaîne actuelle remplie d'espaces à droite et
de la longueur spécifiée.
Si length est inférieur ou égal à la taille de la chaîne
actuelle, la chaîne entière est renvoyée sans remplissage.
Exemple :
String s1 = 'abc';
String s2 =
Référence
Nom
salesforce | Méthodes Primitives Apex | 401
Arguments
Type de renvoi
Description
s1.rightPad(5);
System.assertEquals(
'abc
split
String regExp
Integer limit
String[]
', s2);
Renvoie un liste contenant chaque sous-chaîne de la
chaîne qui se termine par l'expression régulière regExp
ou la fin de la chaîne. Pour plus d'informations sur les
expressions régulières, reportez-vous à la classe Java
Pattern.
Les sous-chaînes sont placées dans la liste dans le même
ordre que dans la chaîne. Si regExp ne correspond à
aucune partie de la chaîne, la liste résultante contient un
seul élément avec la chaîne d'origine.
Le paramètre facultatif limit contrôle le nombre de
fois où le modèle s'applique. Par conséquent, il affecte
la longueur de la liste :
•
•
•
Si limit est supérieur à zéro, le modèle s'applique
au maximum à limit - 1 fois, la longueur de la liste
n'est pas supérieure à limit et la dernière entrée de
la liste contient toutes les entrées au-delà du dernier
délimiteur correspondant.
Si limit est non positif, le modèle s'applique autant
de fois que possible et la liste peut avoir n'importe
quelle longueur.
Si limit est égal à zéro, le modèle s'applique autant
de fois que possible, la liste peut avoir n'importe
quelle longueur et les chaînes vides de fin peuvent
être ignorées.
Par exemple, pour String s = 'boo:and:foo' :
•
s.split(':', 2) résulte en {'boo',
'and:foo'}
•
s.split(':', 5) résulte en {'boo', 'and',
'foo'}
•
s.split(':', -2) résulte en {'boo', 'and',
'foo'}
•
s.split('o', 5) résulte en {'b', '',
':and:f', '', ''}
•
s.split('o', -2) résulte en {'b', '',
':and:f', '', ''}
•
s.split('o', 0) résulte en {'b', '',
':and:f'}
Référence
Nom
salesforce | Méthodes Primitives Apex | 402
Arguments
Type de renvoi
Description
Reportez-vous également à Exemple de fractionnement
de chaîne.
List<String>
splitByCharacterType
Fractionne la chaîne actuelle par type de caractère et
renvoie une liste de groupes de caractères continus du
même type que les jetons complets.
Pour plus d'informations sur les types de caractère
utilisés, reportez-vous à
java.lang.Character.getType(char).
Exemple :
String s1 = 'Force.com platform';
List<String> ls =
s1.splitByCharacterType();
System.debug(ls);
// Writes this output:
// (F, orce, ., com,
List<String>
splitByCharacterType
CamelCase
, platform)
Fractionne la chaîne actuelle par type de caractère et
renvoie une liste de groupes de caractères continus du
même type que les jetons complets, avec l'exception
suivante : le caractère majuscule, le cas échéant, précédant
immédiatement un jeton de caractère minuscule
appartient au jeton de caractère suivant plutôt qu'au
précédent.
Pour plus d'informations sur les types de caractère
utilisés, reportez-vous à
java.lang.Character.getType(char).
Exemple :
String s1 = 'Force.com platform';
List<String> ls =
s1.splitByCharacterTypeCamelCase();
System.debug(ls);
// Writes this output:
// (Force, ., com,
startsWith
String prefix
Boolean
, platform)
Renvoie true si la chaîne qui a appelé la méthode
commence par le prefix spécifié.
Référence
salesforce | Méthodes Primitives Apex | 403
Nom
Arguments
Type de renvoi
Description
startsWith
IgnoreCase
String prefix
Boolean
Renvoie true si la chaîne actuelle commence par le
préfixe spécifié, quelle que soit la casse du préfixe.
substring
Integer startIndex String
Renvoie une nouvelle chaîne qui commence par le
caractère au startIndex basé sur zéro spécifié, et se
termine à la fin de la chaîne.
substring
Integer startIndex String
Renvoie une nouvelle chaîne qui commence par le
caractère au startIndex basé sur zéro spécifié, et se
termine au caractère à endIndex - 1. Par exemple :
Integer endIndex
'hamburger'.substring(4, 8);
// Returns "urge"
'smiles'.substring(1, 5);
// Returns "mile"
substringAfter
String separator
String
Renvoie la sous-chaîne qui se présente après la première
occurrence du séparateur spécifié.
Exemple :
String s1 = 'Force.com.platform';
String s2 =
s1.substringAfter('.');
System.assertEquals(
'com.platform', s2);
substringAfterLast String separator
String
Renvoie la sous-chaîne qui se présente après la dernière
occurrence du séparateur spécifié.
Exemple :
String s1 = 'Force.com.platform';
String s2 =
s1.substringAfterLast('.');
System.assertEquals(
'platform', s2);
Référence
Nom
salesforce | Méthodes Primitives Apex | 404
Arguments
substringBefore String separator
Type de renvoi
Description
String
Renvoie la sous-chaîne qui se présente avant la première
occurrence du séparateur spécifié.
Exemple :
String s1 = 'Force.com.platform';
String s2 =
s1.substringBefore('.');
System.assertEquals(
'Force', s2);
substringBeforeLast String separator
String
Renvoie la sous-chaîne qui se présente avant la dernière
occurrence du séparateur spécifié.
Exemple :
String s1 = 'Force.com.platform';
String s2 =
s1.substringBeforeLast('.');
System.assertEquals(
'Force.com', s2);
substringBetween String tag
String
Renvoie la sous-chaîne qui se présente entre deux
instances de la chaîne spécifiée.
Exemple :
String s1 = 'tagYellowtag';
String s2 =
s1.substringBetween('tag');
System.assertEquals(
'Yellow', s2);
substringBetween String open
String close
String
Renvoie la sous-chaîne qui se présente entre les deux
chaînes spécifiées.
Exemple :
String s1 = 'xYellowy';
String s2 =
s1.substringBetween('x','y');
Référence
Nom
salesforce | Méthodes Primitives Apex | 405
Arguments
Type de renvoi
Description
System.assertEquals(
'Yellow', s2);
swapCase
String open
String
String close
Permute la casse de tous les caractères et renvoie la chaîne
résultante.
Une majuscule et une initiale majuscule sont converties
en minuscules, et une minuscule est convertie en
majuscule.
Exemple :
String s1 = 'Force.com';
String s2 =
s1.swapCase();
System.assertEquals(
'fORCE.COM', s2);
toLowerCase
toLowerCase
String locale
toUpperCase
String
Convertit tous les caractères de la chaîne en minuscules
en utilisant les règles des paramètres régionaux par
défaut.
String
Convertit tous les caractères de la chaîne en minuscules
en utilisant les règles des paramètres régionaux spécifiés.
String
Convertit tous les caractères de la chaîne en majuscules
en utilisant les règles des paramètres régionaux par
défaut. Par exemple :
String myString1 = 'abcd';
String myString2 = 'ABCD';
myString1 =
myString1.toUpperCase();
Boolean result =
myString1.equals(myString2);
System.assertEquals(result, true);
toUpperCase
String locale
String
Convertit tous les caractères de la chaîne en majuscules
en utilisant les règles des paramètres régionaux spécifiés.
Référence
Nom
trim
salesforce | Méthodes Primitives Apex | 406
Arguments
Type de renvoi
Description
String
Renvoie une copie de la chaîne qui ne contient plus
aucun caractère d'espacement de début ou de fin.
Les caractères de contrôle ASCII de début et de fin, tels
que les tabulations et les nouvelles lignes, sont également
supprimés. Les caractères d'espace et de contrôle qui ne
sont pas placés au début ou à la fin de la phrase ne sont
pas supprimés.
uncapitalize
String
Renvoie la chaîne actuelle avec la première lettre en
minuscule.
Exemple :
String s1 =
'Hello max';
String s2 =
s1.uncapitalize();
System.assertEquals(
'hello max',
s2);
unescapeCsv
String
Renvoie une chaîne représentant une colonne CSV non
échappée.
Si la chaîne est placée entre guillemets doubles et
contient une virgule, un saut de ligne ou un guillemet
double, les guillemets sont supprimés. De même, tout
caractère guillemet double échappé (paire de guillemets
doubles) est réduit à un seul guillemet double.
Si la chaîne n'est pas placée entre guillemets doubles, ou
si elle l'est et ne contient pas de virgule, de saut de ligne
ou de double guillemet, elle est renvoyée inchangée.
Cette méthode est basée sur son équivalent
unescapeCsv dans la bibliothèque Apache Commons
Lang StringEscapeUtils.
Exemple :
String s1 =
'"Max1, ""Max2"""';
String s2 =
s1.unescapeCsv();
System.assertEquals(
Référence
Nom
salesforce | Méthodes Primitives Apex | 407
Arguments
Type de renvoi
Description
'Max1, "Max2"',
s2);
unescapeEcmaScript
String
L'échappement de tout littéral EcmaScript trouvé dans
la chaîne est supprimé.
Cette méthode est basée sur son équivalent
unescapeEcmaScript dans la bibliothèque Apache
Commons Lang StringEscapeUtils.
Exemple :
String s1 =
'\"3.8\",\"3.9\"';
String s2 =
s1.unescapeEcmaScript();
System.assertEquals(
'"3.8","3.9"',
s2);
unescapeHtml3
String
L'échappement des caractères d'une chaîne utilisant des
entités HTML 3.0 est supprimé.
Cette méthode est basée sur son équivalent
unescapeHtml3 dans la bibliothèque Apache
Commons Lang StringEscapeUtils.
Exemple :
String s1 =
'&quot;&lt;Black&amp;White&gt;&quot;';
String s2 =
s1.unescapeHtml3();
System.assertEquals(
'"<Black&White>"',
s2);
Référence
Nom
unescapeHtml4
salesforce | Méthodes Primitives Apex | 408
Arguments
Type de renvoi
Description
String
L'échappement des caractères d'une chaîne utilisant des
entités HTML 4.0 est supprimé.
Cette méthode est basée sur son équivalent
unescapeHtml4 dans la bibliothèque Apache
Commons Lang StringEscapeUtils.
Exemple :
String s1 =
'&quot;&lt;Black&amp;White&gt;&quot;';
String s2 =
s1.unescapeHtml4();
System.assertEquals(
'"<Black&White>"',
s2);
unescapeXml
String
L'échappement des caractères d'une chaîne utilisant des
entités XML est supprimé.
Prend en charge uniquement les cinq entités XML de
base (gt, lt, quot, amp, apos). Ne prend pas en charge
les DTD ou les entités externes.
Cette méthode est basée sur son équivalent
unescapeXml dans la bibliothèque Apache Commons
Lang StringEscapeUtils.
Exemple :
String s1 =
'&quot;&lt;Black&amp;White&gt;&quot;';
String s2 =
s1.unescapeXml();
System.assertEquals(
'"<Black&White>"',
s2);
Pour plus d'informations sur le type String, reportez-vous à Types de données Primitif à la page 29.
Référence
salesforce | Méthodes Primitives Apex | 409
Exemple de fractionnement de chaîne
Dans l'exemple suivant, une chaîne est fractionnée en utilisant une barre oblique inversée comme délimiteur :
public String removePath(String filename) {
if (filename == null)
return null;
List<String> parts = filename.split('\\\\');
filename = parts[parts.size()-1];
return filename;
}
static testMethod void testRemovePath() {
System.assertEquals('PPDSF100111.csv',
EmailUtilities.getInstance().
removePath('e:\\processed\\PPDSF100111.csv'));
}
Méthodes Time
Les méthodes ci-dessous sont les méthodes statiques système Time.
Nom
Arguments
Type de renvoi
Description
newInstance
Integer hour
Time
Construit une heure à partir de représentations de
nombre entier de hour, minutes, seconds et
milliseconds. L'exemple suivant crée une heure
18:30:2:20 :
Integer minutes
Integer seconds
Integer
Time myTime =
milliseconds
Time.newInstance(18, 30, 2, 20);
Les méthodes ci-dessous sont les méthodes d'instance pour Time.
Nom
Arguments
Type de renvoi
Description
addHours
Integer addlHours
Time
Ajoute le nombre spécifié de addlHours à une heure.
addMilliseconds Integer
Time
addlMilliseconds
Ajoute le nombre spécifié de addlMilliseconds à une
heure.
Référence
salesforce | Méthodes Collection Apex | 410
Nom
Arguments
Type de renvoi
Description
addMinutes
Integer
Time
Ajoute le nombre spécifié de addlMinutes à une heure.
Par exemple :
addlMinutes
Time myTime =
Time.newInstance(18, 30, 2, 20);
Integer myMinutes = myTime.minute();
myMinutes = myMinutes + 5;
System.assertEquals(myMinutes, 35);
addSeconds
Integer
Time
Ajoute le nombre spécifié de addlSeconds à une heure.
Integer
Renvoie le composant heure d'une heure. Par exemple
:
addlSeconds
hour
Time myTime =
Time.newInstance(18, 30, 2, 20);
myTime = myTime.addHours(2);
Integer myHour = myTime.hour();
System.assertEquals(myHour, 20);
millisecond
Integer
Renvoie le composant milliseconde d'une heure.
minute
Integer
Renvoie le composant minute d'une heure.
second
Integer
Renvoie le composant seconde d'une heure.
Pour plus d'informations sur le type Time, reportez-vous à Types de données Primitive à la page 29.
Méthodes Collection Apex
Toutes les collections dans Apex ont des méthodes qui leur sont associées pour l'attribution, la récupération et la manipulation
des données. Les méthodes collection sont les suivantes :
•
•
•
List
Map
Set
Référence
salesforce | Méthodes Collection Apex | 411
Remarque: Le nombre d'éléments qu'une collection peut contenir n'est pas limité. Il existe toutefois une limite
globale en taille de segment mémoire.
Méthodes List
Les méthodes de liste sont toutes des méthodes d'instance, c.-à-d. qu'elles fonctionnent dans une instance particulière d'une
liste. L'exemple suivant supprime tous les éléments de myList :
myList.clear();
La méthode clear ne contient aucun paramètre, mais la liste qui l'appelle est son paramètre implicite.
Les paramètres suivants sont les paramètres d'instance pour List.
Remarque: Dans le tableau ci-dessous, List_elem représente un élément unique de même type que la liste.
Nom
Arguments
Type de renvoi
Description
add
N'importe quel type e
Void
Ajoute un élément e à la fin de la liste. Par exemple
:
List<Integer> myList = new
List<Integer>();
myList.add(47);
Integer myNumber = myList.get(0);
system.assertEquals(myNumber, 47);
add
Integer i
Void
N'importe quel type e
Insère un élément e dans la liste à la position
d'index i. Dans l'exemple suivant, une liste de six
éléments est créée et des nombres entiers sont
ajoutés aux première et deuxième positions d'index.
List<Integer> myList = new
Integer[6];
myList.add(0, 47);
myList.add(1, 52);
system.assertEquals(myList.get(1),
52);
addAll
List l
Void
Ajoute tous les éléments de la liste l à la liste qui
appelle la méthode. Notez que les deux listes
doivent être de même type.
Référence
salesforce | Méthodes Collection Apex | 412
Nom
Arguments
Type de renvoi
Description
addAll
Set s
Void
Ajoute tous les éléments de l'ensemble s à la liste
qui appelle la méthode. Notez que l'ensemble et la
liste doivent être de même type.
clear
Void
Supprime tous les éléments de la liste, en définissant
ainsi la longueur de la liste sur zéro.
clone
List (de même
type)
Effectue une copie d'une liste.
Notez que s'il s'agit d'une liste d'enregistrements
de sObject, la liste dupliquée est uniquement une
copie superficielle de la liste. Par conséquent, la
copie référence chaque objet, mais les
enregistrements de sObject eux-mêmes ne sont pas
dupliqués. Par exemple :
Account a = new
Account(Name='Acme',
BillingCity='New
York');
Account b = new Account();
Account[] q1 = new
Account[]{a,b};
Account[] q2 = q1.clone();
q1[0].BillingCity = 'San Francisco';
System.assertEquals(
q1[0].BillingCity,
'San Francisco');
System.assertEquals(
q2[0].BillingCity,
'San Francisco');
Pour copier également les enregistrements de
sObject, utilisez la méthode deepClone.
Référence
salesforce | Méthodes Collection Apex | 413
Nom
Arguments
Type de renvoi
deepClone
Boolean opt_preserve_id
List (de même type Effectue une copie d'une liste d'enregistrements de
d'objet)
sObject, qui inclut les enregistrements de sObject
eux-mêmes. Par exemple :
Boolean
opt_preserve_readonly_timestamps
Boolean
opt_preserve_autonumber
Description
Account a = new
Account(Name='Acme',
BillingCity='New York');
Account b = new Account(
Name='Salesforce');
Account[] q1 = new
Account[]{a,b};
Account[] q2 = q1.deepClone();
q1[0].BillingCity = 'San Francisco';
System.assertEquals(
q1[0].BillingCity,
'San Francisco');
System.assertEquals(
q2[0].BillingCity,
'New York');
Remarque: deepClone fonctionne
uniquement avec des listes de sObjects,
pas avec des listes de primitifs.
L'argument facultatif opt_preserve_id
détermine si les ID des objets d'origine sont
conservés ou effacés dans les copies. Si défini sur
true, les ID sont copiés dans les objets clonés. La
valeur par défaut est false, c.-à-d. que les ID sont
effacés.
Référence
Nom
salesforce | Méthodes Collection Apex | 414
Arguments
Type de renvoi
Description
Remarque: Pour un code Apex enregistré
en utilisant l'API Salesforce.com version
22.0 ou antérieure, la valeur par défaut de
l'argument opt_preserve_id est true,
c.-à-d. que les ID sont conservés.
L'argument facultatif
opt_preserve_readonly_timestamps
détermine si l'horodatage et les champs d'ID
utilisateur en lecture seule sont conservés ou effacés
dans les copies. Si défini sur true, les champs en
lecture seule CreatedById, CreatedDate,
LastModifiedById et LastModifiedDate
sont copiés dans les objets clonés. La valeur par
défaut est false, c.-à-d. que les valeurs sont
effacées.
L'argument facultatif
opt_preserve_autonumber détermine si les
champs à numérotation automatique des objets
d'origine sont conservés ou effacés dans les copies.
Si défini sur true, les champs à numérotation
automatique sont copiés dans les objets clonés. La
valeur par défaut est false, c.-à-d. que les champs
à numérotation automatique sont effacés.
Cet exemple est basé sur l'exemple précédent et
montre comment cloner une liste avec un
horodatage et des champs d'ID utilisateur en lecture
seule préservés.
insert q1;
List<Account> accts =
[SELECT CreatedById,
CreatedDate, LastModifiedById,
LastModifiedDate, BillingCity
FROM Account
WHERE Name='Acme' OR
Name='Salesforce'];
// Clone list while preserving
// timestamp and user ID fields.
Référence
Nom
salesforce | Méthodes Collection Apex | 415
Arguments
Type de renvoi
Description
Account[] q3 =
accts.deepClone(false,true,false);
// Verify timestamp fields are
// preserved for the first
// list element.
System.assertEquals(
q3[0].CreatedById,
accts[0].CreatedById);
System.assertEquals(
q3[0].CreatedDate,
accts[0].CreatedDate);
System.assertEquals(
q3[0].LastModifiedById,
accts[0].LastModifiedById);
System.assertEquals(
q3[0].LastModifiedDate,
accts[0].LastModifiedDate);
Pour effectuer une copie superficielle d'une liste
sans dupliquer les enregistrements de sObject qu'elle
contient, utilisez la méthode clone.
get
Integer i
Array element
Renvoie les éléments de liste stockés à l'index i.
Par exemple :
List<Integer> myList = new
List<Integer>();
myList.add(47);
Integer myNumber = myList.get(0);
system.assertEquals(myNumber, 47);
Pour référencer un élément d'une liste
unidimensionnelle de primitifs ou de sObjects, vous
pouvez également ajouter la position d'index de
Référence
Nom
salesforce | Méthodes Collection Apex | 416
Arguments
Type de renvoi
Description
l'élément, entre crochets, après le nom de la liste.
Par exemple :
List<String> colors = new String[3];
colors[0] = 'Red';
colors[1] = 'Blue';
colors[2] = 'Green';
getSObjectType
Schema.SObjectType Renvoie le jeton du type de sObject qui forme une
liste de sObjects. Utilisez-la avec l'information
describe afin de déterminer si une liste contient des
sObjects d'un type particulier. Par exemple :
Account a = new
Account(name='test');
insert a;
// Create a generic sObject
// variable s
SObject s = Database.query
('SELECT Id FROM Account ' +
'LIMIT 1');
// Verify if that sObject
// variable is
// an Account token
System.assertEquals(
s.getSObjectType(),
Account.sObjectType);
// Create a list of
// generic sObjects
List<sObject> q =
new Account[]{};
// Verify if the list of
// sObjects
Référence
Nom
salesforce | Méthodes Collection Apex | 417
Arguments
Type de renvoi
Description
// contains Account tokens
System.assertEquals(
q.getSObjectType(),
Account.sObjectType);
Notez que cette méthode peut être utilisée
uniquement avec des listes composées de sObjects.
Pour plus d'informations, reportez-vous à
Compréhension de l'information Describe Apex à
la page 204.
isEmpty
Boolean
Renvoie true si la liste contient zéro élément.
iterator
Iterator
Renvoie une instance d'un itérateur. À partir de
l'itérateur, vous pouvez utiliser les méthodes
itérables hasNext et next pour parcourir la liste.
Par exemple :
global class CustomIterable
implements Iterator<Account>{
List<Account> accs {get; set;}
Integer i {get; set;}
public CustomIterable(){
accs =
[SELECT Id, Name,
NumberOfEmployees
FROM Account
WHERE Name = 'false'];
i = 0;
}
global boolean hasNext(){
if(i >= accs.size()) {
return false;
} else {
Référence
Nom
salesforce | Méthodes Collection Apex | 418
Arguments
Type de renvoi
Description
return true;
}
}
global Account next(){
// 8 is an arbitrary
// constant in this example
// that represents the
// maximum size of the list.
if(i == 8){return null;}
i++;
return accs[i-1];
}
}
Remarque: Il n'est pas nécessaire de
mettre en oeuvre l'interface iterable
pour utiliser les méthodes iterable avec
une liste.
remove
Integer i
Array element
Supprime l'élément qui stocké au ième index d'une
liste, en renvoyant l'élément qui a été supprimé. Par
exemple :
List<String> colors = new String[3];
colors[0] = 'Red';
colors[1] = 'Blue';
colors[2] = 'Green';
String S1 = colors.remove(2);
system.assertEquals(S1, 'Green');
set
Integer i
N'importe quel type e
Void
Attribue e à la position d'index de liste i. Par
exemple :
List<Integer> myList = new
Integer[6];
Référence
Nom
salesforce | Méthodes Collection Apex | 419
Arguments
Type de renvoi
Description
myList.set(0, 47);
myList.set(1, 52);
system.assertEquals(myList.get(1),
52);
Pour définir un élément d'une liste
unidimensionnelle de primitifs ou de sObjects, vous
pouvez également ajouter la position d'index de
l'élément, entre crochets, après le nom de la liste.
Par exemple :
List<String> colors = new String[3];
colors[0] = 'Red';
colors[1] = 'Blue';
colors[2] = 'Green';
size
Integer
Renvoie le nombre d'éléments de la liste. Par
exemple :
List<Integer> myList = new
List<Integer>();
Integer size = myList.size();
system.assertEquals(size, 0);
List<Integer> myList2 = new
Integer[6];
Integer size2 = myList2.size();
system.assertEquals(size2, 6);
sort
Void
Trie les éléments de la liste par ordre croissant.
Dans l'exemple suivant, la liste compte trois
éléments. Lorsque la liste est triée, le premier
élément est nul, car aucune valeur ne lui est
attribuée, alors que le deuxième élément a la valeur
5:
List<Integer> q1 = new Integer[3];
// Assign values to the first
// two elements
Référence
salesforce | Méthodes Collection Apex | 420
Nom
Arguments
Type de renvoi
Description
q1[0] = 10;
q1[1] = 5;
q1.sort();
// First element is null, second is
5
system.assertEquals(q1.get(1), 5);
Remarque: Avec cette méthode, vous
pouvez trier des types primitifs, des
éléments SelectOption et des sObjects
(objets standard et objets personnalisés).
Pour plus d'informations sur l'ordre de tri
utilisé pour les sObjects, reportez-vous à
Tri des listes. Vous pouvez également trier
des types personnalisés (vos classes Apex)
s'ils mettent en oeuvre l'interface
Comparable.
Pour plus d'informations sur le type List, reportez-vous à Lists à la page 38.
Méthodes Map
Les méthodes Map sont toutes des méthodes d'instance, c.-à-d. qu'elle fonctionnent dans une instance particulière d'un
mappage. Les méthodes ci-dessous sont les méthodes d'instance pour les mappages.
Remarque:
•
•
•
Nom
clear
Dans le tableau ci-dessous, Key_type et Value_type représentent respectivement le type de données de clé de
mappage et de valeur, qui peuvent correspondent à n'importe quel type de données : primitive, collections, sObjects,
types définis par l'utilisateur et types Apex intégrés.
Pour déterminer si les clés de mappage de types définis par l'utilisateur sont uniques, les méthodes equals et
hashCode sont utilisées, que vous fournissez dans vos classes. Pour déterminer si tous les autres types non primitifs
sont uniques, les champs des objets sont comparés.
Les clés de mappage de type String sont sensibles à la casse. Deux clés dont seule la casse diffère sont considérées
comme uniques et ont des entrées de mappage correspondantes distinctes. Par conséquent, les méthodes Map,
qui comprennent put, get, containsKey et remove, traitent ces clés comme étant distinctes.
Arguments
Type de renvoi
Description
Void
Supprime toutes les paires clé-valeur du mappage.
Référence
Nom
salesforce | Méthodes Collection Apex | 421
Arguments
clone
Type de renvoi
Description
Map (de même
type)
Effectue une copie du mappage.
Notez que s'il s'agit d'un mappage avec des valeurs
d'enregistrement de sObject, le mappage dupliqué est
seulement une copie superficielle du mappage. Cela signifie
que la copie a des références à chaque enregistrement de
sObject, mais que les enregistrements eux-mêmes ne sont pas
dupliqués. Par exemple :
Account a = new Account(
Name='Acme',
BillingCity='New York');
Map<Integer, Account> map1 =
new Map<Integer, Account> {};
map1.put(1, a);
Map<Integer, Account> map2 =
map1.clone();
map1.get(1).BillingCity =
'San Francisco';
System.assertEquals(
map1.get(1).BillingCity,
'San Francisco');
System.assertEquals(
map2.get(1).BillingCity,
'San Francisco');
Pour copier également les enregistrements de sObject, utilisez
la méthode deepClone.
containsKey
Key type key
Boolean
Renvoie true si le mappage contient un mappage de la key
spécifiée.
Si la clé est une chaîne, la valeur de clé est sensible à la casse.
Référence
Nom
salesforce | Méthodes Collection Apex | 422
Arguments
Type de renvoi
Description
Par exemple :
Map<string, string> colorCodes =
new Map<String, String>();
colorCodes.put('Red', 'FF0000');
colorCodes.put('Blue', '0000A0');
Boolean contains =
colorCodes.containsKey('Blue');
System.assertEquals(contains, True);
deepClone
Map (de même
type)
Effectue une copie d'un mappage, comprenant les
enregistrements de sObject s'il s'agit d'un mappage avec des
valeurs d'enregistrement de sObject. Par exemple :
Account a = new Account(
Name='Acme',
BillingCity='New York');
Map<Integer, Account> map1 =
new Map<Integer, Account> {};
map1.put(1, a);
Map<Integer, Account> map2 =
map1.deepClone();
map1.get(1).BillingCity =
'San Francisco';
System.assertEquals(map1.get(1).
BillingCity, 'San Francisco');
System.assertEquals(map2.get(1).
Référence
Nom
salesforce | Méthodes Collection Apex | 423
Arguments
Type de renvoi
Description
BillingCity, 'New York');
Pour effectuer une copie superficielle d'un mappage sans
dupliquer les enregistrements de sObject qu'elle contient,
utilisez la méthode clone().
get
Key type key
Value_type
Renvoie la valeur avec laquelle la key spécifiée est mappée,
ou null si le mappage ne contient aucune valeur pour cette
clé.
Si la clé est une chaîne, la valeur de clé est sensible à la casse.
Par exemple :
Map<String, String> colorCodes =
new Map<String, String>();
colorCodes.put('Red', 'FF0000');
colorCodes.put('Blue', '0000A0');
String code =
colorCodes.get('Blue');
System.assertEquals(code, '0000A0');
// The following is not a color
// in the map
String code2 =
colorCodes.get('Magenta');
System.assertEquals(code2, null);
getSObjectType
Schema.SObjectType Renvoie le jeton du type de sObject qui forme les valeurs du
mappage. Utilisez-la avec l'information describe afin de
déterminer si un mappage contient des sObjects d'un type
particulier. Par exemple :
Account a = new Account(
Name='Acme');
Référence
Nom
salesforce | Méthodes Collection Apex | 424
Arguments
Type de renvoi
Description
insert a;
// Create a generic sObject
// variable s
SObject s = Database.query
('SELECT Id FROM Account ' +
'LIMIT 1');
// Verify if that sObject
// variable
// is an Account token
System.assertEquals(
s.getSObjectType(),
Account.sObjectType);
// Create a map of generic
// sObjects
Map<Integer, Account> M =
new Map<Integer, Account>();
// Verify if the list of sObjects
// contains Account tokens
System.assertEquals(
M.getSObjectType(),
Account.sObjectType);
Notez que cette méthode peut être utilisée uniquement avec
des mappages ayant des valeurs de sObject.
Pour plus d'informations, reportez-vous à Compréhension de
l'information Describe Apex à la page 204.
Référence
Nom
salesforce | Méthodes Collection Apex | 425
Arguments
isEmpty
Type de renvoi
Description
Boolean
Renvoie true si le mappage n'a aucune paire clé-valeur. Par
exemple :
Map<String, String> colorCodes =
new Map<String, String>();
Boolean empty = colorCodes.isEmpty();
system.assertEquals(empty, true);
Set of Key_type
keySet
Renvoie un ensemble contenant toutes les clés du mappage.
Par exemple :
Map<String, String> colorCodes =
new Map<String, String>();
colorCodes.put('Red', 'FF0000');
colorCodes.put('Blue', '0000A0');
Set <String> colorSet = new Set<String>();
colorSet = colorCodes.keySet();
put
Key key,
Value_type
Value value
Associe la valeur spécifiée à la key spécifiée dans le mappage.
Si le mappage contenait précédemment un mappage pour cette
clé, l'ancienne valeur est renvoyée par la méthode, puis
remplacée.
Si la clé est une chaîne, la valeur de clé est sensible à la casse.
Par exemple :
Map<String, String> colorCodes =
new Map<String, String>();
colorCodes.put('Red', 'ff0000');
colorCodes.put('Red', '#FF0000');
// Red is now #FF0000
putAll
Map m
Void
Copie l'ensemble du mappage m spécifié dans le mappage
d'origine. Les nouveaux mappages de m remplacent les
mappages d'origine.
Référence
salesforce | Méthodes Collection Apex | 426
Nom
Arguments
putAll
sObject[] l
remove
Key key
Type de renvoi
Description
Si le mappage inclut des ID ou des chaînes mappés avec des
sObjects, elle ajoute la liste des enregistrements de sObjects
l au mappage de la même façon que le constructeur Map avec
cette entrée.
Value_type
Supprime le mappage de cette key du mappage s'il est présent.
La valeur est renvoyée par la méthode, puis supprimée.
Si la clé est une chaîne, la valeur de clé est sensible à la casse.
Par exemple :
Map<String, String> colorCodes =
new Map<String, String>();
colorCodes.put('Red', 'FF0000');
colorCodes.put('Blue', '0000A0');
String myColor = colorCodes.remove('Blue');
String code2 =
colorCodes.get('Blue');
System.assertEquals(code2, null);
size
Integer
Renvoie le nombre de paires clé-valeur du mappage.
Par exemple :
Map<String, String> colorCodes =
new Map<String, String>();
colorCodes.put('Red', 'FF0000');
colorCodes.put('Blue', '0000A0');
Integer mSize = colorCodes.size();
system.assertEquals(mSize, 2);
Référence
salesforce | Méthodes Collection Apex | 427
Nom
Arguments
Type de renvoi
Description
list of Value_type Renvoie une liste contenant toutes les valeurs du mappage
dans un ordre arbitraire. Par exemple :
valeurs
Map<String, String> colorCodes =
new Map<String, String>();
colorCodes.put('Red', 'FF0000');
colorCodes.put('Blue', '0000A0');
List<String> colors = new List<String>();
colors = colorCodes.values();
Pour plus d'informations sur le type Map, reportez-vous à Maps à la page 47.
Méthodes Set
Les méthodes Set fonctionnent dans un ensemble, c.-à-d. sur une collection non triée d'éléments qui ont été initialisés en
utilisant le mot clé set. Un ensemble contient uniquement des éléments uniques et n'a pas de valeurs copiées. Les éléments
d'ensemble peuvent avoir n'importe quel type de données : primitif, collection, sObject, type défini par l'utilisateur et type
Apex intégré. Les méthodes Set sont toutes des méthodes d'instance, c.-à-d. qu'elles fonctionnent sur une instance particulière
d'un ensemble. Les méthodes ci-dessous sont les méthodes d'instance pour Set.
Remarque:
•
•
•
Dans le tableau ci-dessous, Set_elem représente un élément unique dans l'ensemble.
L'unicité des éléments d'ensemble des types définis par l'utilisateur est déterminée par les méthodes equals et
hashCode que vous fournissez dans vos classes. L'unicité de tous les autres types non primitifs est déterminée en
comparant les champs de l'objet.
Si l'ensemble contient des éléments de type String, ils sont sensibles à la casse. Deux éléments d'ensemble dont
seule la casse est différente sont considérés comme distincts.
Nom
Arguments
Type de renvoi
Description
add
Set element e
Boolean
Ajoute un élément à l'ensemble s'il n'est pas déjà présent.
Cette méthode renvoie true si l'ensemble d'origine a été
modifié suite à l'appel. Par exemple :
set<string> myString =
new Set<String>{'a', 'b', 'c'};
Boolean result;
Référence
Nom
salesforce | Méthodes Collection Apex | 428
Arguments
Type de renvoi
Description
result = myString.add('d');
system.assertEquals(result, true);
addAll
List l
Boolean
Ajoute tous les éléments de la liste spécifiée à l'ensemble
s'ils ne sont pas déjà présents. Cette méthode entraîne
l'union de la liste et de l'ensemble. La liste doit être de
même type que l'ensemble qui appelle la méthode.
Cette méthode renvoie true si l'ensemble d'origine a
été modifié suite à l'appel.
addAll
Set s
Boolean
Ajoute tous les éléments de l'ensemble spécifié à
l'ensemble qui appelle la méthode s'il ne sont pas déjà
présents. Cette méthode entraîne l'union des deux
ensembles. L'ensemble spécifié doit être de même type
que l'ensemble d'origine qui appelle la méthode.
Cette méthode renvoie true si l'ensemble d'origine a
été modifié suite à l'appel. Par exemple :
set<string> myString =
new Set<String>{'a', 'b'};
set<string> sString =
new Set<String>{'c'};
Boolean result1;
result1 = myString.addAll(sString);
system.assertEquals(result1, true);
clear
Void
Renvoie tous les éléments à partir de l'ensemble.
clone
Set (de même type)
Effectue une copie de l'ensemble.
Boolean
Renvoie true si l'ensemble contient l'élément spécifié.
Par exemple :
contains
Set element e
set<string> myString =
new Set<String>{'a', 'b'};
Boolean result;
result = myString.contains('z');
system.assertEquals(result, false);
Référence
salesforce | Méthodes Collection Apex | 429
Nom
Arguments
Type de renvoi
Description
containsAll
List l
Boolean
Renvoie true si l'ensemble contient tous les éléments
de la liste spécifiée. La liste doit être de même type que
l'ensemble qui appelle la méthode.
containsAll
Set s
Boolean
Renvoie true si l'ensemble contient tous les éléments
de l'ensemble spécifié. L'ensemble spécifié doit être de
même type que l'ensemble d'origine qui appelle la
méthode. Par exemple :
set<string> myString =
new Set<String>{'a', 'b'};
set<string> sString =
new Set<String>{'c'};
set<string> rString =
new Set<String>{'a', 'b', 'c'};
Boolean result1, result2;
result1 = myString.addAll(sString);
system.assertEquals(result1, true);
result2 = myString.containsAll(rString);
system.assertEquals(result2, true);
Boolean
isEmpty
Renvoie true si l'ensemble compte zéro élément. Par
exemple :
Set<integer> mySet =
new Set<integer>();
Boolean result;
result = mySet.isEmpty();
system.assertEquals(result, true);
remove
Set Element e
Boolean
Supprime l'élément spécifié de l'ensemble s'il est présent.
Cette méthode renvoie true si l'ensemble d'origine a
été modifié suite à l'appel.
removeAll
List l
Boolean
Supprime les éléments de la liste spécifiée de l'ensemble
s'ils sont présents. Cette méthode entraîne le complément
Référence
Nom
salesforce | Méthodes Collection Apex | 430
Arguments
Type de renvoi
Description
relatif des deux ensembles. La liste doit être de même
type que l'ensemble qui appelle la méthode.
Cette méthode renvoie true si l'ensemble d'origine a
été modifié suite à l'appel. Par exemple :
Set<integer> mySet =
new Set<integer>{1, 2, 3};
List<integer> myList =
new List<integer>{1, 3};
Boolean result =
mySet.removeAll(myList);
System.assertEquals(result, true);
Integer result2 = mySet.size();
System.assertEquals(result2, 1);
removeAll
Set s
Boolean
Supprime les éléments de l'ensemble spécifié de
l'ensemble d'origine s'ils sont présents. Cette méthode
entraîne le complément relatif des deux ensembles.
L'ensemble spécifié doit être de même type que
l'ensemble d'origine qui appelle la méthode.
Cette méthode renvoie true si l'ensemble d'origine a
été modifié suite à l'appel.
retainAll
List l
Boolean
Conserve uniquement les éléments de cet ensemble qui
sont inclus dans la liste spécifiée. Cette méthode entraîne
l'intersection de la liste et de l'ensemble. La liste doit être
de même type que l'ensemble qui appelle la méthode.
Cette méthode renvoie true si l'ensemble d'origine a
été modifié suite à l'appel. Par exemple :
Set<integer> mySet =
new Set<integer>{1, 2, 3};
List<integer> myList =
new List<integer>{1, 3};
Boolean result =
mySet.retainAll(myList);
Référence
Nom
salesforce | Méthodes Enum | 431
Arguments
Type de renvoi
Description
System.assertEquals(result, true);
retainAll
Set s
Boolean
Conserve uniquement les éléments de l'ensemble
d'origine qui sont inclus dans la liste spécifiée. Cette
méthode entraîne l'intersection des deux ensembles.
L'ensemble spécifié doit être de même type que
l'ensemble d'origine qui appelle la méthode.
Cette méthode renvoie true si l'ensemble d'origine a
été modifié suite à l'appel.
size
Integer
Renvoie le nombre d'éléments de l'ensemble (sa
cardinalité). Par exemple :
Set<integer> mySet =
new Set<integer>{1, 2, 3};
List<integer> myList =
new List<integer>{1, 3};
Boolean result =
mySet.retainAll(myList);
System.assertEquals(result, true);
Integer result2 = mySet.size();
System.assertEquals(result2, 2);
Pour plus d'informations sur le type Set, reportez-vous à Sets à la page 46.
Méthodes Enum
Bien que des méthodes définies par l'utilisateur ne peuvent pas être ajoutées à des valeurs Enum, toutes les valeurs d'énumération,
y compris les valeurs d'énumération système, ont les méthodes suivantes définies dans Apex :
Nom
Type de renvoi
Description
name
String
Renvoie le nom de l'élément Enum sous forme de chaîne.
ordinal
Integer
Renvoie la position de l'élément dans la liste des valeurs
d'énumération, en commençant par zéro.
Référence
salesforce | Méthodes sObject Apex | 432
Enum inclut également la méthode ci-dessous.
Nom
Type de renvoi
Description
valeurs
List<Enum type>
Renvoie les valeurs de l'énumération sous forme de liste du
même type d'énumération.
Par exemple :
Integer i = StatusCode.DELETE_FAILED.ordinal();
String s = StatusCode.DELETE_FAILED.name();
List<StatusCode> values = StatusCode.values();
Pour plus d'informations sur le type Enum, reportez-vous à Enums à la page 53.
Méthodes sObject Apex
Le terme sObject fait référence à tout objet qui peut être stocké dans la base de données de la plate-forme Salesforce. Les
méthodes sObject Apex suivantes contiennent des méthodes qui peuvent être utilisées avec tous les sObjects ainsi qu'avec les
classes plus générales décrivant des structures de sObject :
•
•
•
•
•
•
Schema
sObject
sObject Describe Results
Field Describe Results
Méthodes Schema.FieldSet
Custom Settings
Méthodes Schéma
Le tableau suivant répertorie les méthodes système pour Schema.
Nom
getGlobalDescribe
Arguments
Type de renvoi
Description
Map<String,
Schema.SObjectType>
Renvoie un mappage de tous les
noms (clés) de sObject avec les
jetons (valeurs) de sObject pour
les objets standard et
personnalisés définis dans votre
organisation. Par exemple :
Map<String,
Schema.SObjectType> gd
=
Référence
Nom
salesforce | Méthodes sObject Apex | 433
Arguments
Type de renvoi
Description
Schema.getGlobalDescribe();
Pour plus d'informations,
reportez-vous à Accès à tous les
sObjects à la page 207.
describeDataCategory
Groups
String
List<Schema.Describe
List<sObjectNames> DataCategoryGroupResult>
Renvoie une liste des groupes de
catégories associés aux objets
spécifiés. Vous pouvez spécifier
l'un des sObjectNames suivants
:
• KnowledgeArticleVersion
: pour récupérer des groupes
de catégories associés à des
types d'article.
• Question : pour récupérer
des groupes de catégories
associés à des questions.
Pour plus d'informations et des
exemples de code utilisant des
groupes describeDataCategory,
reportez-vous à Accès à toutes
les catégories de données
associées à un sObject.
Pour des informations
supplémentaires sur les articles
et les questions, reportez-vous à
« Gestion des articles et des
traductions » et à « Présentation
des réponses » dans l'aide en
ligne de Salesforce.
describeDataCategory
GroupStructures
pairs,
List<Schema.Describe
Renvoie les groupes de catégories
topCategoriesOnly DataCategoryGroupStructureResult> disponibles avec leur structure de
catégorie de données pour les
objets spécifiés dans la requête.
Pour plus d'informations et des
exemples de code utilisant des
GroupStructures
describeDataCategory,
reportez-vous à Accès à toutes
les catégories de données
associées à un sObject.
Référence
salesforce | Méthodes sObject Apex | 434
Arguments de structure de groupe de catégories de données de description
La méthode GroupStructures describeDataCategory renvoie les groupes de catégories disponibles avec leur structure de
catégorie de données. Les arguments ci-dessous sont les arguments pour cette méthode.
Nom
Type de renvoi
Description
pairs
List<Schema.DataCategoryGroupSobjectTypePair> Spécifie un ou plusieurs groupes de catégories et
objets pour demander
Schema.DataCategoryGroupSobjectTypePair.
Les catégories de données visibles sont récupérées
pour l'objet spécifié.
Pour plus d'informations sur la visibilité des
groupes de catégories, reportez-vous à « À propos
de la visibilité des groupes de catégories » dans
l'aide en ligne de Salesforce.
topCategoriesOnly
Boolean
Spécifie true pour renvoyer uniquement la
catégorie la plus visible qui classe l'objet. Spécifie
false pour renvoyer toutes les catégories parents
et enfants visibles. Les deux valeurs dépendent des
paramètres de visibilité des groupes de catégories
de données de l'utilisateur. Pour plus
d'informations sur la visibilité des groupes de
catégories, reportez-vous à « À propos de la
visibilité des groupes de catégories » dans l'aide
en ligne de Salesforce.
Objet Schema.DataCategoryGroupSobjectTypePair
Schema.DataCategoryGroupSobjectTypePair spécifie un groupe de catégories et un objet associé. Il est utilisé par la méthode
describeDataCategory GroupStructures pour renvoyer les catégories disponibles pour cet objet. Le tableau suivant répertorie
toutes les méthodes pour Schema.DataCategoryGroupSobjectTypePair.
Nom
Type de
renvoi
Description
getDataCategoryGroupName
String
Renvoie le nom unique utilisé par l'API pour
accéder au groupe de catégories de données.
getSobject
String
Renvoie le nom d'objet associé au groupe de
catégories de données.
setDataCategoryGroupName
String
Spécifie le nom unique utilisé par l'API pour
accéder au groupe de catégories de données.
setSobject
Arguments
String sObjectName
Void
Le sObjectName est le nom d'objet associé au
groupe de catégories de données. Les valeurs
valides sont :
•
KnowledgeArticleVersion : pour les types
d'article.
•
Question : pour les questions depuis
Réponses.
Référence
salesforce | Méthodes sObject Apex | 435
Objet Schema.DescribeDataCategoryGroupResult
La méthode describeDataCategory Groups renvoie un objet Schema.DescribeDataCategoryGroupResult contenant la
liste des groupes de catégories associés à l'objet spécifié.
L'exemple suivant montre comment instancier un objet de résultat de description de groupe de catégories de données :
List <String> objType = new List<String>();
objType.add('KnowledgeArticleVersion');
objType.add('Question');
List<Schema.DescribeDataCategoryGroupResult> describeCategoryResult =
Schema.describeDataCategoryGroups(objType);
Pour plus d'informations et des exemples de code utilisant describeDataCategory Groups, reportez-vous à Accès à
toutes les catégories de données associées à un sObject.
Le tableau suivant répertorie toutes les méthodes disponibles dans le résultat de description de groupe de catégories de données.
Aucune méthode ne prend d'argument.
Nom
Type de renvoi
Description
getCategoryCount
Integer
Renvoie le nombre de catégories de données visibles
dans le groupe de catégories de données.
getDescription
String
Renvoie la description du groupe de catégories de
données.
getLabel
String
Renvoie l'étiquette du groupe de catégories de
données utilisée dans l'interface utilisateur de
Salesforce.
getName
String
Renvoie le nom unique utilisé par l'API pour accéder
au groupe de catégories de données.
getSobject
String
Renvoie le nom d'objet associé au groupe de
catégories de données.
Objet Schema.DescribeDataCategoryGroupStructureResult
La méthode describeDataCategory GroupStructures renvoie une liste d'objets Schema.Describe
DataCategoryGroupStructureResult contenant les groupes de catégories et les catégories associés à l'objet spécifié.
L'exemple suivant montre comment instancier un objet de résultat de description de structure de groupe de catégories de
données :
List <DataCategoryGroupSobjectTypePair> pairs =
new List<DataCategoryGroupSobjectTypePair>();
DataCategoryGroupSobjectTypePair pair1 =
new DataCategoryGroupSobjectTypePair();
Référence
salesforce | Méthodes sObject Apex | 436
pair1.setSobject('KnowledgeArticleVersion');
pair1.setDataCategoryGroupName('Regions');
DataCategoryGroupSobjectTypePair pair2 =
new DataCategoryGroupSobjectTypePair();
pair2.setSobject('Questions');
pair2.setDataCategoryGroupName('Regions');
pairs.add(pair1);
pairs.add(pair2);
List<Schema.DescribeDataCategoryGroupStructureResult>results =
Schema.describeDataCategoryGroupStructures(pairs, true);
Pour plus d'informations et des exemples de code utilisant des GroupStructures describeDataCategory, reportez-vous
à Accès à toutes les catégories de données associées à un sObject.
Le tableau suivant répertorie toutes les méthodes disponibles dans le résultat de description de structure de groupe de catégories
de données. Aucune méthode ne prend d'argument.
Nom
Type de renvoi
Description
getDescription
String
Renvoie la description du groupe de catégories de
données.
getLabel
String
Renvoie l'étiquette du groupe de catégories de
données utilisée dans l'interface utilisateur de
Salesforce.
getName
String
Renvoie le nom unique utilisé par l'API pour accéder
au groupe de catégories de données.
getSobject
String
Renvoie le nom de l'objet associé au groupe de
catégories de données.
getTopCategories
List<Schema.DataCategory>
Renvoie un objet Schema.DataCategory contenant
les catégories les plus visibles, selon les paramètres
de visibilité des groupes de catégories de données de
l'utilisateur. Pour plus d'informations sur la visibilité
des groupes de catégories, reportez-vous à « À propos
de la visibilité des groupes de catégories » dans l'aide
en ligne de Salesforce.
Objet Schema.DataCategory
Un objet Schema.DataCategory représente les catégories au sein d'un groupe de catégories. L'objet Schema.DataCategory est
renvoyé par la méthode getTopCategories. Le tableau suivant répertorie toutes les méthodes pour l'objet
Schema.DataCategory. Aucune méthode ne prend d'argument.
Référence
salesforce | Méthodes sObject Apex | 437
Nom
Type de renvoi
Description
getChildCategories
List<Schema.DataCategory>
Renvoie un objet récursif contenant les
sous-catégories visibles dans la catégorie de données.
getLabel
String
Renvoie l'étiquette de la catégorie de données utilisée
dans l'interface utilisateur de Salesforce.
getName
String
Renvoie le nom unique utilisé par l'API pour accéder
à la catégorie de données.
Méthodes sObject
Les méthodes sObject sont toutes des méthodes d'instance, c.-à-d. qu'elles sont appelées par un opérateur dans une instance
particulière d'un sObject, tel qu'un compte ou un contact. Les méthodes ci-dessous sont les méthodes d'instance pour sObjects.
Nom
Arguments
Type de renvoi
Description
addError
String errorMsg
Void
Marque un enregistrement avec un message
d'erreur personnalisé et empêche toute
opération DML de se produire.
L'argument errorMsg est le message d'erreur
avec lequel marquer l'enregistrement.
Lorsqu'elle est utilisée dans Trigger.new,
dans les déclencheurs before insert et
before update, et dans Trigger.old, dans
les déclencheurs before delete, le message
d'erreur est affiché dans l'interface de
l'application.
Reportez-vous à Déclencheurs et Exceptions
de déclencheur.
Lorsqu'elle est utilisée dans des contrôleurs
Visualforce, le message créé est ajouté à la
collection d'erreurs de la page. Pour plus
d'informations, reportez-vous à Validation
Rules and Standard Controllers dans le guide
Visualforce Developer's Guide.
addError
Exception exception
Marque un enregistrement avec un message
d'erreur personnalisé et empêche toute
opération DML de se produire.
L'argument exception est un objet Exception
ou un objet d'exception personnalisé contenant
le message d'erreur avec lequel marquer
l'enregistrement.
Lorsqu'elle est utilisée dans Trigger.new,
dans les déclencheurs before insert et
Référence
Nom
salesforce | Méthodes sObject Apex | 438
Arguments
Type de renvoi
Description
before update, et dans Trigger.old, dans
les déclencheurs before delete, le message
d'erreur est affiché dans l'interface de
l'application.
Reportez-vous à Déclencheurs et Exceptions
de déclencheur.
Lorsqu'elle est utilisée dans des contrôleurs
Visualforce, le message créé est ajouté à la
collection d'erreurs de la page. Pour plus
d'informations, reportez-vous à Validation
Rules and Standard Controllers dans le guide
Visualforce Developer's Guide.
field.addError
String errorMsg
Void
Place le message d'erreur spécifié dans le champ
qui appelle cette méthode dans l'interface de
l'application, et empêche toute opération DML
de se produire. Par exemple :
Trigger.new[0].myField__C.addError('bad');
Remarque :
•
•
•
•
Lorsqu'elle est utilisée dans Trigger.new,
dans les déclencheurs before insert et
before update, et dans Trigger.old,
dans les déclencheurs before delete, le
message d'erreur est affiché dans l'interface
de l'application.
Lorsqu'elle est utilisée dans des contrôleurs
Visualforce, si un composant inputField
est lié au champ, le message est joint au
composant. Pour plus d'informations,
reportez-vous à Validation Rules and
Standard Controllers dans le guide
Visualforce Developer's Guide.
Cette méthode est hautement spécialisée,
car en réalité l'identifiant de champ n'est
pas l'objet qui invoque, c'est
l'enregistrement de sObject qui invoque.
Le champ est utilisé seulement pour
identifier le champ à utiliser pour afficher
l'erreur.
Cette méthode sera probablement modifiée
dans les prochaines versions d'Apex.
Reportez-vous à Déclencheurs et Exceptions
de déclencheur.
Référence
Nom
salesforce | Méthodes sObject Apex | 439
Arguments
clear
clone
Type de renvoi
Description
Void
Efface toutes les valeurs de champ.
Boolean opt_preserve_id
sObject (de même Crée une copie de l'enregistrement de sObject.
type)
Boolean opt_IsDeepClone
L'argument facultatif opt_preserve_id
détermine si l'ID de l'objet d'origine est
Boolean
conservé ou effacé dans la copie. Si true, l'ID
opt_preserve_readonly_timestamps
est copié dans la copie. La valeur par défaut est
Boolean
false, c.-à-d. que l'ID est effacé.
opt_preserve_autonumber
Remarque: Pour un code Apex
enregistré en utilisant l'API
Salesforce.com version 22.0 ou
antérieure, la valeur par défaut de
l'argument opt_preserve_id est
true, c.-à-d. que l'ID est conservé.
L'argument facultatif opt_IsDeepClone
détermine si la méthode crée une copie
complète du champ de sObject ou seulement
une référence :
•
•
Si true, la méthode crée une copie
complète du sObject. Tous les champs du
sObject sont copiés en mémoire, y compris
les champs de relation. Par conséquent, si
vous modifiez un champ sur un sObject
cloné, le sObject d'origine n'est pas affecté.
Si false, la méthode crée une copie
superficielle des champs du sObject. Toutes
les champs de relation copiés référencent
les sObjects d'origine. Par conséquent, si
vous modifiez un champ de relation sur le
sObject cloné, le champ correspondant sur
le sObject d'origine est également affecté,
et inversement. Le paramètre par défaut est
false.
L'argument facultatif
opt_preserve_readonly_timestamps
détermine si les champs d'horodatage en lecture
seule sont conservés ou effacés dans la copie.
Si true, les champs en lecture seule
CreatedById, CreatedDate,
LastModifiedById et LastModifiedDate
sont copiés dans la copie. La valeur par défaut
est false, c.-à-d. que les valeurs sont effacées.
L'argument facultatif
opt_preserve_autonumber détermine si les
Référence
Nom
salesforce | Méthodes sObject Apex | 440
Arguments
Type de renvoi
Description
champs à numérotation automatique de l'objet
d'origine sont conservés ou effacés dans la
copie. Si true, les champs à numérotation
automatique sont copiés dans l'objet cloné. La
valeur par défaut est false, c.-à-d. que les
champs à numérotation automatique sont
effacés.
get
String fieldName
Object
Renvoie la valeur du champ spécifié par
fieldName, tel que AccountNumber.
Pour plus d'informations, reportez-vous à
SOQL dynamique.
get
Schema.sObjectField Field
Object
Renvoie la valeur du champ spécifié par le jeton
de champ Schema.sObjectField (par
exemple,
Schema.Account.AccountNumber).
Pour plus d'informations, reportez-vous à
SOQL dynamique.
Database.
DMLOptions
getOptions
Renvoie l'objet database.DMLOptions du
sObject.
Pour plus d'informations, reportez-vous à
Propriétés Database DMLOptions.
getSObject
String fieldName
sObject
Renvoie la valeur du champ spécifié par
fieldName. Cette méthode est utilisée
principalement avec une instruction DML
dynamique pour accéder aux valeurs d'ID
externes.
Pour plus d'informations, reportez-vous à
DML dynamique.
getSObject
Schema.SObjectField fieldName sObject
Renvoie la valeur du champ spécifié par le jeton
de champ Schema.fieldName (par exemple,
Schema.MyObj.MyExternalId). Cette
méthode est utilisée principalement avec une
instruction DML dynamique pour accéder aux
valeurs d'ID externes.
Pour plus d'informations, reportez-vous à
DML dynamique.
getSObjects
String fieldName
sObject[]
Renvoie les valeurs du champ spécifié par
fieldName. Cette méthode est utilisée
principalement avec une instruction DML
Référence
Nom
salesforce | Méthodes sObject Apex | 441
Arguments
Type de renvoi
Description
dynamique pour accéder aux valeurs des objets
associés, tels que des relations enfants.
Pour plus d'informations, reportez-vous à
DML dynamique.
getSObjects
Schema.SObjectType fieldName sObject[]
Renvoie la valeur du champ spécifié par le jeton
de champ Schema.fieldName (par exemple,
Schema.Account.Contact). Cette méthode
est utilisée principalement avec une instruction
DML dynamique pour accéder aux valeurs des
objets associés, tels que des relations enfants.
Pour plus d'informations, reportez-vous à
DML dynamique.
Schema.SObjectType Renvoie le jeton de ce sObject. Cette méthode
est utilisée principalement avec l'information
describe.
getSObjectType
Pour plus d'informations, reportez-vous à
Compréhension de l'information Describe
Apex.
put
String fieldName
Object
Object value
Définit la valeur du champ spécifié par
fieldName et renvoie la valeur précédente de
ce champ.
Pour plus d'informations, reportez-vous à
SOQL dynamique.
put
Schema.SObjectField fieldName Object
Object value
Définit la valeur du champ spécifié par le jeton
de champ Schema.sObjectField (par
exemple,
Schema.Account.AccountNumber).
Pour plus d'informations, reportez-vous à
SOQL dynamique.
putSObject
String fieldName
sObject
sObject value
Définit la valeur du champ spécifié par
fieldName. Cette méthode est utilisée
principalement avec une instruction DML
dynamique pour la définition des ID externes.
La méthode renvoie la valeur précédente du
champ.
Pour plus d'informations, reportez-vous à
SOQL dynamique.
putSObject
Schema.sObjectType fieldName sObject
sObject value
Définit la valeur du champ spécifié par le jeton
Schema.sObjectType. Cette méthode est
utilisée principalement avec une instruction
Référence
Nom
salesforce | Méthodes sObject Apex | 442
Arguments
Type de renvoi
Description
DML dynamique pour la définition des ID
externes. La méthode renvoie la valeur
précédente du champ.
Pour plus d'informations, reportez-vous à
SOQL dynamique.
setOptions
database.DMLOptions
DMLOptions
Void
Définit l'objet DMLOptions du sObject.
Pour plus d'informations, reportez-vous à
Propriétés Database DMLOptions.
Pour plus d'informations sur les sObjects, reportez-vous à Types sObject à la page 32.
Méthodes de résultat de description de sObject
Le tableau suivant décrit les méthodes disponibles pour le résultat de description de sObject, l'objet DescribeSObjectResult.
Aucune méthode ne prend d'argument.
Nom
Type de données
Description
fields
Spécial
Renvoie un type de données spécial qui ne doit pas
être utilisé seul. La méthode fields doit toujours
être suivie par un nom de variable de membre de
champ ou par la méthode getMap. Par exemple :
Schema.DescribeFieldResult F =
Schema.SObjectType.Account.fields.Name;
Pour plus d'informations, reportez-vous à
Compréhension de l'information Describe Apex.
fieldSets
Spécial
Renvoie un type de données spécial qui ne doit pas
être utilisé seul. La méthode fieldsSets doit
toujours être suivie par un nom d'ensemble de champ
ou par la méthode getMap. Par exemple :
Schema.DescribeSObjectResult d =
Account.sObjectType.getDescribe();
Map<String, Schema.FieldSet> FsMap =
d.fieldSets.getMap();
Pour plus d'informations, reportez-vous à Méthodes
Schema.FieldSet.
Référence
salesforce | Méthodes sObject Apex | 443
Nom
Type de données
Description
getChildRelationships
List<Schema.ChildRelationship> Renvoie une liste de relations enfants, qui
correspondent aux noms des sObjects ayant une clé
étrangère pour le sObject décrit. Par exemple, l'objet
Compte a Contacs et Opportunités comme
relations enfants.
getKeyPrefix
String
Renvoie le code du préfixe à trois caractères de l'objet.
Les ID d'enregistrement ont un préfixe avec des codes
de trois caractères qui spécifie le type de l'objet (par
exemple, les comptes ont un préfixe 001 et les
opportunités ont un préfixe 006).
L'objet DescribeSobjectResult renvoie une valeur des
objets ayant un préfixe stable. Pour les types d'objet
n'ayant pas de préfixe stable ou prévisible, ce champ
est vide. Les applications clientes qui dépendent de
ces codes peuvent utiliser cette méthode de
détermination du type d'objet pour la compatibilité
ascendante.
getLabel
String
Renvoie l'étiquette de l'objet, qui peut correspondre
ou non au nom de l'objet. Par exemple, une
organisation dans le secteur médical peut changer
l'étiquette Compte en Patient. Cette étiquette est
ensuite utilisée dans l'interface utilisateur de
Salesforce. Pour plus d'informations, reportez-vous
à l'aide en ligne de Salesforce.
getLabelPlural
String
Renvoie l'étiquette plurielle de l'objet, qui peut
correspondre ou non au nom de l'objet. Par exemple,
une organisation dans le secteur médical peut changer
l'étiquette Comptes en Patients. Cette étiquette est
ensuite utilisée dans l'interface utilisateur de
Salesforce. Pour plus d'informations, reportez-vous
à l'aide en ligne de Salesforce.
getLocalName
String
Renvoie le nom de l'objet, similaire à la méthode
getName. Cependant, si l'objet fait partie de l'espace
de noms actuel, la partie espace de noms du nom est
ignorée.
getName
String
Renvoie le nom de l'objet.
getRecordTypeInfos
List<Schema.RecordTypeInfo>
Renvoie une liste des types d'enregistrement pris en
charge par cet objet. Il n'est pas nécessaire que
l'utilisateur dispose d'un accès au type
d'enregistrement pour l'afficher dans cette liste.
getRecordTypeInfosByID
Map<ID,
Schema.RecordTypeInfo>
Renvoie un mappage des ID d'enregistrement avec
leur type d'enregistrement associé. Il n'est pas
Référence
Nom
salesforce | Méthodes sObject Apex | 444
Type de données
Description
nécessaire que l'utilisateur actuel ait accès au type
d'enregistrement pour l'afficher dans ce mappage.
getRecordTypeInfosByName Map<String,
Schema.RecordTypeInfo>
Renvoie un mappage des étiquettes d'enregistrement
avec leur type d'enregistrement associé. Il n'est pas
nécessaire que l'utilisateur actuel ait accès au type
d'enregistrement pour l'afficher dans ce mappage.
getSobjectType
Schema.SObjectType
Renvoie l'objet Schema.SObjectType du sObject.
Vous pouvez l'utiliser pour créer un sObject similaire.
Pour plus d'informations, reportez-vous
à Schema.SObjectType.
isAccessible
Boolean
Renvoie true si l'utilisateur actuel peut afficher ce
champ, sinon renvoie false.
isCreateable
Boolean
Renvoie true si l'objet peut être créé par l'utilisateur
actuel, sinon renvoie false.
isCustom
Boolean
Renvoie true si l'objet est un champ personnalisé,
renvoie false si l'objet est standard.
isCustomSetting
Boolean
Renvoie true si l'objet est un paramètre personnalisé,
sinon renvoie false.
isDeletable
Boolean
Renvoie true si l'objet peut être supprimé par
l'utilisateur actuel, sinon renvoie false.
isDeprecatedAndHidden
Boolean
Réservé pour une utilisation future.
isFeedEnabled
Boolean
Renvoie true si des fils Chatter sont activés pour
l'objet, sinon renvoie false. Cette méthode est
disponible uniquement pour les classes et
déclencheurs Apex enregistrés en utilisant l'API
Salesforce.com versions 19.0 et ultérieures.
isMergeable
Boolean
Renvoie true si l'objet peut être fusionné avec
d'autres objets de ce type par l'utilisateur actuel, sinon
renvoie false. true est renvoyé pour des pistes, des
contacts ou des comptes.
isQueryable
Boolean
Renvoie true si l'objet peut être demandé par
l'utilisateur actuel, sinon renvoie false.
isSearchable
Boolean
Renvoie true si l'objet peut être recherché par
l'utilisateur actuel, sinon renvoie false.
isUndeletable
Boolean
Renvoie true si l'objet ne peut pas être restauré par
l'utilisateur actuel, sinon renvoie false.
isUpdateable
Boolean
Renvoie true si l'objet peut être mis à jour par
l'utilisateur actuel, sinon renvoie false.
Référence
salesforce | Méthodes sObject Apex | 445
Méthodes ChildRelationship
Si un sObject est un objet parent, vous pouvez accéder à la relation enfant ainsi qu'au sObject enfant à l'aide des méthodes
d'objet ChildRelationship.
Un objet ChildRelationship est renvoyé à partir du résultat de description de sObject en utilisant la méthode
getChildRelationship. Par exemple :
Schema.DescribeSObjectResult R = Account.SObjectType.getDescribe();
List<Schema.ChildRelationship> C = R.getChildRelationships();
Vous pouvez utiliser 100 appels de méthode getChildRelationship par demande Apex seulement. Pour plus d'informations
sur les limitations du gouverneur, reportez-vous à Compréhension des limitations et des gouverneurs d'exécution à la page
273.
Le tableau suivant décrit les méthodes disponibles pour l'objet ChildRelationship. Aucune méthode ne prend d'argument.
Nom
Type de données
Description
getChildSObject
Schema.SObjectType
Renvoie le jeton du sObject enfant pour lequel une
clé étrangère existe sur le sObject parent.
getField
Schema.SObjectField
Renvoie le jeton du champ qui a une clé étrangère
dans le sObject parent.
getRelationshipName
String
Renvoie le nom de la relation.
isCascadeDelete
Boolean
Renvoie true si l'objet enfant est supprimé lorsque
l'objet parent est supprimé, sinon renvoie false.
isDeprecatedAndHidden
Boolean
Réservé pour une utilisation future.
isRestrictedDelete
Boolean
Renvoie true si l'objet parent ne peut pas être
supprimé parce qu'il est référencé par un objet enfant,
sinon renvoie false.
Méthodes RecordTypeInfo
Si un type d'enregistrement est associé à un sObject, vous pouvez accéder aux informations sur le type d'enregistrement en
utilisant les méthodes d'objet RecordTypeInfo.
Un objet RecordTypeInfo est renvoyé à partir du résultat de description de sObject en utilisant la méthode
getRecordTypeInfos. Par exemple :
Schema.DescribeSObjectResult R = Account.SObjectType.getDescribe();
List<Schema.RecordTypeInfo> RT = R.getRecordTypeInfos();
En plus de la méthode getRecordTypeInfos, vous pouvez utiliser les méthodes getRecordTypeInfosById et
getRecordTypeInfosByName. Ces méthodes renvoient les mappages qui associent RecordTypeInfo respectivement à des
ID d'enregistrement et à des étiquettes d'enregistrement.
Vous pouvez renvoyer 100 objets RecordTypeInfo par requête Apex seulement. Pour plus d'informations sur les limitations
du gouverneur, reportez-vous à Compréhension des limitations et des gouverneurs d'exécution à la page 273.
Référence
salesforce | Méthodes sObject Apex | 446
L'exemple suivant suppose qu'un type d'enregistrement au moins a été créé pour l'objet Account :
RecordType rt = [SELECT Id,Name FROM RecordType WHERE SobjectType='Account' LIMIT 1];
Schema.DescribeSObjectResult d = Schema.SObjectType.Account;
Map<Id,Schema.RecordTypeInfo> rtMapById = d.getRecordTypeInfosById();
Schema.RecordTypeInfo rtById =
rtMapById.get(rt.id);
Map<String,Schema.RecordTypeInfo> rtMapByName = d.getRecordTypeInfosByName();
Schema.RecordTypeInfo rtByName =
rtMapByName.get(rt.name);
System.assertEquals(rtById,rtByName);
Le tableau suivant décrit les méthodes disponibles pour l'objet RecordTypeInfo. Aucune méthode ne prend d'argument.
Nom
Type de données
Description
getName
String
Renvoie le nom de ce type d'enregistrement.
getRecordTypeId
ID
Renvoie l'ID de ce type d'enregistrement.
isAvailable
Boolean
Renvoie true si ce type d'enregistrement est
disponible pour l'utilisateur actuel, sinon renvoie
false. Utilisez cette méthode pour afficher une liste
des types d'enregistrement disponibles pour
l'utilisateur lorsqu'il crée un enregistrement.
isDefaultRecordTypeMapping Boolean
Renvoie true s'il s'agit du mappage de type
d'enregistrement par défaut, sinon renvoie false.
Méthodes Describe Field Result
Le tableau suivant présente les méthodes disponibles dans les résultats de description de champ. L'exemple suivant montre
comment instancier un objet de résultat de description de champ :
Schema.DescribeFieldResult F = Account.AccountNumber.getDescribe();
Aucune méthode ne prend d'argument.
Nom
Type de données
Description
getByteLength
Integer
Pour les champs à longueur variable (y compris les
champs binaires), renvoie la taille maximale du
champ, en octets
getCalculatedFormula
String
Renvoie la formule spécifiée pour ce champ
getController
Schema.sObjectField
Renvoie le jeton du champ de contrôle
getDefaultValue
Object
Renvoie la valeur par défaut pour ce champ
Référence
salesforce | Méthodes sObject Apex | 447
Nom
Type de données
Description
getDefaultValueFormula
String
Renvoie la valeur par défaut spécifiée pour ce champ
si une formule n'est pas utilisée
getDigits
Integer
Renvoie le nombre maximal de chiffres spécifié pour
ce champ. Cette méthode est valide uniquement avec
des champs Integer
getInlineHelpText
String
Renvoie le contenu de l'aide au niveau du champ.
Pour plus d'informations, reportez-vous à Définition
de l'aide au niveau du champ.
getLabel
String
Renvoie l'étiquette du texte affiché en regard du
champ dans l'interface utilisateur de Salesforce. Cette
étiquette peut être traduite.
getLength
Integer
Pour les champs de chaîne, renvoie la taille maximale
du champ en caractères Unicode (pas en octets)
getLocalName
String
Renvoie le nom du champ, similaire à la méthode
getName. Cependant, si le champ fait partie de
l'espace de noms actuel, la partie espace de noms est
ignorée.
getName
String
Renvoie le nom de champ utilisé dans le code Apex
getPicklistValues
List <Schema.PicklistEntry>
Renvoie une liste d'objets PicklistEntry. Une erreur
d'exécution est renvoyée si le champ n'est pas une
liste de sélection.
getPrecision
Integer
Pour les champs de type Double, renvoie le nombre
maximal de chiffres pouvant être stockés, qui
comprennent les chiffres à gauche et à droite de la
virgule (mais pas le caractère décimal)
getReferenceTo
List <Schema.sObjectType>
Renvoie une liste d'objets Schema.sObjectType pour
les objets parents de ce champ. Si la méthode
isNamePointing renvoie true, plusieurs entrées
existent dans la liste, sinon une seule existe.
getRelationshipName
String
Renvoie le nom de la relation. Pour plus
d'informations sur les relations et les noms de
relation, reportez-vous à Understanding Relationship
Names dans le document Force.com SOQL and SOSL
Reference.
getRelationshipOrder
Integer
Renvoie 1 si le champ est un enfant, sinon renvoie
0. Pour plus d'informations sur les relations et les
noms de relation, reportez-vous à Understanding
Relationship Names dans le document Force.com
SOQL and SOSL Reference.
getScale
Integer
Pour les champs de type Double, renvoie le nombre
de chiffres à droite du caractère décimal. Tout chiffre
Référence
Nom
salesforce | Méthodes sObject Apex | 448
Type de données
Description
supplémentaire à droite du caractère décimal est
tronqué. Cette méthode renvoie une réponse de
défaut si le nombre de chiffres à gauche du caractère
décimal est excessif.
getSOAPType
Schema.SOAPType
Renvoie l'une des valeurs d'énumération SoapType,
en fonction du type du champ. Pour plus
d'informations, reportez-vous à Valeurs enum
Schema.SOAPType à la page 455.
getSObjectField
Schema.sObjectField
Renvoie le jeton de ce champ
getType
Schema.DisplayType
Renvoie l'une des valeurs d'énumération DisplayType,
en fonction du type du champ. Pour plus
informations, reportez-vous à Valeurs enum
Schema.DisplayType à la page 450.
isAccessible
Boolean
Renvoie true si l'utilisateur actuel peut afficher ce
champ, sinon renvoie false
isAutoNumber
Boolean
Renvoie true si le champ est un champ de
numérotation automatique, sinon renvoie false.
Similaires à un type IDENTITY SQL, les champs
à numérotation automatique sont en lecture seule, ne
peuvent pas être créés et ont une longueur maximale
de 30 caractères. Les champs à numérotation
automatique sont utilisés pour fournir un ID unique
indépendant de l'ID d'objet interne (tel qu'un numéro
de commande ou un numéro de facture). Les champs
à numérotation automatique sont entièrement
configurés dans l'interface utilisateur de Salesforce.
isCalculated
Boolean
Renvoie true si le champ est un champ de formule
personnalisé, sinon renvoie false. Notez que les
champs de formule personnalisés sont toujours en
lecture seule.
isCascadeDelete
Boolean
Renvoie true si l'objet enfant est supprimé lorsque
l'objet parent est supprimé, sinon renvoie false.
isCaseSensitive
Boolean
Renvoie true si le champ est sensible à la casse,
sinon renvoie false.
isCreateable
Boolean
Renvoie true si le champ peut être créé par
l'utilisateur actif, sinon renvoie false.
isCustom
Boolean
Renvoie true si le champ est un champ personnalisé,
false s'il est un objet standard.
isDefaultedOnCreate
Boolean
Renvoie true si le champ reçoit une valeur par défaut
à sa création, sinon renvoie false. Si true,
Salesforce attribue implicitement une valeur à ce
Référence
Nom
salesforce | Méthodes sObject Apex | 449
Type de données
Description
champ à la création de l'objet, même si aucune valeur
pour ce champ n'est passée lors de l'appel de création.
Par exemple, dans l'objet Opportunité, le champ
Probabilité a cet attribut, car sa valeur est dérivée du
champ Phase. De même, le Propriétaire a cet attribut
dans la plupart des objets, car sa valeur est dérivée de
l'utilisateur actif (si le champ Propriétaire n'est pas
spécifié).
isDependentPicklist
Boolean
Renvoie true si la liste de sélection est une liste de
sélection dépendante, sinon renvoie false.
isDeprecatedAndHidden
Boolean
Réservé pour une utilisation future.
isExternalID
Boolean
Renvoie true si le champ est utilisé en tant qu'ID
externe, sinon renvoie false.
isFilterable
Boolean
Renvoie true si le champ peut être utilisé dans le
cadre du critère de filtre d'une instruction WHERE,
sinon renvoie false.
isGroupable
Boolean
Renvoie true si le champ peut être inclus dans la
clause GROUP BY d'une requête SOQL, sinon renvoie
false. Cette méthode est disponible uniquement
pour les classes et les déclencheurs Apex enregistrés
en utilisant l'API versions 18.0 et supérieures.
isHtmlFormatted
Boolean
Renvoie true si le champ a été mis en forme pour
HTML et doit être codé pour l'affichage en HTML,
sinon renvoie false. Un champ de formule
personnalisé d'un lien hypertexte est un exemple de
champ qui renvoie true pour cette méthode. Un
champ de formule personnalisé qui a une fonction
de texte IMAGE est un autre exemple.
isIdLookup
Boolean
Renvoie true si le champ peut être utilisé pour
spécifier un enregistrement dans une méthode
upsert, sinon renvoie false.
isNameField
Boolean
Renvoie true si le champ est un champ de nom,
sinon renvoie false. Cette méthode est utilisée pour
identifier le champ de nom pour des objets standard
(tels queAccountName pour un objet Compte) et
des objets personnalisés. Les objets ne peuvent avoir
qu'un seul champ de nom, sauf lorsque des champs
Prénom et Nom sont utilisés à la place (comme dans
l'objet Contact).
Si un nom composé existe, par exemple le champ
Nom dans un compte personnel, isNameField est
défini sur true pour cet enregistrement.
Référence
salesforce | Méthodes sObject Apex | 450
Nom
Type de données
Description
isNamePointing
Boolean
Renvoie true si le champ peut avoir plusieurs types
d'objet en tant que parents. Par exemple, une tâche
qui peut avoir à la fois le champ ID de piste/ID
de contact (WhoId) et le champ ID
d'opportunité/ID de compte (WhatId)
renvoie true pour cette méthode, car ces deux objets
peuvent être le parent d'un enregistrement de tâche
particulier. Sinon, cette méthode renvoie false.
isNillable
Boolean
Renvoie true si le champ peut être nul, sinon renvoie
false. Un champ qui peut être nul peut avoir un
contenu vide. Un champ ne peut pas être nul doit
inclure une valeur pour l'objet à créer ou à enregistrer.
isPermissionable
Boolean
Renvoie true si des autorisations de champ peuvent
être spécifiées pour ce champ, sinon renvoie false.
isRestrictedDelete
Boolean
Renvoie true si l'objet parent ne peut pas être
supprimé parce qu'il est référencé par un objet enfant,
sinon renvoie false.
isRestrictedPicklist
Boolean
Renvoie true si le champ est une liste de sélection
restreinte, sinon renvoie false.
isSortable
Boolean
Renvoie true si une requête peut être triée sur le
champ, sinon renvoie false.
isUnique
Boolean
Renvoie true si une valeur pour le champ doit être
unique, sinon renvoie false.
isUpdateable
Boolean
Renvoie true si :
• Le champ peut être modifié par l'utilisateur actif,
ou
• Des enregistrements enfants dans un champ de
relation principal-détails d'un objet personnalisé
peuvent être attribués à d'autres enregistrements
parents
Sinon renvoie false.
isWriteRequiresMasterRead Boolean
Renvoie true si l'écriture dans l'objet de détail
nécessite un partage en lecture au lieu du partage en
lecture/écriture du parent.
Valeurs enum Schema.DisplayType
Une valeur d'énumération Schema.DisplayType est renvoyée par la méthode getType du résultat de description de champ.
Pour plus d'informations, reportez-vous à Field Types dans le document Object Reference for Salesforce and Force.com. Pour plus
d'informations sur les méthodes partagées par toutes les énumérations, reportez-vous à Méthodes Enum à la page 431.
Référence
salesforce | Méthodes sObject Apex | 451
Valeur de champ de type
Contenu de l'objet champ
anytype
Toute valeur de type : String, Picklist, Boolean, Integer, Double, Percent,
ID, Date, DateTime, URL ou Email.
base64
Données binaires arbitraires codées en base64 (de type base64Binary)
Boolean
Valeurs booléennes (true ou false)
Combobox
Listes déroulantes qui fournissent une série de valeurs énumérées et permettent à l'utilisateur
de spécifier une valeur ne figurant pas dans la liste
Currency
Valeurs de devise
DataCategoryGroupReference Référence à un groupe de catégorie de données ou à un nom de catégorie unique
Date
Valeurs de date
DateTime
Valeurs de date/heure
Double
Valeurs de doublons
Email
Adresses e-mail
EncryptedString
Chaîne cryptée
ID
Champ de clé primaire d'un objet
Integer
Valeurs de nombre entier
MultiPicklist
Listes de sélection multiple qui fournissent une série de valeurs énumérées dans laquelle
plusieurs valeurs peuvent être sélectionnées
Percent
Valeurs de poucentage
Phone
Numéros de téléphone. Les valeurs peuvent inclure des caractères alphanumériques. Les
applications clientes sont responsables de la mise en forme du numéro de téléphone
Picklist
Listes de sélection unique qui fournissent une série de valeurs énumérées dans laquelle
une seule valeur peut être sélectionnée
Reference
Référence croisée à un objet différent, semblable à un champ de clé étrangère
String
Valeurs de chaîne
TextArea
Valeurs de chaîne affichées en tant que champs de texte multilignes
Time
Valeurs temporelles
URL
Valeurs d'URL affichées en tant que liens hypertexte
Méthodes Schema.PicklistEntry
Les champs de liste de sélection contiennent un ou plusieurs éléments dans lesquels un utilisateur choisit un élément unique.
Ils s'affichent sous la forme de listes déroulantes dans l'interface utilisateur de Salesforce. Un élément peut être défini comme
élément par défaut.
Un objet Schema.PicklistEntry est renvoyé depuis le résultat de description de champ en utilisant la méthode
getPicklistValues. Par exemple :
Schema.DescribeFieldResult F = Account.Industry.getDescribe();
List<Schema.PicklistEntry> P = F.getPicklistValues();
Référence
salesforce | Méthodes sObject Apex | 452
Vous pouvez utiliser uniquement 100 appels de méthode getPicklistValue par demande Apex. Pour plus d'informations
sur les limitations du gouverneur, reportez-vous à Compréhension des limitations et des gouverneurs d'exécution à la page
273.
Le tableau suivant décrit les méthodes disponibles avec l'objet PicklistEntry. Aucune méthode ne prend d'argument.
Nom
Type de données
Description
getLabel
String
Renvoie le nom d'affichage de cet élément dans la liste de sélection
getValue
String
Renvoie la valeur de cet élément dans la liste de sélection
isActive
Boolean
Renvoie true si l'élément doit être affiché dans la liste déroulante du
champ de liste de sélection dans l'interface utilisateur, sinon renvoie false
isDefaultValue
Boolean
Renvoie true si l'élément est la valeur par défaut de la liste de sélection,
sinon renvoie false. Un seul élément d'une liste de sélection peut être
désigné comme valeur par défaut
Schema.sObjectField
Un objet Schema.sObjectField est renvoyé depuis le résultat de description de champ en utilisant les méthodes getControler
et getSObjectField. Par exemple :
Schema.DescribeFieldResult F = Account.Industry.getDescribe();
Schema.sObjectField T = F.getSObjectField();
Le tableau suivant présente la méthode disponible avec l'objet sObjectField. Cette méthode ne prend aucun argument.
Nom
Type de données
Description
getDescribe
Schema.DescribeFieldResult Renvoie le résultat de description de ce champ
Schema.sObjectType
Un objet Schema.sObjectType est renvoyé depuis le résultat de description de champ en utilisant la méthode getReferenceTo,
ou depuis le résultat de description de sObject en utilisant la méthode getSObjectType. Par exemple :
Schema.DescribeFieldResult F = Account.Industry.getDescribe();
List<Schema.sObjectType> P = F.getReferenceTo();
Le tableau suivant présente les méthodes disponibles avec l'objet sObjectType.
Nom
Argument
Type de données
Description
getDescribe
Schema.DescribeSObjectResult Renvoie le résultat sObject description de ce
champ
newSObject
sObject
Construit un nouveau sObject de ce type.
Pour consulter un exemple, reportez-vous à
Création de sObjects de façon dynamique.
Référence
salesforce | Méthodes sObject Apex | 453
Nom
Argument
Type de données
Description
newSObject
ID Id
sObject
Construit un nouveau sObject de ce type, avec
l'ID spécifié.
Pour cet argument, passez l'ID d'un
enregistrement existant dans la base de
données.
Une fois le nouveau sObject créé, les champs
du sObject renvoyé sont tous définis sur null.
Vous pouvez définir tout champ qui peut être
mis à jour avec les valeurs de votre choix, puis
mettre à jour l'enregistrement dans la base de
données. Seuls les champs pour lesquels vous
définissez de nouvelles valeurs sont mis à jour.
Les autres champs, qui ne sont pas des champs
système, sont conservés.
newSObject
ID
recordTypeId
Boolean
loadDefaults
sObject
Construit un nouveau sObject de ce type et,
en option, avec l'ID du type d'enregistrement
spécifié et des valeurs de champ personnalisé
par défaut.
L'argument recordTypeId spécifie l'ID de
type d'enregistrement du sObject à créer. Si
aucun type d'enregistrement n'existe pour ce
sObject, utilisez null. Si le sObject a des
types d'enregistrement et que vous spécifiez
null, le type d'enregistrement par défaut est
utilisé.
L'argument loadDefaults spécifie si les
champs personnalisés sont renseignés avec
leurs valeurs par défaut prédéfinies (true) ou
non (false).
Remarques :
•
•
•
Pour les champs obligatoires ayant des
valeurs par défaut, assurez-vous de fournir
une valeur avant d'insérer le nouveau
sObject, sinon l'insertion génère une
erreur. Le champ Nom de compte ou un
champ de relation principal-détails en sont
des exemples.
Les listes de sélection et les listes de
sélection multiple peuvent prendre des
valeurs par défaut spécifiées par type
d'enregistrement. Par conséquent, cette
méthode renseigne la valeur par défaut
correspondant au type d'enregistrement
spécifié.
Si des champs n'ont aucune valeur par
défaut prédéfinie et que l'argument
loadDefaults est true, cette méthode
Référence
Nom
salesforce | Méthodes sObject Apex | 454
Argument
Type de données
Description
•
•
•
crée le sObject avec des valeurs de champ
null.
Si l'argument loadDefaults est false,
cette méthode crée le sObject avec des
valeurs de champ null.
Cette méthode renseigne les champs
personnalisés en lecture seule du nouveau
sObject avec les valeurs par défaut. Vous
pouvez ensuite insérer le nouveau sObject
avec les champs en lecture seule, même si
ces champs ne sont pas modifiables une
fois insérés.
Si un champ personnalisé est marqué
comme unique et qu'il fournit également
une valeur par défaut, l'insertion de
plusieurs nouveaux sObjects génère une
exception d'exécution en raison des valeurs
de champ dupliquées.
Pour plus d'informations sur les valeurs de
champ par défaut, reportez-vous à « À propos
des valeurs de champ par défaut » dans l'aide
en ligne de Salesforce.
Pour un exemple, reportez-vous à Exemple :
Création d'un nouveau sObject avec des
valeurs par défaut.
Exemple : Création d'un nouveau sObject avec des valeurs par défaut
Cet exemple crée un compte avec toutes les valeurs par défaut renseignées pour ses champs personnalisés, s'il en contient, en
utilisant la méthode newSObject. Il crée également un deuxième compte pour un type d'enregistrement spécifique. L'exemple
définit le champ Nom (obligatoire et sans valeur par défaut) pour les deux comptes avant de les insérer.
// Create an account with predefined default values
Account acct = (Account)Account.sObjectType.newSObject(null, true);
// Provide a value for Name
acct.Name = 'Acme';
// Insert new account
insert acct;
// This is for record type RT1 of Account
ID rtId = [SELECT Id FROM RecordType WHERE sObjectType='Account' AND Name='RT1'].Id;
Account acct2 = (Account)Account.sObjectType.newSObject(rtId, true);
// Provide a value for Name
Référence
salesforce | Méthodes sObject Apex | 455
acct2.Name = 'Acme2';
// Insert new account
insert acct2;
Valeurs enum Schema.SOAPType
Une valeur d'énumération Schema.SOAPType est renvoyée par la méthode getSoapType de résultat de description de
champ.
Pour plus d'informations, reportez-vous à SOAPTypes dans le guide SOAP API Developer's Guide. Pour plus d'informations
sur les méthodes partagées par toutes les énumérations, reportez-vous à Méthodes Enum à la page 431.
Valeur de champ de type
Contenu de l'objet champ
anytype
Toute valeur de type : String, Boolean, Integer, Double, ID, Date ou DateTime.
base64binary
Données binaires arbitraires codées en base64 (de type base64Binary)
Boolean
Valeurs booléennes (true ou false)
Date
Valeurs de date
DateTime
Valeurs de date/heure
Double
Valeurs de doublons
ID
Champ de clé primaire d'un objet
Integer
Valeurs de nombre entier
String
Valeurs de chaîne
Time
Valeurs temporelles
Méthodes Schema.FieldSet
Contient des méthodes de découverte et de récupération des détails des ensembles de champs créés dans des sObjects.
Remarque: Cette édition contient une version bêta d'ensembles de champs prêts pour la production, mais qui inclut
des limitations connues.
Utilisation
Utilisez les méthodes de la classe Schema.FieldSet pour découvrir les champs inclus dans un ensemble de champs, et
récupérez des informations sur l'ensemble de champs lui-même, notamment le nom, l'espace de noms, l'étiquette, etc. L'exemple
suivant montre comment obtenir une collection d'objets de résultat de description d'ensemble de champs pour un sObject. La
clé du mappage renvoyé est le nom de l'ensemble de champs, et la valeur est le résultat de description d'ensemble de champs
correspondant.
Map<String, Schema.FieldSet> FsMap =
Schema.SObjectType.Account.fieldSets.getMap();
Référence
salesforce | Méthodes sObject Apex | 456
Les ensembles de champs sont également disponibles à partir des résultats de description de sObject. Les lignes de codes
suivantes sont équivalentes à l'exemple précédent :
Schema.DescribeSObjectResult d =
Account.sObjectType.getDescribe();
Map<String, Schema.FieldSet> FsMap =
d.fieldSets.getMap();
Pour travailler avec un ensemble de champs individuel, vous pouvez y accéder via le mappage d'ensembles de champs avec un
sObject, ou en utilisant une référence explicite à l'ensemble de champs si vous connaissez son nom. Les deux lignes de code
suivantes récupèrent le même ensemble de champs :
Schema.FieldSet fs1 = Schema.SObjectType.Account.fieldSets.getMap().get('field_set_name');
Schema.FieldSet fs2 = Schema.SObjectType.Account.fieldSets.field_set_name;
Méthodes
Les méthodes suivantes sont les méthodes d'instance de la classe Schema.FieldSet. Aucune méthode ne prend d'argument.
Méthode
Type de renvoi
Description
getDescription
String
Renvoie la description de l'ensemble de champs.
Description est un champ obligatoire d'un ensemble de champs, qui
indique le contexte et le contenu de l'ensemble de champs. Il est souvent
destiné à l'administrateur qui configure un ensemble de champs défini
dans un package géré, plutôt qu'à l'utilisateur final.
getFields
List<FieldSetMember> Renvoie une liste d'objets Schema.FieldSetMember pour les champs
qui composent l'ensemble de champs.
getLabel
String
Renvoie l'étiquette du texte affiché en regard du champ dans l'interface
utilisateur de Salesforce.
getName
String
Renvoie le nom de l'ensemble de champs.
getNamespace
String
Renvoie l'espace de noms de l'ensemble de champs.
L'espace de noms est une chaîne vide si votre organisation n'a pas défini
d'espace de noms et que l'ensemble de champs est défini dans votre
organisation. Sinon, il correspond à l'espace de noms de votre
organisation ou à celui du package géré contenant l'ensemble de champs.
getSObjectType
SObjectType
Renvoie le Schema.sObjectType du sObject qui contient la
définition de l'ensemble de champs.
Méthodes Schema.FieldSetMember
Contient les méthodes d'accès aux métadonnées des champs de membre d'ensemble de champs.
Utilisation
Utilisez la méthode de la classe Schema.FieldSetMember pour obtenir des détails sur les champs contenus dans un ensemble
de champs, notamment l'étiquette du champ, le type, un chemin de champ prêt pour SOQL, etc. L'exemple suivant montre
Référence
salesforce | Méthodes sObject Apex | 457
comment obtenir une collection d'objets de résultat de description de membre pour un ensemble de champs spécifique dans
un sObject :
List<Schema.FieldSetMember> fields =
Schema.SObjectType.Account.fieldSets.getMap().get('field_set_name').getFields();
Si vous connaissez le nom de l'ensemble de champs, vous pouvez accéder directement aux champs en utilisant une référence
explicite à l'ensemble de champs :
List<Schema.FieldSetMember> fields =
Schema.SObjectType.Account.fieldSets.field_set_name.getFields();
Méthodes
Les méthodes suivantes sont les méthodes d'instance de la classe Schema.FieldSetMember. Aucune méthode ne prend
d'argument.
Méthode
Type de renvoi
Description
getDBRequired
Boolean
Renvoie true si le champ est requis par la définition du champ dans
ce sObject, sinon renvoie false.
getFieldPath
String
Renvoie une chaîne de chemin de champ sous un format prêt pour une
requête SOQL dynamique.
Pour consulter un exemple d'utilisation de cette méthode, reportez-vous
à Affichage d'un ensemble de champs dans une page Visualforce.
getLabel
String
Renvoie l'étiquette du texte affiché en regard du champ dans l'interface
utilisateur de Salesforce.
getRequired
Boolean
Renvoie true si le champ est requis par l'ensemble de champs, sinon
renvoie false.
getType
Schema.DisplayType Renvoie le type de données Apex du champ.
Exemple : Affichage d'un ensemble de champs dans une page Visualforce
Cet exemple utilise les méthodes Schema.FieldSet et Schema.FieldSetMember pour obtenir dynamiquement tous les
champs de l'ensemble de champs Dimensions de l'objet personnalisé Merchandise. La liste de champs est ensuite utilisée pour
construire une requête SOQL qui vérifie que ces champs peuvent être affichés. La page Visualforce utilise la classe
MerchandiseDetails en tant que contrôleur.
public class MerchandiseDetails {
public Merchandise__c merch { get; set; }
public MerchandiseDetails() {
this.merch = getMerchandise();
}
Référence
salesforce | Méthodes sObject Apex | 458
public List<Schema.FieldSetMember> getFields() {
return SObjectType.Merchandise__c.FieldSets.Dimensions.getFields();
}
private Merchandise__c getMerchandise() {
String query = 'SELECT ';
for(Schema.FieldSetMember f : this.getFields()) {
query += f.getFieldPath() + ', ';
}
query += 'Id, Name FROM Merchandise__c LIMIT 1';
return Database.query(query);
}
}
La page Visualforce utilisant le contrôleur ci-dessus est simple :
<apex:page controller="MerchandiseDetails">
<apex:form >
<apex:pageBlock title="Product Details">
<apex:pageBlockSection title="Product">
<apex:inputField value="{!merch.Name}"/>
</apex:pageBlockSection>
<apex:pageBlockSection title="Dimensions">
<apex:repeat value="{!fields}" var="f">
<apex:inputField value="{!merch[f.fieldPath]}"
required="{!OR(f.required, f.dbrequired)}"/>
</apex:repeat>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
Référence
salesforce | Méthodes sObject Apex | 459
</apex:page>
Dans la construction ci-dessus, notez l'expression utilisée pour déterminer si un champ du formulaire doit être défini comme
obligatoire. Un champ d'un ensemble peut être requis par la définition d'ensemble de champs ou par la définition de propriétaire
du champ. L'expression gère ces deux cas.
Méthodes Custom Settings
Les méthodes Custom Settings (paramètres personnalisés) sont toutes des méthodes d'instance, c.-à-d. qu'elles sont appelées
par un opérateur dans une instance particulière d'un paramètre personnalisé. Il existe deux types de paramètres personnalisés :
hiérarchie et liste. Les méthodes sont divisées entre celles qui fonctionnent avec des paramètres personnalisés de liste et celles
qui fonctionnent avec des paramètres personnalisés de hiérarchie.
Les méthodes ci-dessous sont les méthodes d'instance pour List Custom Settings.
Tableau 1: Méthodes List Custom Settings
Nom
Arguments
getAll
Type de renvoi
Description
Map<String
Renvoie un mappage des ensembles de données définis
pour le paramètre personnalisé.
Data_set_name,
CustomSetting__c>
Si aucun ensemble de données n'est défini, cette méthode
renvoie un mappage vide.
Remarque: Pour Apex enregistré en utilisant
l'API Salesforce.com version 20.0 ou antérieure,
les noms d'ensemble de données, qui sont les
clés du mappage renvoyé, sont convertis en
minuscules. Pour Apex enregistré en utilisant
l'API Salesforce.com versions 21.0 et
ultérieures, la casse des noms d'ensemble de
données dans les clés de mappage renvoyées
n'est pas modifiée et la casse d'origine est
conservée.
getInstance
String
CustomSetting__c
dataset_name
Renvoie l'enregistrement d'ensemble de données pour
le paramètre personnalisé dataset_name spécifié. Cette
méthode renvoie exactement le même objet que
getValues(dataset_name).
Si aucune donnée n'est définie pour l'ensemble de
données spécifié, cette méthode renvoie null.
getValues
String
dataset_name
CustomSetting__c
Renvoie l'enregistrement d'ensemble de données pour
le paramètre personnalisé dataset_name spécifié. Cette
méthode renvoie exactement le même objet que
getInstance(dataset_name).
Si aucune donnée n'est définie pour l'ensemble de
données spécifié, cette méthode renvoie null.
Référence
salesforce | Méthodes sObject Apex | 460
Les méthodes ci-dessous sont les méthodes d'instance pour Hierarchy Custom Settings.
Tableau 2: Méthodes Hierarchy Custom Settings
Nom
getInstance
Arguments
Type de renvoi
Description
CustomSetting__c
Renvoie un enregistrement d'ensemble de données de
paramètre personnalisé de l'utilisateur actif. Les champs
renvoyés dans l'enregistrement de paramètre personnalisé
sont fusionnés sur la base des champs au niveau le plus
bas de la hiérarchie.
Si aucune donnée de paramètre personnalisé n'est définie
pour l'utilisateur, cette méthode renvoie un nouvel objet
de paramètre personnalisé avec l'ID défini sur un null,
et avec des champs fusionnés plus haut dans la hiérarchie.
Vous pouvez ajouter ce nouvel enregistrement de
paramètre personnalisé pour l'utilisateur en utilisant
insert ou upsert. Si aucune donnée de paramètre
personnalisé n'est définie dans la hiérarchie, le paramètre
personnalisé renvoyé contient des champs vides, à
l'exception du champ SetupOwnerId qui contient l'ID
utilisateur.
Remarque: Pour Apex enregistré en utilisant
l'API Salesforce.com version 21.0 ou antérieure,
cette méthode renvoie l'enregistrement
d'ensemble de données de paramètre
personnalisé, avec des champs fusionnés à partir
de valeurs de champ définies au plus bas niveau
de la hiérarchie, en commençant par
l'utilisateur. En outre, si aucune donnée de
paramètre personnalisé n'est définie dans la
hiérarchie, cette méthode renvoie null.
Exemples :
•
•
Ensemble de données de paramètre personnalisé
défini pour l'utilisateur : si vous avez un ensemble de
données de paramètre personnalisé défini pour
l'utilisateur « Uriel Jones », pour le profil «
Administrateur système » et pour l'organisation dans
son ensemble, et que l'utilisateur exécutant le code
est Uriel Jones, cette méthode renvoie
l'enregistrement de paramètre personnalisé défini
pour Uriel Jones.
Champs fusionnés : si vous avez un ensemble de
données de paramètre personnalisé avec des champs
A et B pour l'utilisateur « Uriel Jones » et pour le
profil « Administrateur système », et que le champ
A est défini pour Uriel Jones, que le champ B est
Référence
Nom
salesforce | Méthodes sObject Apex | 461
Arguments
Type de renvoi
Description
null, mais défini pour le profil Administrateur
•
système, cette méthode renvoie l'enregistrement de
paramètre personnalisé de Uriel Jones, avec le champ
A d'Uriel Jones et le champ B du profil
Administrateur système.
Aucun ensemble de données de paramètre
personnalisé défini pour l'utilisateur : si l'utilisateur
actuel est « Barbara Mahonie », qui partage
également le profil « Administrateur système », mais
qu'aucune donnée n'est définie pour Barbara en tant
qu'utilisatrice, cette méthode renvoie un nouvel
enregistrement de paramètre personnalisé avec l'ID
défini sur null, et avec des champs fusionnés sur la
base des champs définis au niveau le plus bas de la
hiérarchie.
Cette méthode est équivalente à un appel de méthode
de getInstance(User_Id) pour l'utilisateur actuel.
getInstance
ID User_Id
CustomSetting__c
Renvoie l'enregistrement d'ensemble de données pour
le paramètre personnalisé User_Id spécifié.
L'enregistrement de paramètre personnalisé et les champs
au niveau le plus bas sont renvoyés. Utilisez-la afin de
récupérer explicitement des données pour le paramètre
personnalisé au niveau de l'utilisateur.
Si aucune donnée de paramètre personnalisé n'est définie
pour l'utilisateur, cette méthode renvoie un nouvel objet
de paramètre personnalisé avec l'ID défini sur un null,
et avec des champs fusionnés plus haut dans la hiérarchie.
Vous pouvez ajouter ce nouvel enregistrement de
paramètre personnalisé pour l'utilisateur en utilisant
insert ou upsert. Si aucune donnée de paramètre
personnalisé n'est définie dans la hiérarchie, le paramètre
personnalisé renvoyé contient des champs vides, à
l'exception du champ SetupOwnerId qui contient l'ID
utilisateur.
Remarque: Pour Apex enregistré en utilisant
l'API Salesforce.com version 21.0 ou antérieure,
cette méthode renvoie l'enregistrement
d'ensemble de données de paramètre
personnalisé, avec des champs fusionnés à partir
de valeurs de champ définies au plus bas niveau
de la hiérarchie, en commençant par
l'utilisateur. En outre, si aucune donnée de
paramètre personnalisé n'est définie dans la
hiérarchie, cette méthode renvoie null.
Référence
salesforce | Méthodes sObject Apex | 462
Nom
Arguments
Type de renvoi
Description
getInstance
ID Profile_Id
CustomSetting__c
Renvoie l'enregistrement d'ensemble de données pour
le paramètre personnalisé Profile_Id spécifié.
L'enregistrement de paramètre personnalisé et les champs
au niveau le plus bas sont renvoyés. Utilisez-la afin de
récupérer explicitement des données pour le paramètre
personnalisé au niveau du profil.
Si aucune donnée de paramètre personnalisé n'est définie
pour le profil, cette méthode renvoie un nouvel
enregistrement de paramètre personnalisé avec l'ID défini
sur un null, et avec des champs fusionnés à partir des
valeurs par défaut de votre organisation. Vous pouvez
ajouter ce nouveau paramètre personnalisé pour le profil
en utilisant insert ou upsert. Si aucune donnée de
paramètre personnalisé n'est définie dans la hiérarchie,
le paramètre personnalisé renvoyé contient des champs
vides, à l'exception du champ SetupOwnerId qui
contient l'ID de profil.
Remarque: Pour Apex enregistré en utilisant
l'API Salesforce.com version 21.0 ou antérieure,
cette méthode renvoie l'enregistrement
d'ensemble de données de paramètre
personnalisé, avec des champs fusionnés à partir
de valeurs de champ définies au plus bas niveau
de la hiérarchie, en commençant par le profil.
En outre, si aucune donnée de paramètre
personnalisé n'est définie dans la hiérarchie,
cette méthode renvoie null.
CustomSetting__c
getOrgDefaults
Renvoie l'enregistrement d'ensemble de données de
paramètre personnalisé pour l'organisation.
Si aucune donnée de paramètre personnalisé n'est définie
pour l'organisation, cette méthode renvoie un objet de
paramètre personnalisé vide.
Remarque: Pour Apex enregistré en utilisant
l'API Salesforce.com version 21.0 ou antérieure,
cette méthode renvoie null si aucune donnée
de paramètre personnalisé n'est définie pour
l'organisation.
getValues
ID User_Id
CustomSetting__c
Renvoie l'enregistrement d'ensemble de données pour
le paramètre personnalisé User_Id spécifié. Utilisez-la
si vous souhaitez uniquement le sous-ensemble de
données de paramètre personnalisé qui a été défini au
niveau de l'utilisateur. Par exemple, supposons que vous
Référence
salesforce | Méthodes sObject Apex | 463
Nom
Arguments
Type de renvoi
Description
avez un champ de paramètre personnalisé auquel une
valeur « foo » a été attribuée au niveau de l'organisation,
mais qui n'a aucune valeur attribuée au niveau de
l'utilisateur ou du profil. L'utilisation de
getValues(User_Id) renvoie null pour ce champ
de paramètre personnalisé.
getValues
ID Profile_Id
CustomSetting__c
Renvoie l'ensemble de données pour le paramètre
personnalisé Profile_Id spécifié. Utilisez-la si vous
souhaitez uniquement le sous-ensemble de données de
paramètre personnalisé qui a été défini au niveau du
profil. Par exemple, supposons que vous avez un champ
de paramètre personnalisé auquel une valeur « foo » a
été attribuée au niveau de l'organisation, mais qui n'a
aucune valeur attribuée au niveau de l'utilisateur ou du
profil. L'utilisation de getValues(Profile_Id)
renvoie null pour ce champ de paramètre personnalisé.
Pour plus d'informations sur les paramètres personnalisés, reportez-vous à « Présentation des paramètres personnalisés » dans
l'aide en ligne de Salesforce.
Remarque: Toutes les données des paramètres personnalisés sont exposées dans la mémoire cache de l'application,
ce qui optimise l'accès sans les coûts inhérents aux requêtes répétées vers la base de données. Cependant, une demande
de données de paramètres personnalisés à l'aide de SOQL (Standard Object Query Language) n'utilise pas le cache
de l'application et est similaire à une demande d'objet personnalisé. Pour bénéficier de la mise en cache, utilisez d'autres
méthodes d'accès aux données de paramètres personnalisés, telles que les méthodes de paramètres personnalisés Apex.
Exemples de paramètres personnalisés
L'exemple suivant utilise une liste de paramètres personnalisés appelée Games. Games possède un champ appelé GameType.
Cet exemple détermine si la valeur du premier ensemble de données est égal à la chaîne PC.
List<Games__C> mcs = Games__c.getall().values();
boolean textField = null;
if (mcs[0].GameType__c == 'PC') {
textField = true;
}
system.assertEquals(textField, true);
L'exemple suivant utilise un paramètre personnalisé depuis Exemple de paramètres personnalisés de code de pays et de région.
Cet exemple montre que le paramètre personnalisé de liste des méthodes getValues et getInstance renvoie des valeurs
identiques.
Foundation_Countries__c myCS1 = Foundation_Countries__c.getValues('United States');
String myCCVal = myCS1.Country_code__c;
Référence
salesforce | Méthodes sObject Apex | 464
Foundation_Countries__c myCS2 = Foundation_Countries__c.getInstance('United States');
String myCCInst = myCS2.Country_code__c;
system.assertEquals(myCCinst, myCCVal);
Exemples de paramètres personnalisés de hiérarchie
Dans l'exemple suivant, le paramètre personnalisé de hiérarchie GamesSupport possède un champ appelé Corporate_number.
Le code renvoie la valeur pour le profil spécifié par pid.
GamesSupport__c mhc = GamesSupport__c.getInstance(pid);
string mPhone = mhc.Corporate_number__c;
L'exemple est identique si vous choisissez d'utiliser la méthode getValues.
L'exemple suivant montre comment utiliser les méthodes de paramètres personnalisés de hiérarchie. Pour getInstance,
l'exemple montre comment les valeurs de champ qui ne sont pas définies pour un utilisateur ou un profil spécifique sont
renvoyées depuis les champs définis au niveau le plus bas suivant de la hiérarchie. L'exemple montre également comment
utiliser getOrgDefaults.
Enfin, l'exemple montre comment getValues renvoie des champs de l'enregistrement de paramètre personnalisé uniquement
pour l'utilisateur ou le profil spécifique, sans fusionner de valeurs d'autres niveaux de la hiérarchie. À la place, getValues
renvoie null pour tous les champs non définis. Cet exemple utilise un paramètre personnalisé de hiérarchie appelé Hierarchy.
Hierarchy possède deux champs : OverrideMe et DontOverrideMe. De plus, un utilisateur appelé Robert a un profil
d'administrateur système. Les paramètres d'organisation, de profil et d'utilisateur de cet exemple sont les suivants :
Paramètres d'organisation
OverrideMe: Hello
DontOverrideMe: World
Paramètres de profil
OverrideMe: Goodbye
DontOverrideMe n'est pas défini.
Paramètres d'utilisateur
OverrideMe: Fluffy
DontOverrideMe n'est pas défini.
L'exemple suivant montre le résultat de la méthode getInstance si Robert l'appelle dans son organisation :
Hierarchy__c CS = Hierarchy__c.getInstance();
System.Assert(CS.OverrideMe__c == 'Fluffy');
System.assert(CS.DontOverrideMe__c == 'World');
Si Robert transmet son ID utilisateur spécifié par RobertId à getInstance, les résultats sont identiques. En effet, le niveau
le plus bas des données dans le paramètre personnalisé est spécifié au niveau de l'utilisateur.
Hierarchy__c CS = Hierarchy__c.getInstance(RobertId);
System.Assert(CS.OverrideMe__c == 'Fluffy');
Référence
salesforce | Méthodes sObject Apex | 465
System.assert(CS.DontOverrideMe__c == 'World');
Si Robert transmet l'ID de profil Administrateur système spécifié par SysAdminID à getInstance, le résultat est différent.
Les données spécifiées pour le profil sont renvoyées :
Hierarchy__c CS = Hierarchy__c.getInstance(SysAdminID);
System.Assert(CS.OverrideMe__c == 'Goodbye');
System.assert(CS.DontOverrideMe__c == 'World');
Lorsque Robert essaie de renvoyer l'ensemble de données de l'organisation en utilisant getOrgDefaults, le résultat est :
Hierarchy__c CS = Hierarchy__c.getOrgDefaults();
System.Assert(CS.OverrideMe__c == 'Hello');
System.assert(CS.DontOverrideMe__c == 'World');
En utilisant la méthode getValues, Robert peut obtenir les valeurs de paramètre personnalisé de hiérarchie spécifiques à ces
paramètres d'utilisateur et de profil. Par exemple, si Robert transmet son ID d'utilisateur RobertId à getValues, le résultat
est :
Hierarchy__c CS = Hierarchy__c.getValues(RobertId);
System.Assert(CS.OverrideMe__c == 'Fluffy');
// Note how this value is null, because you are returning
// data specific for the user
System.assert(CS.DontOverrideMe__c == null);
Si Robert transmet son ID de profil Administrateur système SysAdminID à getValues, le résultat est :
Hierarchy__c CS = Hierarchy__c.getValues(SysAdminID);
System.Assert(CS.OverrideMe__c == 'Goodbye');
// Note how this value is null, because you are returning
// data specific for the profile
System.assert(CS.DontOverrideMe__c == null);
Exemple de paramètres personnalisés de code de pays et de région
Cet exemple illustre l'utilisation de deux objets de paramètre personnalisé pour le stockage d'informations associées, et d'une
page Visualforce pour l'affichage des données dans un ensemble de listes de sélection associées.
Dans l'exemple suivant, les codes de pays et de région sont stockés dans deux paramètres personnalisés différents :
Foundation_Countries et Foundation_States.
Le paramètre personnalisé Foundation_Countries est un paramètre personnalisé de type de liste et possède un champ unique,
Country_Code.
Référence
salesforce | Méthodes sObject Apex | 466
Le paramètre personnalisé Foundation_States est également un paramètre personnalisé de type de liste et possède les champs
suivants :
•
•
•
Country Code
State Code
State Name
La page Visualforce affiche deux listes de sélection : une pour le pays et une pour la région.
Référence
salesforce | Méthodes sObject Apex | 467
<apex:page controller="CountryStatePicker">
<apex:form >
<apex:actionFunction name="rerenderStates" rerender="statesSelectList" >
<apex:param name="firstParam" assignTo="{!country}" value="" />
</apex:actionFunction>
<table><tbody>
<tr>
<th>Country</th>
<td>
<apex:selectList id="country" styleclass="std" size="1"
value="{!country}" onChange="rerenderStates(this.value)">
<apex:selectOptions value="{!countriesSelectList}"/>
</apex:selectList>
</td>
</tr>
<tr id="state_input">
<th>State/Province</th>
<td>
<apex:selectList id="statesSelectList" styleclass="std" size="1"
value="{!state}">
<apex:selectOptions value="{!statesSelectList}"/>
Référence
salesforce | Méthodes sObject Apex | 468
</apex:selectList>
</td>
</tr>
</tbody></table>
</apex:form>
</apex:page>
Le contrôleur Apex CountryStatePicker récupère les valeurs saisies dans les paramètres personnalisés, puis les renvoie
vers la page Visualforce.
public with sharing class CountryStatePicker {
// Variables to store country and state selected by user
public String state { get; set; }
public String country {get; set;}
// Generates country dropdown from country settings
public List<SelectOption> getCountriesSelectList() {
List<SelectOption> options = new List<SelectOption>();
options.add(new SelectOption('', '-- Select One --'));
// Find all the countries in the custom setting
Map<String, Foundation_Countries__c> countries = Foundation_Countries__c.getAll();
// Sort them by name
List<String> countryNames = new List<String>();
countryNames.addAll(countries.keySet());
countryNames.sort();
// Create the Select Options.
for (String countryName : countryNames) {
Foundation_Countries__c country = countries.get(countryName);
options.add(new SelectOption(country.country_code__c, country.Name));
}
Référence
salesforce | Méthodes sObject Apex | 469
return options;
}
// To generate the states picklist based on the country selected by user.
public List<SelectOption> getStatesSelectList() {
List<SelectOption> options = new List<SelectOption>();
// Find all the states we have in custom settings.
Map<String, Foundation_States__c> allstates = Foundation_States__c.getAll();
// Filter states that belong to the selected country
Map<String, Foundation_States__c> states = new Map<String, Foundation_States__c>();
for(Foundation_States__c state : allstates.values()) {
if (state.country_code__c == this.country) {
states.put(state.name, state);
}
}
// Sort the states based on their names
List<String> stateNames = new List<String>();
stateNames.addAll(states.keySet());
stateNames.sort();
// Generate the Select Options based on the final sorted list
for (String stateName : stateNames) {
Foundation_States__c state = states.get(stateName);
options.add(new SelectOption(state.state_code__c, state.state_name__c));
}
// If no states are found, just say not required in the dropdown.
if (options.size() > 0) {
options.add(0, new SelectOption('', '-- Select One --'));
} else {
options.add(new SelectOption('', 'Not Required'));
Référence
salesforce | Méthodes Système Apex | 470
}
return options;
}
}
Méthodes Système Apex
Les classes suivantes sont les classes système Apex.
•
•
•
ApexPages
Approval
Database
◊
◊
◊
◊
•
Database Batch
Database DMLOptions
Database EmptyRecycleBinResult
Database Error
JSON Support
◊ Méthodes JSON
◊ Méthodes JSONGenerator
◊ Méthodes JSONParser
•
•
•
•
Limits
Math
MultiStaticResourceCalloutMock
Apex REST
◊ Méthodes RestContext
◊ Méthodes RestRequest
◊ Méthodes RestResponse
•
•
•
•
•
•
•
•
•
Search
StaticResourceCalloutMock
System
Test
TimeZone
Type
URL
UserInfo
Version
Référence
salesforce | Méthodes Système Apex | 471
Méthodes ApexPages
Utilisez ApexPages pour ajouter et consulter les messages associés à la page actuelle, et pour référencer cette page. Les méthodes
ApexPages sont également utilisées en tant qu'espace de noms pour des classes PageReference et Message.
Le tableau suivant répertorie les méthodes ApexPages :
Nom
Arguments
Type de renvoi
Description
addMessage
sObject
Void
Ajoute un message au contexte de page actuel.
Void
Ajoute une liste de messages au contexte de page actuel
sur la base d'une exception levée.
ApexPages.Message
addMessages
Exception ex
getMessages
ApexPages.Message[] Renvoie une liste des messages associés au contexte
actuel.
hasMessages
Boolean
Renvoie true si des messages sont associés au contexte
actuel, sinon renvoie false.
Boolean
Renvoie true si des messages de la sévérité spécifiée
existent, sinon renvoie false.
hasMessages
ApexPages.Severity
Méthodes Approval
Le tableau suivant répertorie les méthodes statiques Approval. Approval est également utilisée comme espace de noms pour
les classes ProcessRequest et ProcessResult.
Nom
Arguments
Type de renvoi
Description
process
Approval.ProcessRequest Approval.ProcessResult Soumet une nouvelle requête d'approbation et approuve
ProcessRequest
ou refuse les requêtes d'approbation existantes.
Par exemple :
// Insert an account
Account a = new Account(Name='Test',
annualRevenue=100.0);
insert a;
// Create an approval request for the
account
Approval.ProcessSubmitRequest req1 =
new
Référence
Nom
salesforce | Méthodes Système Apex | 472
Arguments
Type de renvoi
Description
Approval.ProcessSubmitRequest();
req1.setObjectId(a.id);
// Submit the approval request for the
account
Approval.ProcessResult result =
Approval.process(req1);
process
Approval.ProcessRequest Approval.ProcessResult Soumet une nouvelle requête d'approbation et approuve
ProcessRequests
ou refuse les requêtes d'approbation existantes.
Boolean
Le paramètre facultatif opt_allOrNone spécifie si
l'opération autorise un succès partiel. Si vous spécifiez
false pour ce paramètre et qu'une approbation échoue,
le reste des processus d'approbation peut réussir.
opt_allOrNone
process
Approval.ProcessRequest Approval.ProcessResult Soumet une liste de nouvelles requêtes d'approbation et
[]
[]
approuve ou refuse les requêtes d'approbation existantes.
ProcessRequests
process
Approval.ProcessRequest Approval.ProcessResult Soumet une liste de nouvelles requêtes d'approbation et
[]
[]
approuve ou refuse les requêtes d'approbation existantes.
ProcessRequests
Le paramètre facultatif opt_allOrNone spécifie si
l'opération autorise un succès partiel. Si vous spécifiez
false pour ce paramètre et qu'une approbation échoue,
le reste des processus d'approbation peut réussir.
Boolean
opt_allOrNone
Pour plus d'informations sur le processus approbation Apex, reportez-vous à Classes de gestion des approbations Apex à la
page 674.
Méthodes Database
Les méthodes ci-dessous sont les méthodes statiques système pour Database.
Nom
Arguments
Type de renvoi
convertLead
LeadConvert
Database.
Convertit une piste en compte et en contact, et
LeadConvertResult (facultatif) en opportunité.
leadToConvert,
Boolean opt_allOrNone
Description
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
Référence
Nom
salesforce | Méthodes Système Apex | 473
Arguments
Type de renvoi
Description
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode convertLead exécutée est prise
en compte dans les limitations du gouverneur pour
les instructions DML.
convertLead
LeadConvert[]
leadsToConvert
Boolean opt_allOrNone
Database.
LeadConvert
Result[]
Convertit une liste d'objets LeadConvert en
comptes et en contacts, et (facultatif) en
opportunités.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode convertLead exécutée est prise
en compte dans les limitations du gouverneur pour
les instructions DML.
countQuery
String query
Integer
Renvoie le nombre d'enregistrements qu'une requête
SOQL dynamique renverrait à l'exécution. Par
exemple :
String QueryString =
'SELECT count() FROM Account';
Integer i =
Database.countQuery(QueryString);
Pour plus d'informations, reportez-vous à SOQL
dynamique à la page 217.
Chaque méthode convertQuery exécutée est prise
en compte dans les limitations du gouverneur pour
les requêtes SOQL.
delete
SObject recordToDelete
Boolean opt_allOrNone
DeleteResult
Supprime un enregistrement de sObject existant,
tel qu'un compte ou un contact individuel, des
données de votre organisation. delete est
semblable à l'instruction delete() dans l'API
SOAP.
Référence
Nom
salesforce | Méthodes Système Apex | 474
Arguments
Type de renvoi
Description
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode delete exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
delete
SObject[] recordsToDelete DeleteResult[]
Boolean opt_allOrNone
Supprime une liste d'enregistrements de sObject
existants, tels que des comptes ou des contacts
individuels, des données de votre
organisation.delete est semblable à l'instruction
delete() dans l'API SOAP.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode delete exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
delete
RecordID ID
Boolean opt_allOrNone
DeleteResult
Supprime des enregistrements de sObject existants,
tels que des comptes ou des contacts individuels,
des données de votre organisation.delete est
semblable à l'instruction delete() dans l'API
SOAP.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode delete exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
Référence
salesforce | Méthodes Système Apex | 475
Nom
Arguments
Type de renvoi
Description
delete
RecordIDs []IDs
DeleteResult[]
Supprime une liste d'enregistrements de sObject
existants, tels que des comptes ou des contacts
individuels, des données de votre
organisation.delete est semblable à l'instruction
delete() dans l'API SOAP.
Boolean opt_allOrNone
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode delete exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
emptyRecycleBin RecordIds []Ids
Database.
EmptyRecycleBin
Result[]
Supprime définitivement les enregistrements
spécifiés de la corbeille. Notez les points suivants :
• Les enregistrements supprimés avec cette
méthode ne peuvent pas être restaurés.
• Seuls 10 000 enregistrements peuvent être
spécifiés pour la suppression.
• L'utilisateur connecté peut supprimer tout
enregistrement qu'il peut demander dans sa
Corbeille ou dans celle de ses subordonnés. Si
l'utilisateur connecté dispose de l'autorisation
« Modifier toutes les données », il peut
demander et supprimer des enregistrements dans
n'importe quelle Corbeille de l'organisation.
• Les ID d'enregistrements de suppression en
cascade ne doivent pas être inclus dans la liste
des ID, sinon une erreur est générée. Par
exemple, si un enregistrement de compte est
supprimé, tous les contacts, opportunités,
contrats, etc., associés sont également
supprimés. Incluez uniquement l'ID du compte
de niveau supérieur. Tous les enregistrements
associés sont automatiquement supprimés.
• Les éléments supprimés sont ajoutés au nombre
d'éléments traités par une instruction DML, et
l'appel de méthode est ajouté au nombre total
d'instructions DML générées. Chaque méthode
emptyRecycleBin exécutée est prise en
compte dans les limitations du gouverneur pour
les instructions DML.
Référence
Nom
salesforce | Méthodes Système Apex | 476
Arguments
emptyRecycleBin sObject sObject
Type de renvoi
Description
Database.
EmptyRecycleBin
Result
Supprime définitivement le sObject spécifié de la
corbeille. Notez les points suivants :
• Un sObject supprimé avec cette méthode ne
peut pas être restauré.
• Seuls 10 000 sObjects peuvent être spécifiés
pour être supprimés.
• L'utilisateur connecté peut supprimer tout
sObject qu'il peut demander dans sa Corbeille
ou dans celle de ses subordonnés. Si l'utilisateur
connecté dispose de l'autorisation « Modifier
toutes les données », il peut demander et
supprimer des sObjects dans n'importe quelle
Corbeille de l'organisation.
• N'incluez pas un sObject qui a été supprimé
suite à une suppression en cascade, sinon une
erreur est générée. Par exemple, si un compte
est supprimé, tous les contacts, opportunités,
contrats, etc., associés sont également
supprimés. Incluez uniquement les sObjects du
compte de niveau supérieur. Tous les sObjects
associés sont automatiquement supprimés.
• Les éléments supprimés sont ajoutés au nombre
d'éléments traités par une instruction DML, et
l'appel de méthode est ajouté au nombre total
d'instructions DML générées. Chaque méthode
emptyRecycleBin exécutée est prise en
compte dans les limitations du gouverneur pour
les instructions DML.
emptyRecycleBin sObjects []listOfSObjects Database.
EmptyRecycleBin
Result[]
Supprime définitivement les sObjects spécifiés de
la corbeille. Notez les points suivants :
• Un sObject supprimé avec cette méthode ne
peut pas être restauré.
• Seuls 10 000 sObjects peuvent être spécifiés
pour être supprimés.
• L'utilisateur connecté peut supprimer tout
sObject qu'il peut demander dans sa Corbeille
ou dans celle de ses subordonnés. Si l'utilisateur
connecté dispose de l'autorisation « Modifier
toutes les données », il peut demander et
supprimer des sObjects dans n'importe quelle
Corbeille de l'organisation.
• N'incluez pas un sObject qui a été supprimé
suite à une suppression en cascade, sinon une
erreur est générée. Par exemple, si un compte
est supprimé, tous les contacts, opportunités,
Référence
Nom
salesforce | Méthodes Système Apex | 477
Arguments
Type de renvoi
Description
•
executeBatch
sObject className
ID
contrats, etc., associés sont également
supprimés. Incluez uniquement les sObjects du
compte de niveau supérieur. Tous les sObjects
associés sont automatiquement supprimés.
Les éléments supprimés sont ajoutés au nombre
d'éléments traités par une instruction DML, et
l'appel de méthode est ajouté au nombre total
d'instructions DML générées. Chaque méthode
emptyRecycleBin exécutée est prise en
compte dans les limitations du gouverneur pour
les instructions DML.
Exécute la classe spécifiée en tant que tâche Apex
par lot. Pour plus d'informations, reportez-vous à
Utilisation d'un code Apex par lot à la page 224.
Remarque: La classe appelée par la
méthode executeBatch met en oeuvre
la méthode execute.
executeBatch
sObject className, Integer ID
scope
Exécute la classe spécifiée en tant que tâche Apex
par lot. La valeur de scope doit être supérieure à
0. Pour plus d'informations, reportez-vous à
Utilisation d'un code Apex par lot à la page 224.
Remarque: La classe appelée par la
méthode executeBatch met en oeuvre
la méthode execute.
getQueryLocator sObject [] listOfQueries
QueryLocator
Crée un objet QueryLocator utilisé dans un code
Apex par lot ou une page Visualforce. Pour plus
d'informations, reportez-vous à Objets et méthodes
Apex de base de données par lot, Compréhension
du partage géré Apex et Classe
StandardSetController.
Vous ne pouvez utiliser getQueryLocator avec
aucune requête contenant une fonction agrégée.
Chaque méthode getQueryLocator exécutée est
prise en compte dans les limitations du gouverneur
de 10 000 enregistrements au total récupérés et en
nombre total de requêtes SOQL générées.
getQueryLocator String query
QueryLocator
Crée un objet QueryLocator utilisé dans un code
Apex par lot ou une page Visualforce. Pour plus
d'informations, reportez-vous à Objets et méthodes
Apex de base de données par lot, Compréhension
Référence
Nom
salesforce | Méthodes Système Apex | 478
Arguments
Type de renvoi
Description
du partage géré Apex et Classe
StandardSetController.
Vous ne pouvez utiliser getQueryLocator avec
aucune requête contenant une fonction agrégée.
Chaque méthode getQueryLocator exécutée est
prise en compte dans les limitations du gouverneur
de 10 000 enregistrements au total récupérés et en
nombre total de requêtes SOQL générées.
insert
sObject recordToInsert
SaveResult
Boolean opt_allOrNone |
database.DMLOptions
opt_DMLOptions
Ajoute un sObject, tel qu'un compte ou un contact
individuel, aux données de votre organisation.
insert est semblable à l'instruction INSERT dans
SQL.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Le paramètre facultatif opt_DMLOptions
spécifique des données supplémentaires pour la
transaction, telles que des informations sur une règle
d'attribution ou un comportement d'annulation
lorsque des erreurs se produisent durant l'insertion
d'enregistrements.
Les classes et les déclencheurs Apex sauvegardés
(compilés) en utilisant l'API versions 15.0 et
supérieures, génèrent une erreur d'exécution si vous
attribuez une valeur String trop longue pour le
champ.
Chaque méthode insert exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
insert
sObject [] recordsToInsert SaveResult[]
Boolean opt_allOrNone |
database.DMLOptions
opt_DMLOptions
Ajoute un ou plusieurs sObjects, tels que des
comptes ou des contacts individuels, aux données
de votre organisation.insert est semblable à
l'instruction INSERT dans SQL.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
Référence
Nom
salesforce | Méthodes Système Apex | 479
Arguments
Type de renvoi
Description
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Le paramètre facultatif opt_DMLOptions
spécifique des données supplémentaires pour la
transaction, telles que des informations sur une règle
d'attribution ou un comportement d'annulation
lorsque des erreurs se produisent durant l'insertion
d'enregistrements.
Les classes et les déclencheurs Apex sauvegardés
(compilés) en utilisant l'API versions 15.0 et
supérieures, génèrent une erreur d'exécution si vous
attribuez une valeur String trop longue pour le
champ.
Chaque méthode insert exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
query
String query
sObject[]
Crée une requête SOQL dynamique à l'exécution.
Cette méthode peut être utilisée partout où une
requête SOQL statique est utilisable, notamment
dans des instructions d'attribution régulières et des
boucles for.
Pour plus d'informations, reportez-vous à SOQL
dynamique à la page 217.
Chaque méthode query exécutée est prise en
compte dans les limitations du gouverneur pour les
requêtes SOQL.
rollback
System.Savepoint sp
Void
Restaure la base de données à l'état spécifié par la
variable de point de sauvegarde. Tous les e-mails
soumis depuis le dernier point de sauvegarde sont
également restaurés et pas envoyés.
Notez les points suivants :
•
Les variables statiques ne sont pas restaurées
durant une restauration. Si vous essayez de
réexécuter le déclencheur, les variables statiques
conservent les valeurs de la première exécution.
•
Chaque annulation est prise en compte dans les
limitations du gouverneur pour les instructions
DML. Vous obtenez une erreur d'exécution si
vous essayez de restaurer la base de données un
nombre de fois excessif.
Référence
Nom
salesforce | Méthodes Système Apex | 480
Arguments
Type de renvoi
Description
•
L'ID dans un sObject inséré après la définition
d'un point enregistrement n'est pas effacé après
une annulation. Créez un nouveau sObject à
insérer après une annulation. Une tentative
d'insertion du sObject en utilisant la même
variable créée avant l'annulation échoue, car la
variable du sObject inclut un ID. La mise à jour
ou la mise à jour/insertion du sObject en
utilisant la même variable échoue également,
car le sObject ne figure pas dans la base de
données et, par conséquent, ne peut pas être mis
à jour.
Pour consulter un exemple, reportez-vous à
Contrôle des transactions.
setSavepoint
System.Savepoint
Renvoie une variable de point de sauvegarde qui
peut être stockée en tant que variable locale, puis
utilisée avec la méthode rollback pour restaurer
la base de données à ce point.
Notez les points suivants :
•
•
•
Si vous définissez plusieurs points
d'enregistrement, puis restaurez un point
d'enregistrement qui ne correspond pas au
dernier point d'enregistrement généré, les
variables des points d'enregistrement ultérieurs
ne sont plus valides. Par exemple, si vous
générez un premier point d'enregistrement SP1,
puis un deuxième point d'enregistrement SP2,
et que vous restaurez vers le point
d'enregistrement SP1, la variable SP2 n'est plus
valide. Vous recevez une erreur d'exécution
lorsque vous essayez de l'utiliser.
Les références à des points d'enregistrements
ne peuvent pas croiser des invocations de
déclencheur, car chaque invocation de
déclencheur correspond à un nouveau contexte
d'exécution. Si vous déclarez un point
d'enregistrement en tant que variable statique,
puis essayez de l'utiliser à travers des contextes
de déclencheur, vous obtenez une erreur
d'exécution.
Chaque point d'enregistrement que vous
définissez est prise en compte dans les
limitations du gouverneur pour les instructions
DML.
Référence
Nom
salesforce | Méthodes Système Apex | 481
Arguments
Type de renvoi
Description
Pour consulter un exemple, reportez-vous à
Contrôle des transactions.
undelete
sObject recordToUndelete UndeleteResult
Boolean opt_allOrNone
Restaure un enregistrement de sObject existant, tel
qu'un compte ou un contact individuel, depuis la
corbeille de votre organisation. undelete est
semblable à l'instruction UNDELETE dans SQL.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode undelete exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
undelete
sObject []
UndeleteResult[]
recordsToUndelete
Boolean opt_allOrNone
Restaure un ou plusieurs enregistrements de
sObjects existants, tels que des comptes ou des
contacts individuels, depuis la Corbeille de votre
organisation.undelete est semblable à l'instruction
UNDELETE dans SQL.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode undelete exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
undelete
RecordID ID
Boolean opt_allOrNone
UndeleteResult
Restaure un enregistrement de sObject existant, tel
qu'un compte ou un contact individuel, depuis la
corbeille de votre organisation. undelete est
semblable à l'instruction UNDELETE dans SQL.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
Référence
Nom
salesforce | Méthodes Système Apex | 482
Arguments
Type de renvoi
Description
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode undelete exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
undelete
RecordIDs[] ID
Boolean opt_allOrNone
UndeleteResult []
Restaure un ou plusieurs enregistrements de
sObjects existants, tels que des comptes ou des
contacts individuels, depuis la Corbeille de votre
organisation.undelete est semblable à l'instruction
UNDELETE dans SQL.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Chaque méthode undelete exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
update
sObject recordToUpdate
Boolean opt_allOrNone |
database.DMLOptions
opt_DMLOptions
Database.SaveResult Modifie un enregistrement de sObject existant, tel
qu'un compte ou un contact individuel, dans les
données de votre organisation. update est
semblable à l'instruction UPDATE dans SQL.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Le paramètre facultatif opt_DMLOptions
spécifique des données supplémentaires pour la
transaction, telles que des informations sur une règle
d'attribution ou un comportement d'annulation
lorsque des erreurs se produisent durant l'insertion
d'enregistrements.
Les classes et les déclencheurs Apex sauvegardés
(compilés) en utilisant l'API versions 15.0 et
supérieures, génèrent une erreur d'exécution si vous
Référence
Nom
salesforce | Méthodes Système Apex | 483
Arguments
Type de renvoi
Description
attribuez une valeur String trop longue pour le
champ.
Chaque méthode update exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
update
sObject [] recordsToUpdate Database.SaveResult Modifie un ou plusieurs enregistrements de sObject
[]
existants, tels que des relevés de compte de comptes
Boolean opt_allOrNone
ou contacts individuels, dans les données de votre
|
organisation. update est semblable à l'instruction
UPDATE dans SQL.
database.DMLOptions
opt_DMLOptions
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Le paramètre facultatif opt_DMLOptions
spécifique des données supplémentaires pour la
transaction, telles que des informations sur une règle
d'attribution ou un comportement d'annulation
lorsque des erreurs se produisent durant l'insertion
d'enregistrements.
Les classes et les déclencheurs Apex sauvegardés
(compilés) en utilisant l'API versions 15.0 et
supérieures, génèrent une erreur d'exécution si vous
attribuez une valeur String trop longue pour le
champ.
Chaque méthode update exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
upsert
sObject recordToUpsert
Schema.SObjectField
External_ID_Field
Boolean opt_allOrNone
Database.UpsertResult Crée un enregistrement de sObject ou met à jour
un enregistrement de sObject existant dans une
instruction unique à l'aide d'un champ personnalisé
facultatif afin de déterminer la présence d'objets
existants.
Le External_ID_Field est de type
Schema.SObjectField, c.-à-d. un jeton de champ.
Recherchez le jeton du champ en utilisant la
méthode spéciale fields. Par exemple,
Schema.SObjectField f =
Account.Fields.MyExternalId.
Référence
Nom
salesforce | Méthodes Système Apex | 484
Arguments
Type de renvoi
Description
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Les classes et les déclencheurs Apex sauvegardés
(compilés) en utilisant l'API versions 15.0 et
supérieures, génèrent une erreur d'exécution si vous
attribuez une valeur String trop longue pour le
champ.
Chaque méthode upsert exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
upsert
sObject [] recordsToUpsert Database.UpsertResult Utilisation d'un champ personnalisé facultatif pour
[]
déterminer la présence d'objets existants.
Schema.SObjectField
External_ID_Field
Le External_ID_Field est de type
Schema.SObjectField, c.-à-d. un jeton de champ.
Boolean opt_allOrNone
Recherchez le jeton du champ en utilisant la
méthode spéciale fields. Par exemple,
Schema.SObjectField f =
Account.Fields.MyExternalId.
Le paramètre facultatif opt_allOrNone indique
si l'opération autorise le succès partiel. Si vous
spécifiez false pour ce paramètre et qu'un
enregistrement échoue, le reste de l'opération DML
peut réussir. Cette méthode renvoie un objet de
résultat qui permet de déterminer quels
enregistrements ont réussi, quels enregistrements
ont échoué, et pour quelles raisons.
Les classes et les déclencheurs Apex sauvegardés
(compilés) en utilisant l'API versions 15.0 et
supérieures, génèrent une erreur d'exécution si vous
attribuez une valeur String trop longue pour le
champ.
Référence
salesforce | Méthodes Système Apex | 485
Nom
Arguments
Type de renvoi
Description
Chaque méthode upsert exécutée est prise en
compte dans les limitations du gouverneur pour les
instructions DML.
Voir aussi :
Opérations DML (langage de manipulation de données) Apex
Compréhension des limitations et des gouverneurs d'exécution
Objets et méthodes Database Batch Apex
Méthode Database.QueryLocator
Le tableau suivant indique la méthode de l'objet Database.QueryLocator :
Nom
Arguments
getQuery
Type de renvoi
Description
String
Renvoie la requête utilisée pour instancier l'objet
Database.QueryLocator. Elle est utile lors d'un test de
la méthode start. Par exemple :
System.assertEquals(QLReturnedFromStart.
getQuery(),
Database.getQueryLocator([SELECT Id
FROM Account]).getQuery() );
Vous ne pouvez pas utiliser les mots clésFOR UPDATE
avec une requête getQueryLocator pour verrouiller un
ensemble d'enregistrements. La méthode start
verrouille automatiquement l'ensemble d'enregistrements
dans le lot.
Propriétés Database DMLOptions
Utilisez la classe Database.DMLOptions pour fournir des informations supplémentaires durant une transaction, par exemple
en spécifiant des informations sur le comportement de troncature des champs ou sur les règles d'attribution. DMLOptions
est disponible uniquement pour un code Apex enregistré en utilisant l'API versions 15.0 et supérieures.
La classe Database.DMLOptions a les propriétés suivantes :
•
•
•
•
Propriété allowFieldTruncation
Propriété assignmentRuleHeader
Propriété emailHeader
Propriété localeOptions
Référence
•
salesforce | Méthodes Système Apex | 486
Propriété optAllOrNone
Propriété allowFieldTruncation
La propriété allowFieldTruncation spécifie le comportement de troncature des chaînes. Dans un code Apex enregistré
en utilisant l'API de versions antérieures à 15.0, si vous spécifiez une valeur de chaîne trop grande, elle est tronquée. Avec
l'API versions 15.0 et ultérieures, si une valeur spécifiée est trop grande, l'opération échoue et un message d'erreur est renvoyé.
La propriété allowFieldTruncation permet de spécifier que le comportement précédent, la troncature, doit être utilisée
au lieu du nouveau comportement dans un code Apex enregistré en utilisant l'API versions 15.0 et ultérieures.
La propriété allowFieldTruncation prend une valeur booléenne. Si true, la propriété tronque les valeurs de chaîne trop
longues, ce qui correspond au comportement de l'API versions 14.0 et antérieures. Par exemple :
Database.DMLOptions dml = new Database.DMLOptions();
dml.allowFieldTruncation = true;
Propriété assignmentRuleHeader
La propriété assignmentRuleHeader spécifie la règle d'attribution à utiliser lors de la création d'une requête ou d'une piste.
Remarque: L'objet database.DMLOptions prend en charge les règles d'attribution pour les requêtes et les pistes,
mais pas pour les comptes ou la gestion des territoires.
Les options suivantes peuvent être définies avec assignmentRuleHeader :
Nom
Type
Description
assignmentRuleID
ID
Spécifie l'ID d'une règle d'attribution spécifique à exécuter pour
la requête ou la piste. La règle d'attribution peut être active ou
inactive. L'ID peut être récupéré en demandant le sObject
AssignmentRule. Si l'ID est spécifié, ne définissez pas
useDefaultRule.
Si la valeur ne respecte pas le format d'ID correct (ID Salesforce
à 15 ou 18 caractères), l'appel échoue et une exception est
renvoyée.
useDefaultRule
Boolean
Si spécifié comme true pour une requête ou une piste, le
système utilise la règle d'attribution (active) par défaut pour la
requête ou la piste. Si cette propriété est spécifiée, ne définissez
pas assignmentRuleId.
L'exemple suivant utilise l'option useDefaultRule :
Database.DMLOptions dmo = new Database.DMLOptions();
dmo.assignmentRuleHeader.useDefaultRule= true;
Lead l = new Lead(company='ABC', lastname='Smith');
l.setOptions(dmo);
Référence
salesforce | Méthodes Système Apex | 487
insert l;
L'exemple suivant utilise l'option assignmentRuleID :
Database.DMLOptions dmo = new Database.DMLOptions();
dmo.assignmentRuleHeader.assignmentRuleId= '01QD0000000EqAn';
Lead l = new Lead(company='ABC', lastname='Smith');
l.setOptions(dmo);
insert l;
Propriété emailHeader
L'interface utilisateur de Salesforce permet de spécifier l'envoi ou non d'un e-mail lorsque les événements ci-dessous se
produisent :
•
•
•
•
•
•
Création d'un requête ou tâche
Création d'un commentaire de requête
Conversion d'un e-mail de requête en contact
Nouvelle notification d'utilisateur par e-mail
Notification par e-mail de file d'attente de piste
Réinitialisation du mot de passe
Dans un code Apex enregistré en utilisant l'API version 15.0 ou ultérieure, la propriété emailHeader Database.DMLOptions
permet de spécifier des informations supplémentaires dans l'e-mail envoyé si l'exécution du code entraîne l'un des événements.
Les options suivantes peuvent être définies avec la propriété emailHeader :
Nom
Type
Description
triggerAutoResponseEmail
Boolean
Indique de déclencher des règles de réponse automatique (true)
ou non (false) pour des pistes et des requêtes. Dans l'interface
utilisateur Salesforce, cet e-mail peut être déclenché
automatiquement par plusieurs événements, par exemple lors
de la création d'une requête ou la réinitialisation d'un mot de
passe utilisateur. Si cette valeur est définie sur true, lors de la
création d'une requête, si une adresse e-mail du contact est
spécifiée dans ContactID, l'e-mail est envoyé à cette adresse.
Sinon, l'e-mail est envoyé à l'adresse spécifiée dans
SuppliedEmail.
triggerOtherEmail
Boolean
Indique de déclencher un e-mail hors de l'organisation (true)
ou non (false). Dans l'interface utilisateur de Salesforce, cet
e-mail peut être déclenché automatiquement lors de la création,
la modification ou la suppression d'un contact d'une requête.
triggerUserEmail
Boolean
Indique de déclencher un e-mail envoyé aux utilisateurs dans
l'organisation (true) ou non (false). Dans l'interface
utilisateur de Salesforce, cet e-mail peut être déclenché
automatiquement lors de plusieurs événements, notamment la
Référence
salesforce | Méthodes Système Apex | 488
Nom
Type
Description
réinitialisation d'un mot de passe, la création d'un utilisateur,
l'ajout de commentaires à une requête, la création ou la
modification d'une tâche.
Dans l'exemple suivant, l'option triggerAutoResponseEmail est spécifiée :
Account a = new Account(name='Acme Plumbing');
insert a;
Contact c = new Contact(email='[email protected]', firstname='Joe',lastname='Plumber',
accountid=a.id);
insert c;
Database.DMLOptions dlo = new Database.DMLOptions();
dlo.EmailHeader.triggerAutoResponseEmail = true;
Case ca = new Case(subject='Plumbing Problems', contactid=c.id);
database.insert(ca, dlo);
E-mail envoyé via Apex, car un événement de groupe inclut des comportements supplémentaires. Un événement de groupe est
un événement pour lequel IsGroupEvent est true. L'objet EventAttendee suit les utilisateurs, les pistes ou les contacts qui
sont invités dans un événement de groupe. Notez les comportements suivants pour un e-mail d'événement de groupe envoyé
via Apex :
•
•
•
L'envoi d'une invitation d'événement de groupe à un utilisateur respecte l'option triggerUserEmail
L'envoi d'une invitation d'événement de groupe à une piste ou un contact respecte l'option triggerOtherEmail
Un e-mail envoyé lors de la mise à jour ou de la suppression d'un événement de groupe respecte également les options
triggerUserEmail et triggerOtherEmail, selon le cas
Propriété localeOptions
La propriété localeOptions spécifie la langue de toutes les étiquettes qui sont renvoyées par Apex. La valeur doit être un
paramètre régional valide de l'utilisateur (langue et pays), tel que fr_FR ou en_GB. La valeur est une chaîne d'une longueur
de 2 à 5 caractères. Les deux premiers caractères correspondent toujours à un code de langue ISO, par exemple 'fr' ou 'en'. Si
la valeur est ensuite définie avec un pays, la chaîne inclut également un trait de soulignement (_) et un autre code de pays ISO,
par exemple 'FR' ou 'UK'. SiPar exemple, pour les États-Unis la chaîne est 'en_US', et pour le français canadien la chaîne est
'fr_CA'.
Référence
salesforce | Méthodes Système Apex | 489
Pour une liste des langues prises en charge par Salesforce, reportez-vous à Quelles sont les langues prises en charge par Salesforce
? dans l'aide en ligne de Salesforce.
Propriété optAllOrNone
La propriété optAllOrNone spécifie si l'opération autorise un succès partiel. Si optAllOrNone est défini sur true, toutes
les modifications sont annulées dans tout enregistrement qui génère des erreurs. La valeur par défaut de cette propriété est
false, c.-à-d. que les enregistrements traités avec succès sont transmis alors que ceux contenant des erreurs ne le sont pas.
Cette propriété est disponible dans Apex enregistré en utilisant l'API Salesforce.com versions 20.0 et ultérieures.
Méthodes Database EmptyRecycleBinResult
Une liste d'objets Database.EmptyRecycleBinResult est renvoyée par la méthode Database.emptyRecycleBin. Chaque
objet de la liste correspond à un ID d'enregistrement ou à un sObject passé comme paramètre dans la méthode
Database.emptyRecycleBin. Le premier index dans la liste EmptyRecycleBinResult correspond au premier enregistrement
ou sObject spécifié dans la liste, le deuxième au deuxième, et ainsi de suite.
Les méthodes suivantes sont toutes des méthodes d'instance, c.-à-d. qu'elles fonctionnent dans une instance spécifique d'un
objet EmptyRecyclelBinResult. Aucune méthode ne prend d'argument.
Nom
Type de renvoi
Description
getErrors
Database.Errors []
Si une erreur se produit durant la suppression de cet
enregistrement ou sObject, une liste d'un ou de plusieurs objets
Database.Error est renvoyée. Si aucune erreur ne se produit,
cette liste est vide.
getId
ID
Renvoie l'ID de l'enregistrement ou sObject que vous avez
tenté de supprimer.
isSuccess
Boolean
Renvoie true si l'enregistrement ou le sObject a été supprimé
avec succès de la Corbeille, sinon renvoie false.
Méthodes Database Error Object
Un objet Database.error contient les informations sur une erreur survenue au cours d'une opération DML ou d'une autre
opération.
Toutes les opérations DML qui sont exécutées avec leur forme de méthode système de base de données renvoient un objet
d'erreur si elles échouent.
Tous les objets d'erreur ont accès aux méthodes suivantes :
Nom
Arguments
Type de renvoi Description
getMessage
String
Renvoie le texte du message d'erreur.
getStatusCode
StatusCode
Renvoie un code qui caractérise l'erreur. La liste complète
des codes de statut est disponible dans le fichier WSDL de
votre organisation (reportez-vous à Téléchargement des
certificats d'authentification client et des WSDL de
Salesforce dans l'aide en ligne de Salesforce).
Référence
salesforce | Méthodes Système Apex | 490
Prise en charge JSON
La prise en charge JSON (JavaScript Object Notation) dans le langage Apex active la sérialisation d'objets Apex sous le format
JSON et la désérialisation de contenu JSON sérialisé. Le langage Apex fournit un ensemble de classes qui exposent des
méthodes pour la sérialisation et la désérialisation JSON. Le tableau suivant présente les classes disponibles.
Classe
Description
System.JSON
Contient les méthodes pour la sérialisation d'objets Apex sous
le format JSON et la désérialisation de contenu JSON qui a
été sérialisé à l'aide de la méthode serialize dans cette
classe.
System.JSONGenerator
Contient les méthodes utilisées pour sérialiser des objets Apex
dans un contenu JSON à l'aide du codage JSON standard.
System.JSONParser
Représente un analyseur de contenu codé en JSON.
L'énumération System.JSONToken contient les jetons utilisés pour l'analyse JSON.
Les méthodes de ces classes lèvent une exception JSONException en cas de problème durant l'exécution.
Considérations sur la prise en charge JSON
•
•
•
•
•
•
•
La prise en charge de la sérialisation et de la désérialisation JSON est disponible pour les sObjects (objets standard
et objets personnalisés), les types primitive et collection Apex, les types de renvoi des méthodes Database (tels que
SaveResult, DeleteResult, etc.), et les instances de vos classes Apex.
Seuls les objets personnalisés, qui sont des types de sObject, de packages gérés peuvent être sérialisés à partir d'un
code extérieur au package géré. Les objets qui sont des instances de classes Apex définies dans le package géré ne
peuvent pas être sérialisés.
Les objets Map désérialisés dont les clés ne sont pas des chaînes ne correspondent pas à leur objet Map respectif avant
la sérialisation. Les valeurs de clé sont converties en chaînes durant la sérialisation, et leur type change lors de la
désérialisation. Par exemple, Map<Object, sObject> devient Map<String, sObject>.
Lorsqu'un objet est déclaré comme type parent, mais défini sur une instance du sous-type, certaines données peuvent
être perdues. Les objets sont sérialisés et désérialisés en tant que type parent et tous les champs spécifiques au sous-type
sont perdus.
Un objet qui se référence lui-même n'est pas sérialisé et entraîne une exception JSONException.
Les graphiques de référence qui référencent deux fois le même objet sont désérialisés et entraînent la génération de
plusieurs copies de l'objet référencé.
Le type de données System.JSONParser ne peut pas être sérialisé. Si vous avez une classe sérialisable, telle qu'un
contrôleur Visualforce, qui inclut une variable de membre de type System.JSONParser et que vous essayez de
créer cet objet, vous recevez une exception. Pour utiliser JSONParser dans une classe sérialisable, utilisez plutôt une
variable locale dans votre méthode.
Méthodes JSON
Contient des méthodes pour la sérialisation d'objets Apex sous le format JSON, et la désérialisation d'un contenu JSON
sérialisé en utilisant la méthode serialize dans cette classe.
Référence
salesforce | Méthodes Système Apex | 491
Utilisation
Utilisez les méthodes de la classe System.JSON pour exécuter des allers-retours de sérialisation et désérialisation JSON
d'objets Apex.
Méthodes
Les méthodes suivantes sont des méthodes statiques de la classe Schema.JSON.
Méthode
Arguments
createGenerator Boolean
pretty
createParser
String
Type de renvoi
System.JSONGenerator Renvoie un nouveau générateur JSON.
L'argument pretty détermine si le générateur JSON crée
un contenu JSON sous le format d'impression automatique
avec le contenu prévu. Définissez sur true pour créer un
contenu intentionnel.
System.JSONParser Renvoie un nouvel analyseur JSON.
jsonString
deserialize
String
Description
L'argument jsonString est le contenu JSON à analyser.
N'importe quel type
jsonString
Désérialise la chaîne JSON spécifiée dans un objet Apex du
type spécifié.
L'argument jsonString est le contenu JSON à désérialiser.
System.Type
apexType
L'argument apexType est le type Apex de l'objet que crée
cette méthode après la désérialisation du contenu JSON.
Si le contenu JSON à analyser contient des attributs absents
dans le type Apex spécifié dans l'argument, tel qu'un champ
ou un objet manquant, cette méthode ignore ces attributs et
analyse le reste du contenu JSON. Cependant, pour un code
Apex enregistré en utilisant l'API Salesforce.com version 24.0
ou antérieure, cette méthode lève une exception à l'exécution
pour les attributs manquants.
L'exemple suivant désérialise une valeur Decimal.
Decimal n = (Decimal)JSON.deserialize(
'100.1', Decimal.class);
System.assertEquals(n, 100.1);
deserializeStrict String
jsonString
System.Type
apexType
N'importe quel type
Désérialise la chaîne JSON spécifiée dans un objet Apex du
type spécifié. Tous les attributs de la chaîne JSON doivent
être présents dans le type spécifié.
L'argument jsonString est le contenu JSON à désérialiser.
L'argument apexType est le type Apex de l'objet que crée
cette méthode après la désérialisation du contenu JSON.
Si le contenu JSON à analyser contient des attributs absents
dans le type Apex spécifié dans l'argument, tel qu'un champ
ou un objet manquant, cette méthode lève une exception à
l'exécution.
Référence
Méthode
salesforce | Méthodes Système Apex | 492
Arguments
Type de renvoi
Description
L'exemple suivant désérialise une chaîne JSON dans un objet
d'un type défini par l'utilisateur représenté par la classe Car,
que cet exemple définit également.
public class Car {
public String make;
public String year;
}
public void parse() {
Car c = (Car)JSON.deserializeStrict(
'{"make":"SFDC","year":"2020"}',
Car.class);
System.assertEquals(c.make, 'SFDC');
System.assertEquals(c.year, '2020');
}
deserializeUntyped String
jsonString
N'importe quel type
Désérialise la chaîne JSON spécifiée dans des collections de
types de données primitifs.
L'argument jsonString est le contenu JSON à désérialiser.
L'exemple suivant désérialise une représentation JSON d'un
objet appliance dans un mappage contenant des types de
données primitifs et d'autres collections de types primitifs. Il
vérifie ensuite les valeurs désérialisées.
String jsonInput = '{\n' +
' "description" :"An appliance",\n' +
' "accessories" : [ "powerCord", ' +
'{ "right":"door handle1", ' +
'"left":"door handle2" } ],\n' +
' "dimensions" : ' +
'{ "height" : 5.5 , ' +
'"width" : 3.0 , ' +
'"depth" : 2.2 },\n' +
' "type" : null,\n' +
' "inventory" : 2000,\n' +
Référence
Méthode
salesforce | Méthodes Système Apex | 493
Arguments
Type de renvoi
Description
' "price" : 1023.45,\n' +
' "isShipped" : true,\n' +
' "modelNumber" : "123"\n' +
'}';
Map<String, Object> m =
(Map<String, Object>)
JSON.deserializeUntyped(jsonInput);
System.assertEquals(
'An appliance', m.get('description'));
List<Object> a =
(List<Object>)m.get('accessories');
System.assertEquals('powerCord', a[0]);
Map<String, Object> a2 =
(Map<String, Object>)a[1];
System.assertEquals(
'door handle1', a2.get('right'));
System.assertEquals(
'door handle2', a2.get('left'));
Map<String, Object> dim =
(Map<String, Object>)m.get('dimensions');
System.assertEquals(
5.5, dim.get('height'));
System.assertEquals(
3.0, dim.get('width'));
System.assertEquals(
2.2, dim.get('depth'));
System.assertEquals(null, m.get('type'));
Référence
salesforce | Méthodes Système Apex | 494
Méthode
Arguments
Type de renvoi
Description
System.assertEquals(
2000, m.get('inventory'));
System.assertEquals(
1023.45, m.get('price'));
System.assertEquals(
true, m.get('isShipped'));
System.assertEquals(
'123', m.get('modelNumber'));
serialize
N'importe quel String
type object
Sérialise des objets Apex dans un contenu JSON.
L'argument object est l'objet Apex à sérialiser.
L'exemple suivant sérialise une nouvelle valeur Datetime.
Datetime dt = Datetime.newInstance(
Date.newInstance(
2011, 3, 22),
Time.newInstance(
1, 15, 18, 0));
String str = JSON.serialize(dt);
System.assertEquals(
'"2011-03-22T08:15:18.000Z"',
str);
serializePretty N'importe quel String
type object
Sérialise des objets Apex dans un contenu JSON et génère
un contenu prévu à l'aide du format d'impression automatique.
L'argument object est l'objet Apex à sérialiser.
Exemple : Sérialisation et désérialisation d'une liste de relevés de facture
Cet exemple crée une liste d'objets InvoiceStatement et sérialise la liste. Ensuite, la chaîne JSON sérialisée est utilisée
pour désérialiser de nouveau la liste, et l'exemple vérifie que la nouvelle liste contient les mêmes factures que dans la liste
d'origine.
public class JSONRoundTripSample {
public class InvoiceStatement {
Référence
salesforce | Méthodes Système Apex | 495
Long invoiceNumber;
Datetime statementDate;
Decimal totalPrice;
public InvoiceStatement(Long i, Datetime dt, Decimal price)
{
invoiceNumber = i;
statementDate = dt;
totalPrice = price;
}
}
public static void SerializeRoundtrip() {
Datetime dt = Datetime.now();
// Create a few invoices.
InvoiceStatement inv1 = new InvoiceStatement(1,Datetime.valueOf(dt),1000);
InvoiceStatement inv2 = new InvoiceStatement(2,Datetime.valueOf(dt),500);
// Add the invoices to a list.
List<InvoiceStatement> invoices = new List<InvoiceStatement>();
invoices.add(inv1);
invoices.add(inv2);
// Serialize the list of InvoiceStatement objects.
String JSONString = JSON.serialize(invoices);
System.debug('Serialized list of invoices into JSON format: ' + JSONString);
// Deserialize the list of invoices from the JSON string.
List<InvoiceStatement> deserializedInvoices =
(List<InvoiceStatement>)JSON.deserialize(JSONString, List<InvoiceStatement>.class);
System.assertEquals(invoices.size(), deserializedInvoices.size());
Integer i=0;
for (InvoiceStatement deserializedInvoice :deserializedInvoices) {
system.debug('Deserialized:' + deserializedInvoice.invoiceNumber + ','
Référence
salesforce | Méthodes Système Apex | 496
+ deserializedInvoice.statementDate.formatGmt('MM/dd/yyyy
HH:mm:ss.SSS')
+ ', ' + deserializedInvoice.totalPrice);
system.debug('Original:' + invoices[i].invoiceNumber + ','
+ invoices[i].statementDate.formatGmt('MM/dd/yyyy
HH:mm:ss.SSS')
+ ', ' + invoices[i].totalPrice);
i++;
}
}
}
Voir aussi :
Méthodes Type
Méthodes JSONGenerator
Contient les méthodes utilisées pour sérialiser des objets Apex dans un contenu JSON à l'aide du codage JSON standard.
Utilisation
Dans certains cas, le codage JSON généré par Apex via la méthode de sérialisation dans la classe System.JSON est différente
du codage JSON standard. Par conséquent, la classe System.JSONGenerator est fournie pour activer la création d'un
contenu codé en JSON standard.
Méthodes
Les méthodes suivantes sont les méthodes d'instance de la classe Schema.JSONGenerator.
Méthode
Arguments
close
Type de
renvoi
Description
Void
Ferme le générateur JSON.
Aucun contenu ne peut être écrit après la fermeture du
générateur JSON.
String
getAsString
Renvoie le contenu JSON créé.
De plus, cette méthode ferme le générateur JSON si ce n'est
déjà fait.
Boolean
isClosed
Renvoie true si le générateur JSON est fermé, sinon renvoie
false.
writeBlob
Blob blobValue Void
Écrit la valeur Blob spécifiée en tant que chaîne codée en
base64.
writeBlobField
String fieldName Void
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur Blob spécifiés.
Blob blobValue
Référence
salesforce | Méthodes Système Apex | 497
Méthode
Arguments
Type de
renvoi
Description
writeBoolean
Boolean
Void
Écrit la valeur booléenne spécifiée.
blobValue
writeBooleanField
String fieldName Void
Boolean
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur Boolean spécifiés.
booleanValue
writeDate
Date dateValue Void
Écrit la valeur de date spécifiée sous le format ISO-8601.
writeDateField
String fieldName Void
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur spécifiés. La valeur de date est
écrite sous le format ISO-8601.
Date dateValue
writeDateTime
Datetime
Void
datetimeValue
writeDateTimeField String fieldName Void
Datetime
datetimeValue
Écrit la valeur de date et d'heure spécifiée sous le format
ISO-8601.
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la date/heure spécifiés. La valeur de
date/heure est écrite sous le format ISO-8601.
writeEndArray
Void
Écrit le marqueur final d'un tableau JSON (']').
writeEndObject
Void
Écrit le marqueur final d'un objet JSON ('}').
writeFieldName
String fieldName Void
Écrit un nom de champ.
writeId
ID identifier
Écrit la valeur d'ID spécifiée.
writeIdField
String fieldName Void
Void
Id identifier
Void
writeNull
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur d'identificateur spécifiés.
Écrit la valeur littérale null JSON.
writeNullField
String fieldName Void
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur littérale null JSON spécifiés.
writeNumber
Decimal number
Void
Écrit la valeur décimale spécifiée.
writeNumber
Double number
Void
Écrit la valeur double spécifiée.
writeNumber
Integer number
Void
Écrit la valeur d'entier spécifiée.
writeNumber
Long number
Void
Écrit la valeur de longueur spécifiée.
writeNumberField
String fieldName Void
Decimal number
writeNumberField
String fieldName Void
Double number
writeNumberField
String fieldName Void
Integer number
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur de décimale spécifiés.
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur de double spécifiés.
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur d'entier spécifiés.
Référence
salesforce | Méthodes Système Apex | 498
Méthode
Arguments
Type de
renvoi
writeNumberField
String fieldName Void
Long number
writeObject
N'importe quel
type object
Void
writeObjectField
String fieldName Void
N'importe quel
type object
Description
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur de longueur spécifiés.
Écrit l'objet Apex spécifié sous le format JSON.
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de l'objet Apex spécifiés.
writeStartArray
Void
Écrit le marqueur de début d'un tableau JSON ('[').
writeStartObject
Void
Écrit le marqueur de début d'un objet JSON ('{').
Void
Écrit la valeur de chaîne spécifiée.
writeString
String
stringValue
writeStringField
String fieldName Void
String
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur de chaîne spécifiés.
stringValue
writeTime
Time timeValue Void
Écrit la valeur d'heure spécifiée sous le format ISO-8601.
writeTimeField
String fieldName Void
Écrit une paire nom de champ - valeur de champ à l'aide du
nom de champ et de la valeur d'heure sous le format ISO-8601
spécifiés.
Time timeValue
Exemple de JSONGenerator
Cet exemple crée une chaîne JSON en utilisant les méthodes de JSONGenerator.
public class JSONGeneratorSample{
public class A {
String str;
public A(String s) { str = s; }
}
static void generateJSONContent() {
// Create a JSONGenerator object.
// Pass true to the constructor for pretty print formatting.
JSONGenerator gen = JSON.createGenerator(true);
Référence
salesforce | Méthodes Système Apex | 499
// Create a list of integers to write to the JSON string.
List<integer> intlist = new List<integer>();
intlist.add(1);
intlist.add(2);
intlist.add(3);
// Create an object to write to the JSON string.
A x = new A('X');
// Write data to the JSON string.
gen.writeStartObject();
gen.writeNumberField('abc', 1.21);
gen.writeStringField('def', 'xyz');
gen.writeFieldName('ghi');
gen.writeStartObject();
gen.writeObjectField('aaa', intlist);
gen.writeEndObject();
gen.writeFieldName('Object A');
gen.writeObject(x);
gen.writeEndObject();
// Get the JSON string.
String pretty = gen.getAsString();
System.assertEquals('{\n' +
'
"abc" : 1.21,\n' +
'
"def" : "xyz",\n' +
'
"ghi" : {\n' +
Référence
salesforce | Méthodes Système Apex | 500
'
"aaa" : [ 1, 2, 3 ]\n' +
'
},\n' +
'
"Object A" : {\n' +
'
"str" : "X"\n' +
'
}\n' +
'}', pretty);
}
}
Méthodes JSONParser
Représente un analyseur de contenu codé en JSON.
Utilisation
Utilisez les méthodes System.JSONParser pour analyser une réponse renvoyée depuis un appel à un service externe sous le
format JSON, telle qu'une réponse codée en JSON d'un appel de service Web.
Méthodes
Les méthodes suivantes sont des méthodes d'instance de la classe Schema.JSONParser.
Méthode
clearCurrentToken
Arguments
Type de renvoi
Description
Void
Supprime le jeton actuel.
Lorsque cette méthode est appelée, un appel à
hasCurrentToken renvoie false et un appel à
getCurrentToken renvoie null. Vous pouvez récupérer le
jeton effacé en appelant getLastClearedToken.
getBlobValue
Blob
Renvoie le jeton actuel en tant que valeur BLOB.
Le jeton actuel doit être de type JSONToken.VALUE_STRING
et doit être codé en base64.
getBooleanValue
Boolean
Renvoie le jeton actuel en tant que valeur booléenne.
Le jeton actuel doit être de type JSONToken.VALUE_TRUE ou
JSONToken.VALUE_FALSE.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur booléenne.
String JSONContent =
'{"isActive":true}';
JSONParser parser =
JSON.createParser(JSONContent);
// Advance to the start object marker.
Référence
Méthode
salesforce | Méthodes Système Apex | 501
Arguments
Type de renvoi
Description
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the Boolean value.
Boolean isActive = parser.getBooleanValue();
getCurrentName
String
Renvoie le nom associé au jeton actuel.
Si le jeton actuel est de type JSONToken.FIELD_NAME, cette
méthode renvoie la même valeur que getText. Si le jeton actuel
est une valeur, cette méthode renvoie le nom de champ qui
précède ce jeton. Pour d'autres valeurs, telles que des valeurs de
tableau ou des valeurs de niveau racine, cette méthode renvoie
null.
L'exemple suivant analyse un exemple de chaîne JSON. Il
progresse vers la valeur de champ et récupère son nom de champ
correspondant.
String JSONContent = '{"firstName":"John"}';
JSONParser parser =
JSON.createParser(JSONContent);
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the field name for the current value.
String fieldName = parser.getCurrentName();
// Get the textual representation
// of the value.
String fieldValue = parser.getText();
getCurrentToken
System.JSONToken Renvoie le jeton vers lequel l'analyseur pointe actuellement ou
null s'il n'existe actuellement aucun jeton.
L'exemple suivant itère dans tous les jetons dans un exemple de
chaîne JSON.
String JSONContent = '{"firstName":"John"}';
JSONParser parser =
Référence
Méthode
salesforce | Méthodes Système Apex | 502
Arguments
Type de renvoi
Description
JSON.createParser(JSONContent);
// Advance to the next token.
while (parser.nextToken() != null) {
System.debug('Current token: ' +
parser.getCurrentToken());
}
getDatetimeValue
Datetime
Renvoie le jeton actuel en tant que valeur de date et d'heure.
Le jeton actuel doit être de type JSONToken.VALUE_STRING
et doit représenter une valeur Datetime sous le format
ISO-8601.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur de date/heure.
String JSONContent =
'{"transactionDate":"2011-03-22T13:01:23"}';
JSONParser parser =
JSON.createParser(JSONContent);
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the transaction date.
Datetime transactionDate =
parser.getDatetimeValue();
getDateValue
Date
Renvoie le jeton actuel en tant que valeur de date.
Le jeton actuel doit être de type JSONToken.VALUE_STRING
et doit représenter une valeur Date sous le format ISO-8601.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur de date.
String JSONContent =
'{"dateOfBirth":"2011-03-22"}';
JSONParser parser =
JSON.createParser(JSONContent);
Référence
Méthode
salesforce | Méthodes Système Apex | 503
Arguments
Type de renvoi
Description
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the date of birth.
Date dob = parser.getDateValue();
getDecimalValue
Decimal
Renvoie le jeton actuel en tant que valeur décimale.
Le jeton actuel doit être de type
JSONToken.VALUE_NUMBER_FLOAT ou
JSONToken.VALUE_NUMBER_INT, et est une valeur numérique
qui peut être convertie en valeur de type Decimal.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur décimale.
String JSONContent =
'{"GPA":3.8}';
JSONParser parser =
JSON.createParser(JSONContent);
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the GPA score.
Decimal gpa = parser.getDecimalValue();
getDoubleValue
Double
Renvoie le jeton actuel en tant que valeur double.
Le jeton actuel doit être de type
JSONToken.VALUE_NUMBER_FLOAT, et est une valeur
numérique qui peut être convertie en valeur de type Double.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur double.
String JSONContent =
'{"GPA":3.8}';
JSONParser parser =
Référence
Méthode
salesforce | Méthodes Système Apex | 504
Arguments
Type de renvoi
Description
JSON.createParser(JSONContent);
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the GPA score.
Double gpa = parser.getDoubleValue();
getIdValue
ID
Renvoie le jeton actuel en tant que valeur d'ID.
Le jeton actuel doit être de type JSONToken.VALUE_STRING
et être un ID valide.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur d'ID.
String JSONContent =
'{"recordId":"001R0000002nO6H"}';
JSONParser parser =
JSON.createParser(JSONContent);
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the record ID.
ID recordID = parser.getIdValue();
getIntegerValue
Integer
Renvoie le jeton actuel en tant que valeur de nombre entier.
Le jeton actuel doit être de type
JSONToken.VALUE_NUMBER_INT et doit représenter un
Integer valide.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur de nombre entier.
String JSONContent =
'{"recordCount":10}';
JSONParser parser =
Référence
Méthode
salesforce | Méthodes Système Apex | 505
Arguments
Type de renvoi
Description
JSON.createParser(JSONContent);
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the record count.
Integer count = parser.getIntegerValue();
getLastClearedToken
System.JSONToken Renvoie le dernier jeton effacé par la méthode
clearCurrentToken.
getLongValue
Long
Renvoie le jeton actuel en tant que valeur de longueur.
Le jeton actuel doit être de type
JSONToken.VALUE_NUMBER_INT, et est une valeur numérique
qui peut être convertie en valeur de type Long.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur de longueur.
String JSONContent =
'{"recordCount":2097531021}';
JSONParser parser =
JSON.createParser(JSONContent);
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the record count.
Long count = parser.getLongValue();
getText
String
Renvoie la représentation textuelle du jeton actuel ou null s'il
n'existe actuellement aucun jeton.
Aucun jeton actuel n'existe, par conséquent cette méthode
renvoie null, si nextToken n'a pas encore été appelé une
première fois ou si l'analyseur a atteint la fin du flux d'entrée.
Pour consulter un exemple, reportez-vous à getCurrentName
à la page 501.
Référence
Méthode
getTimeValue
salesforce | Méthodes Système Apex | 506
Arguments
Type de renvoi
Description
Time
Renvoie le jeton actuel en tant que valeur d'heure.
Le jeton actuel doit être de type JSONToken.VALUE_STRING
et représenter une valeur Time sous le format ISO-8601.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur de date/heure.
String JSONContent =
'{"arrivalTime":"18:05"}';
JSONParser parser =
JSON.createParser(JSONContent);
// Advance to the start object marker.
parser.nextToken();
// Advance to the next value.
parser.nextValue();
// Get the arrival time.
Time arrivalTime = parser.getTimeValue();
hasCurrentToken
Boolean
Renvoie true si l'analyseur pointe actuellement vers un jeton,
sinon renvoie false.
nextToken
System.JSONToken Renvoie le jeton suivant ou null si l'analyseur a atteint la fin
du flux d'entrée.
Progresse suffisamment dans le flux pour déterminer le type du
jeton suivant, s'il existe.
Pour consulter un exemple, reportez-vous à getCurrentName
à la page 501.
nextValue
System.JSONToken Renvoie le jeton suivant qui est un type de valeur ou null si
l'analyseur a atteint la fin du flux d'entrée.
Progresse suffisamment dans le flux pour déterminer le type du
jeton suivant qui, s'il existe, est un type de valeur comprenant
un tableau JSON et des marqueurs de début et de fin.
Pour consulter un exemple, reportez-vous à getCurrentName
à la page 501.
readValueAs
System.Type N'importe quel
type
apexType
Désérialise un contenu JSON dans un objet du type Apex
spécifié et renvoie l'objet désérialisé.
L'argument apexType spécifie le type de l'objet que cette
méthode renvoie après la désérialisation de la valeur actuelle.
Si le contenu JSON à analyser contient des attributs absents
dans le type Apex spécifié dans l'argument, tels qu'un champ
Référence
Méthode
salesforce | Méthodes Système Apex | 507
Arguments
Type de renvoi
Description
ou un objet manquant, cette méthode ignore ces attributs et
analyse le reste du contenu JSON. Cependant, pour un code
Apex enregistré en utilisant l'API Salesforce.com version 24.0
ou antérieure, cette méthode lève une exception à l'exécution
pour les attributs manquants.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur de date/heure. Pour pouvoir exécuter cet
exemple, vous devez créer une classe Apex comme suit :
public class Person {
public String name;
public String phone;
}
Insérez ensuite l'exemple suivant dans une méthode de classe :
// JSON string that contains a Person object.
String JSONContent =
'{"person":{' +
'"name":"John Smith",' +
'"phone":"555-1212"}}';
JSONParser parser =
JSON.createParser(JSONContent);
// Make calls to nextToken()
// to point to the second
// start object marker.
parser.nextToken();
parser.nextToken();
parser.nextToken();
// Retrieve the Person object
// from the JSON string.
Person obj =
(Person)parser.readValueAs(
Person.class);
System.assertEquals(
obj.name, 'John Smith');
Référence
Méthode
salesforce | Méthodes Système Apex | 508
Arguments
Type de renvoi
Description
System.assertEquals(
obj.phone, '555-1212');
readValueAsStrict
System.Type N'importe quel
type
apexType
Désérialise un contenu JSON dans un objet du type Apex
spécifié et renvoie l'objet désérialisé. Tous les attributs dans le
contenu JSON doivent être présents dans le type spécifié.
L'argument apexType spécifie le type de l'objet que cette
méthode renvoie après la désérialisation de la valeur actuelle.
Si le contenu JSON à analyser contient des attributs absents
dans le type Apex spécifié dans l'argument, tel qu'un champ ou
un objet manquant, cette méthode lève une exception à
l'exécution.
L'exemple suivant analyse un exemple de chaîne JSON et
récupère une valeur de date/heure. Pour pouvoir exécuter cet
exemple, vous devez créer une classe Apex comme suit :
public class Person {
public String name;
public String phone;
}
Insérez ensuite l'exemple suivant dans une méthode de classe :
// JSON string that contains a Person object.
String JSONContent =
'{"person":{' +
'"name":"John Smith",' +
'"phone":"555-1212"}}';
JSONParser parser =
JSON.createParser(JSONContent);
// Make calls to nextToken()
// to point to the second
// start object marker.
parser.nextToken();
parser.nextToken();
parser.nextToken();
// Retrieve the Person object
// from the JSON string.
Référence
salesforce | Méthodes Système Apex | 509
Méthode
Arguments
Type de renvoi
Description
Person obj =
(Person)parser.readValueAsStrict(
Person.class);
System.assertEquals(
obj.name, 'John Smith');
System.assertEquals(
obj.phone, '555-1212');
skipChildren
Void
Ignore tous les jetons enfants de type
JSONToken.START_ARRAY et JSONToken.START_OBJECT
vers lesquels l'analyseur pointe actuellement.
Exemple : Analyse d'une réponse JSON à partir d'un appel de service Web
Cet exemple montre comment analyser une réponse formatée en JSON en utilisant des méthodes JSONParser. Il émet un
appel vers un service Web qui renvoie une réponse sous le format JSON. La réponse est ensuite analysée pour obtenir toutes
les valeurs de champ totalPrice, puis le prix total est calculé. Pour pouvoir exécuter cet exemple, vous devez ajouter l'URL de
point de destination du service Web à la liste des sites distants autorisés dans l'interface utilisateur de Salesforce. Pour cela,
connectez-vous à Salesforce, puis sélectionnez Votre nom > Configuration > Contrôles de sécurité > Paramètres de site
distant.
public class JSONParserUtil {
@future(callout=true)
public static void parseJSONResponse() {
Http httpProtocol = new Http();
// Create HTTP request to send.
HttpRequest request = new HttpRequest();
// Set the endpoint URL.
String endpoint = 'http://www.cheenath.com/tutorial/sfdc/sample1/response.php';
request.setEndPoint(endpoint);
// Set the HTTP verb to GET.
request.setMethod('GET');
// Send the HTTP request and get the response.
// The response is in JSON format.
HttpResponse response = httpProtocol.send(request);
System.debug(response.getBody());
/* The JSON response returned is the following:
Référence
salesforce | Méthodes Système Apex | 510
String s = '{"invoiceList":[' +
'{"totalPrice":5.5,"statementDate":"2011-10-04T16:58:54.858Z","lineItems":[' +
'{"UnitPrice":1.0,"Quantity":5.0,"ProductName":"Pencil"},' +
'{"UnitPrice":0.5,"Quantity":1.0,"ProductName":"Eraser"}],' +
'"invoiceNumber":1},' +
'{"totalPrice":11.5,"statementDate":"2011-10-04T16:58:54.858Z","lineItems":[' +
'{"UnitPrice":6.0,"Quantity":1.0,"ProductName":"Notebook"},' +
'{"UnitPrice":2.5,"Quantity":1.0,"ProductName":"Ruler"},' +
'{"UnitPrice":1.5,"Quantity":2.0,"ProductName":"Pen"}],"invoiceNumber":2}' +
']}';
*/
// Parse JSON response to get all the totalPrice field values.
JSONParser parser = JSON.createParser(response.getBody());
Double grandTotal = 0.0;
while (parser.nextToken() != null) {
if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
(parser.getText() == 'totalPrice')) {
// Get the value.
parser.nextToken();
// Compute the grand total price for all invoices.
grandTotal += parser.getDoubleValue();
}
}
system.debug('Grand total=' + grandTotal);
}
}
Exemple : Analyse d'une chaîne JSON et désérialisation de cette chaîne en objets
Cet exemple utilise une chaîne JSON codée en dur, qui est la même chaîne JSON renvoyée par l'appel dans l'exemple précédent.
Dans cet exemple, la chaîne entière est analysée dans des objets Invoice en utilisant la méthode readValueAs. Il utilise
également la méthode skipChildren pour ignorer le tableau enfant et les objets enfants, et peut analyser la facture semblable
suivante dans la liste. Les objets analysés sont des instances de la classe Invoice qui est définie en tant que classe interne.
Référence
salesforce | Méthodes Système Apex | 511
Puisque chaque facture contient des éléments de ligne, la classe qui représente le type d'élément de ligne correspondant,
LineItem, est également définie en tant que classe interne. Ajoutez cet exemple de code à une classe pour l'utiliser.
public static void parseJSONString() {
String jsonStr =
'{"invoiceList":[' +
'{"totalPrice":5.5,"statementDate":"2011-10-04T16:58:54.858Z","lineItems":[' +
'{"UnitPrice":1.0,"Quantity":5.0,"ProductName":"Pencil"},' +
'{"UnitPrice":0.5,"Quantity":1.0,"ProductName":"Eraser"}],' +
'"invoiceNumber":1},' +
'{"totalPrice":11.5,"statementDate":"2011-10-04T16:58:54.858Z","lineItems":[' +
'{"UnitPrice":6.0,"Quantity":1.0,"ProductName":"Notebook"},' +
'{"UnitPrice":2.5,"Quantity":1.0,"ProductName":"Ruler"},' +
'{"UnitPrice":1.5,"Quantity":2.0,"ProductName":"Pen"}],"invoiceNumber":2}' +
']}';
// Parse entire JSON response.
JSONParser parser = JSON.createParser(jsonStr);
while (parser.nextToken() != null) {
// Start at the array of invoices.
if (parser.getCurrentToken() == JSONToken.START_ARRAY) {
while (parser.nextToken() != null) {
// Advance to the start object marker to
//
find next invoice statement object.
if (parser.getCurrentToken() == JSONToken.START_OBJECT) {
// Read entire invoice object, including its array of line items.
Invoice inv = (Invoice)parser.readValueAs(Invoice.class);
system.debug('Invoice number: ' + inv.invoiceNumber);
system.debug('Size of list items: ' + inv.lineItems.size());
// For debugging purposes, serialize again to verify what was parsed.
String s = JSON.serialize(inv);
system.debug('Serialized invoice: ' + s);
// Skip the child start array and start object markers.
parser.skipChildren();
Référence
salesforce | Méthodes Système Apex | 512
}
}
}
}
}
// Inner classes used for serialization by readValuesAs().
public class Invoice {
public Double totalPrice;
public DateTime statementDate;
public Long invoiceNumber;
List<LineItem> lineItems;
public Invoice(Double price, DateTime dt, Long invNumber, List<LineItem> liList) {
totalPrice = price;
statementDate = dt;
invoiceNumber = invNumber;
lineItems = liList.clone();
}
}
public class LineItem {
public Double unitPrice;
public Double quantity;
public String productName;
}
L'énumération System.JSONToken
Valeur Enum
Description
END_ARRAY
La fin d'une valeur de tableau. Ce jeton est renvoyé lorsque ']'
est rencontré.
END_OBJECT
La fin d'une valeur d'objet. Ce jeton est renvoyé lorsque '}' est
rencontré.
Référence
salesforce | Méthodes Système Apex | 513
Valeur Enum
Description
FIELD_NAME
Un jeton de chaîne qui est un nom de champ.
NOT_AVAILABLE
Le jeton requis n'est pas disponible.
START_ARRAY
Le début d'une valeur de tableau. Ce jeton est renvoyé lorsque
'[' est rencontré.
START_OBJECT
Le début d'une valeur d'objet. Ce jeton est renvoyé lorsque '{'
est rencontré.
VALUE_EMBEDDED_OBJECT
Un objet incorporé qui n'est pas accessible en tant que structure
d'objet classique et qui comprend les jetons d'objet de début
et de fin START_OBJECT et END_OBJECT, mais qui est
représenté en tant qu'objet brut.
VALUE_FALSE
La valeur « false » littérale.
VALUE_NULL
La valeur « null » littérale.
VALUE_NUMBER_FLOAT
Une valeur de flottement.
VALUE_NUMBER_INT
Une valeur de nombre entier.
VALUE_STRING
Une valeur de chaîne.
VALUE_TRUE
Une valeur correspondant à la littérale de chaîne « true ».
Voir aussi :
Méthodes Type
Méthodes Limits
Comme le langage Apex est exécuté dans un environnement mutualisé, le moteur d'exécution Apex applique une limitation
stricte pour empêcher qu'un emballement de code Apex ne monopolise des ressources partagées.
Les méthodes Limits renvoient la limite spécifique du gouverneur particulier, notamment le nombre d'appels d'une méthode
ou la taille du segment mémoire restant.
Aucune méthodes Limits ne prend d'argument. Le format des méth