IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Salesforce.com Discussion :

[Apex][VF] Questions basiques (packages, i18n, etc)


Sujet :

Salesforce.com

  1. #1
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut [Apex][VF] Questions basiques (packages, i18n, etc)
    Bonjour,

    je débute en salesforce et je me pose quelques questions. J'ai essayé dans la mesure du possible de lire la doc, mais n'ai pas toujours trouvé mon bonheur. Merci d'avance de m'éclairer sur les points suivants:

    - peut-on regrouper nos classes ou triggers en 'packages'? Je viens de commencer, mais j'ai déjà des dizaines de fichiers dans un peu chaque répertoire de mon projet, et j'aimerais organiser cela un peu mieux...
    - un truc tout bête, a-t-on des fonctions de manipulation de string avancées (autres que ce qui est dispo dans la classe string, je pense surtout à une fonction null-safe equals entre 2 strings?)
    - un de mes besoins est de traduire mes applis, pour ça j'utilise la variable globale $Label en VF et la classe Label en Apex. A-t-on un moyen d'y injecter des paramètres? Genre "Label.format('You have {0} unread mails out of {1}', 3, 27)"?
    - je dois faire du rendu de DataTable paginée, venant d'un catalogue de produits contenant environ 200k enregistrements. J'ai cru comprendre que la classe StandardSetController gérait elle-même les dépassements des limites SF. Mais avec le code suivant:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
        private ApexPages.StandardSetController ctrl {
            get {
                if(ctrl==null) {
                    String q = 'SELECT Name, ProductCode, External_Id__c, Colour__c, PictureMini__c from Product2 WHERE VisibleOniPad__c = TRUE';
     
                    if(String.isNotBlank(actualFilterString)) {
                        q += ' AND (Name LIKE \'%'+String.escapeSingleQuotes(actualFilterString)+'%\' OR External_Id__c LIKE \'%'+String.escapeSingleQuotes(actualFilterString)+'%\')';
                    }
     
                    if(String.isNotBlank(mainProductGroupFilter)) {
                        q += ' AND MainProductGroup__c = \''+String.escapeSingleQuotes(mainProductGroupFilter)+'\'';
                    }
     
                    if(actualSort!=null) {
                        q += ' ORDER BY '+actualSort;
     
                        if('desc'.equalsIgnoreCase(actualSortDirection)) {
                            q += ' DESC';
                        }
                    }
     
                    q += ' LIMIT 10000';
     
                    System.debug('running query "'+q+'"');
     
                    ctrl = new ApexPages.StandardSetController(Database.getQueryLocator(q));
                    // Ne fonctionne pas ctrl = new ApexPages.StandardSetController(Database.getQueryLocator(Database.query(q)));
                }
     
                return ctrl;
            }
     
            set;
        }

    je suis obligé de mettre le "LIMIT 10000", sinon je prend une LimitException. J'ai bien vu dans la doc que pour que ça marche surtout si on passe une requête soql ou une liste (de ce que j'ai compris)... Pourtant dans mon cas je dois faire une requête soql dynamique, y a-t-il une solution pour coupler les 2? Car actuellement, avec "LIMIT 10000", je ne peux pas utiliser la méthode "getCompleteResult" pour indiquer à l'utilisateur que des résultats ne sont pas disponible (elle renvoie toujours 'true').
    - toujours en soql, j'aimerais utiliser des variables bindés dans la string, pour éviter tous ces appels à 'escapeSingleQuotes'. Selon la doc ça devrait marcher, mais je n'arrive pas à utiliser cela en conjonction avec le QueryLocator. Est-ce une limitation connue?
    - quelqu'un voit une bonne raison à la limitation de l'instruction soql "OFFSET" à un maximum de 2000? je suis tombé dessus l'autre jour, j'ai vraiment pas compris l'intérêt de nous limiter ça?

    Voilà ce sera tout pour l'instant. Merci d'avance de tout commentaire!

    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  2. #2
    Membre régulier
    Homme Profil pro
    Inscrit en
    Octobre 2004
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Octobre 2004
    Messages : 77
    Points : 97
    Points
    97
    Par défaut
    Salut et bienvenue sur la techno SFDC.

    J'ai répondu à une partie de tes questions dans le texte, je ferais les autres plus tard car je n'ai pas trop le temps.

    Citation Envoyé par Pill_S Voir le message
    Bonjour,

    je débute en salesforce et je me pose quelques questions. J'ai essayé dans la mesure du possible de lire la doc, mais n'ai pas toujours trouvé mon bonheur. Merci d'avance de m'éclairer sur les points suivants:

    - peut-on regrouper nos classes ou triggers en 'packages'? Je viens de commencer, mais j'ai déjà des dizaines de fichiers dans un peu chaque répertoire de mon projet, et j'aimerais organiser cela un peu mieux...
    OLE: c'est possible pour les classes via tout simplement des nested-types (classe définie dans une classe, comme dans à peu près n'importe quel langage objet).
    Cependant tu ne pourras pas déclarer de méthodes static dans les inner-classes. Il y a peut-être aussi d'autres limites mais je ne les connais pas/ou je ne les ais plus en tête.
    A noter que lors du développement d'une classe de test pour une inner-classe, tu dois obligatoirement instancier un objet de la classe de premier niveau pour que le code coverage soit calculé (sinon ce n'est pas le cas) => c'est un "bug" connu chez Salesforce sous la référence W-1256149.
    Pour ce qui est des triggers, je t'invite à ne jamais coder directement dedans mais plutôt d'implémenter les traitements dans une classe apex et d'ensuite appeller cette classe dans le trigger (ca te permettra d'écrire une classe de test pour vérifier le traitement associé au trigger), je pense que c'est une des bonnes pratiques de la méthode PAD.


    - un truc tout bête, a-t-on des fonctions de manipulation de string avancées (autres que ce qui est dispo dans la classe string, je pense surtout à une fonction null-safe equals entre 2 strings?)
    OLE: pas à ma connaissance, cependant tu peux très bien développer une classe utilitaire qui pourra, entre autre, contenir ta propre implémentation.
    En général l'apex est un langage simple et il faut pas mal de fois "réinventer" la roue en codant sa propre library mais une fois que c'est fait tu pourras t'en reservir sur d'autres projets donc je t'invite à le faire.


    - un de mes besoins est de traduire mes applis, pour ça j'utilise la variable globale $Label en VF et la classe Label en Apex. A-t-on un moyen d'y injecter des paramètres? Genre "Label.format('You have {0} unread mails out of {1}', 3, 27)"?
    OLE: je ne pense pas. Cependant, Label.TonLabel retourne une String donc rien ne t'empêche de faire "String.format(Label.TonLabel, TaListDeParam)".
    A ne pas oublier que pour tout ce qui est traduction de champs, de valeur de picklist, de helptext etc... tu as le translation workbench fait pour ça.


    - je dois faire du rendu de DataTable paginée, venant d'un catalogue de produits contenant environ 200k enregistrements. J'ai cru comprendre que la classe StandardSetController gérait elle-même les dépassements des limites SF. Mais avec le code suivant:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
        private ApexPages.StandardSetController ctrl {
            get {
                if(ctrl==null) {
                    String q = 'SELECT Name, ProductCode, External_Id__c, Colour__c, PictureMini__c from Product2 WHERE VisibleOniPad__c = TRUE';
     
                    if(String.isNotBlank(actualFilterString)) {
                        q += ' AND (Name LIKE \'%'+String.escapeSingleQuotes(actualFilterString)+'%\' OR External_Id__c LIKE \'%'+String.escapeSingleQuotes(actualFilterString)+'%\')';
                    }
     
                    if(String.isNotBlank(mainProductGroupFilter)) {
                        q += ' AND MainProductGroup__c = \''+String.escapeSingleQuotes(mainProductGroupFilter)+'\'';
                    }
     
                    if(actualSort!=null) {
                        q += ' ORDER BY '+actualSort;
     
                        if('desc'.equalsIgnoreCase(actualSortDirection)) {
                            q += ' DESC';
                        }
                    }
     
                    q += ' LIMIT 10000';
     
                    System.debug('running query "'+q+'"');
     
                    ctrl = new ApexPages.StandardSetController(Database.getQueryLocator(q));
                    // Ne fonctionne pas ctrl = new ApexPages.StandardSetController(Database.getQueryLocator(Database.query(q)));
                }
     
                return ctrl;
            }
     
            set;
        }

    je suis obligé de mettre le "LIMIT 10000", sinon je prend une LimitException. J'ai bien vu dans la doc que pour que ça marche surtout si on passe une requête soql ou une liste (de ce que j'ai compris)... Pourtant dans mon cas je dois faire une requête soql dynamique, y a-t-il une solution pour coupler les 2? Car actuellement, avec "LIMIT 10000", je ne peux pas utiliser la méthode "getCompleteResult" pour indiquer à l'utilisateur que des résultats ne sont pas disponible (elle renvoie toujours 'true').

    - toujours en soql, j'aimerais utiliser des variables bindés dans la string, pour éviter tous ces appels à 'escapeSingleQuotes'. Selon la doc ça devrait marcher, mais je n'arrive pas à utiliser cela en conjonction avec le QueryLocator. Est-ce une limitation connue?

    - quelqu'un voit une bonne raison à la limitation de l'instruction soql "OFFSET" à un maximum de 2000? je suis tombé dessus l'autre jour, j'ai vraiment pas compris l'intérêt de nous limiter ça?
    OLE: oui je pense qu'a un moment ou un autre il faut mettre des limites sinon tu consommes trop de ressource CPU et mémoire sur la plateforme d'infra, de plus ta page/ton webservice/ton batch mettrais trop de temps à s'exécuter.
    Imagine le nombre de client qu'a salesforce multiplié par le nombre d'account de ces clients... rien que sur mon projet j'ai plus de 5 millions d'Account, j'imagine pas avoir le droit de réccupérer ces 5 millions via une requête SoQL.


    Voilà ce sera tout pour l'instant. Merci d'avance de tout commentaire!

    Stay in touch

  3. #3
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Extra, merci pour toutes ces informations
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  4. #4
    Membre régulier
    Homme Profil pro
    Inscrit en
    Octobre 2004
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Octobre 2004
    Messages : 77
    Points : 97
    Points
    97
    Par défaut
    Hello,

    J'ai ajouté d'autres réponses en bleues dans le texte, il m'en reste plus qu'une

    Citation Envoyé par Pill_S Voir le message
    Bonjour,
    - je dois faire du rendu de DataTable paginée, venant d'un catalogue de produits contenant environ 200k enregistrements. J'ai cru comprendre que la classe StandardSetController gérait elle-même les dépassements des limites SF. Mais avec le code suivant:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
        private ApexPages.StandardSetController ctrl {
            get {
                if(ctrl==null) {
                    String q = 'SELECT Name, ProductCode, External_Id__c, Colour__c, PictureMini__c from Product2 WHERE VisibleOniPad__c = TRUE';
     
                    if(String.isNotBlank(actualFilterString)) {
                        q += ' AND (Name LIKE \'%'+String.escapeSingleQuotes(actualFilterString)+'%\' OR External_Id__c LIKE \'%'+String.escapeSingleQuotes(actualFilterString)+'%\')';
                    }
     
                    if(String.isNotBlank(mainProductGroupFilter)) {
                        q += ' AND MainProductGroup__c = \''+String.escapeSingleQuotes(mainProductGroupFilter)+'\'';
                    }
     
                    if(actualSort!=null) {
                        q += ' ORDER BY '+actualSort;
     
                        if('desc'.equalsIgnoreCase(actualSortDirection)) {
                            q += ' DESC';
                        }
                    }
     
                    q += ' LIMIT 10000';
     
                    System.debug('running query "'+q+'"');
     
                    ctrl = new ApexPages.StandardSetController(Database.getQueryLocator(q));
                    // Ne fonctionne pas ctrl = new ApexPages.StandardSetController(Database.getQueryLocator(Database.query(q)));
                }
     
                return ctrl;
            }
     
            set;
        }

    je suis obligé de mettre le "LIMIT 10000", sinon je prend une LimitException. J'ai bien vu dans la doc que pour que ça marche surtout si on passe une requête soql ou une liste (de ce que j'ai compris)... Pourtant dans mon cas je dois faire une requête soql dynamique, y a-t-il une solution pour coupler les 2? Car actuellement, avec "LIMIT 10000", je ne peux pas utiliser la méthode "getCompleteResult" pour indiquer à l'utilisateur que des résultats ne sont pas disponible (elle renvoie toujours 'true').
    OLE : dans la spec (http://www.salesforce.com/us/develop...code/index.htm rubrique Reference > Apex Classes > Visualforce Classes > StandardSetController class) il est marqué :
    The maximum record limit for StandardSetController is 10,000 records. Instantiating StandardSetController using a query locator returning more than 10,000 records causes a LimitException to be thrown. However, instantiating StandardSetController with a list of more than 10,000 records doesn’t throw an exception, and instead truncates the records to the limit.
    Donc en gros si tu passes au contrôleur une requête SoQL où nb resultats > 10.000, ca pète. Par contre si tu lui donne une liste qui dépasse les 10 000, ca marche (du moins ca ne lève pas d'exception).
    Je pensais qu'il suffisait de créer une liste via une requête et de la passer au contrôleur, mais j'ai également lu dans la même doc (Reference > DML Operations > Database methods > getQueryLocator) que
    Each executed getQueryLocator method counts against the governor limit of 10,000 total records retrieved and the total number of SOQL queries issued.
    Donc comme solutions tu aurais :
    - ajouter des critères de filtre à l'IHM, que l'utilisateur rempli et qui ont directement un impact sur la requête SoQL
    - ou essayer de "bricoler" quelque chose avec l'instruction SoQL 'OFFSET'.


    - toujours en soql, j'aimerais utiliser des variables bindés dans la string, pour éviter tous ces appels à 'escapeSingleQuotes'. Selon la doc ça devrait marcher, mais je n'arrive pas à utiliser cela en conjonction avec le QueryLocator. Est-ce une limitation connue?
    OLE: je vois pas ce que tu veux faire, tu aurais un exemple stp?
    Stay in touch

  5. #5
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    L'idée ce serait de pouvoir avoir
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    String q = 'SELECT Name, ProductCode, External_Id__c, Colour__c, PictureMini__c from Product2 WHERE VisibleOniPad__c = TRUE';
     
    if(String.isNotBlank(actualFilterString)) {
        q += ' AND (Name LIKE \'%:actualFilterString%\' OR External_Id__c LIKE \'%:actualFilterString%\')';
    }
     
    if(String.isNotBlank(mainProductGroupFilter)) {
        q += ' AND MainProductGroup__c = \':mainProductGroupFilter\'';
    }

    à la place de ça
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    String q = 'SELECT Name, ProductCode, External_Id__c, Colour__c, PictureMini__c from Product2 WHERE VisibleOniPad__c = TRUE';
     
    if(String.isNotBlank(actualFilterString)) {
        q += ' AND (Name LIKE \'%'+String.escapeSingleQuotes(actualFilterString)+'%\' OR External_Id__c LIKE \'%'+String.escapeSingleQuotes(actualFilterString)+'%\')';
    }
     
    if(String.isNotBlank(mainProductGroupFilter)) {
        q += ' AND MainProductGroup__c = \''+String.escapeSingleQuotes(mainProductGroupFilter)+'\'';
    }

    pour éviter, lors de la construction d'une requête soql dynamique, de devoir tout protéger via escapeSingleQuotes (ce qui alourdit beaucoup le code et induit un risque d'erreurs beaucoup plus grand).

    De ce que j'ai pu lire un peu partout, cela devrait fonctionner (on est juste limité par le fait que l'expression doit être simple, eg ":maVar.maMethode()" ne fonctionnera pas en dynamic soql)... Est-ce que c'est le jumelage avec le QueryLocator qui pose problème?

    Merci d'avance!
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  6. #6
    Membre régulier
    Homme Profil pro
    Inscrit en
    Octobre 2004
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Octobre 2004
    Messages : 77
    Points : 97
    Points
    97
    Par défaut
    Salut

    Je pense qu'à partir du moment où tu construis une requête SoQL par l'intermédiaire d'un objet de type String, tu n'as pas vraiment le choix.
    Stay in touch

  7. #7
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Et pourtant... ça devrait http://www.salesforce.com/us/develop...namic_soql.htm

    You can use simple bind variables in dynamic SOQL query strings. The following is allowed:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    String myTestString = 'TestName';
    List<sObject> L = Database.query('SELECT Id FROM MyCustomObject__c WHERE Name = :myTestString');
    However, unlike inline SOQL, dynamic SOQL can’t use bind variable fields in the query string. The following example isn’t supported and results in a Variable does not exist error:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MyCustomObject__c myVariable = new MyCustomObject__c(field1__c ='TestField');
    List<sObject> L = Database.query('SELECT Id FROM MyCustomObject__c WHERE field1__c = :myVariable.field1__c');
    You can instead resolve the variable field into a string and use the string in your dynamic SOQL query:
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    String resolvedField1 = myVariable.field1__c;
    List<sObject> L = Database.query('SELECT Id FROM MyCustomObject__c WHERE field1__c = ' + resolvedField1);
    D'ailleurs c'est un faux problème, je viens de réessayer et ça a fonctionné du premier coup... Je ne sais pas trop ce qui a fait que j'aie eu des problèmes.

    Merci en tout cas de te pencher sur mes problèmes
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  8. #8
    Membre régulier
    Homme Profil pro
    Inscrit en
    Octobre 2004
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Octobre 2004
    Messages : 77
    Points : 97
    Points
    97
    Par défaut
    Citation Envoyé par Pill_S Voir le message
    Et pourtant... ça devrait http://www.salesforce.com/us/develop...namic_soql.htm



    D'ailleurs c'est un faux problème, je viens de réessayer et ça a fonctionné du premier coup... Je ne sais pas trop ce qui a fait que j'aie eu des problèmes.

    Merci en tout cas de te pencher sur mes problèmes
    Ok, tant mieux dans ce cas

    Ce qui est intéressant dans la doc SFDC, c'est qu'au premier paragraphe ils indiquent qu'on peut utiliser la notation ':<var type string>' mais qu'au 3eme paragraphe (où ils passent par une string pour injecter la valeur du champ dans la requête) ils n'utilisent pas cette notation et utilisent la notation '+' classique qui, a priori, marche directement en mentionnant le champ de l'objet (genre '...Name = ' + myObj.Name).
    Stay in touch

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Question basique (sdl)
    Par insomniak dans le forum SDL
    Réponses: 2
    Dernier message: 24/10/2005, 18h03
  2. Question Basique Gestion Erreur VBA ...
    Par Le_Phasme dans le forum Access
    Réponses: 2
    Dernier message: 11/10/2005, 13h42
  3. Question basique
    Par PatLeOuf dans le forum C++
    Réponses: 1
    Dernier message: 23/03/2005, 10h57
  4. Réponses: 5
    Dernier message: 04/03/2005, 12h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo