Skip to main content

Mise en œuvre du stockage hors connexion avec SmartStore

Objectifs de formation

Une fois cette unité terminée, vous pourrez :

  • Comprendre les termes et les concepts de base de SmartStore
  • Utiliser SmartStore pour générer des requêtes SELECT
  • Enregistrer, générer et gérer des données SmartStore sur vos plates-formes cibles préférées (iOS, Android, hybride ou React Native)
  • Utiliser l’inspecteur SmartStore

Utilisation de SmartStore pour le stockage hors connexion

Les appareils mobiles peuvent être déconnectés à tout moment et les environnements comme les hôpitaux ou les avions interdisent souvent toute connexion. Afin de gérer ces situations, il est important que vos applications mobiles continuent à fonctionner même lorsqu'elles sont déconnectées. 

Le kit de développement mobile fournit un accès à SmartStore, une solution multithread sécurisée permettant un stockage hors connexion sur les périphériques mobiles. Avec SmartStore, vos clients peuvent continuer à exploiter leurs données dans un environnement sécurisé même lorsque leur appareil n’est plus connecté. En associant SmartStore à Mobile Sync, vous pouvez facilement faire en sorte que les données locales de SmartStore soient synchronisées avec le serveur Salesforce quand la connectivité revient.

SmartStore stocke les données dans des documents JSON, dans une base de données simple à table unique. Vous pouvez récupérer les données SmartStore soit avec les méthodes d’assistance du kit de développement mobile, soit par le biais de requêtes personnalisées à l’aide du langage Smart SQL de SmartStore.

Soupes

SmartStore stocke les données hors ligne dans des collections logiques appelées soupes. Une soupe SmartStore représente une table unique dans la base de données SQLite sous-jacente, également appelée magasin. Elle est généralement mappée avec un objet Salesforce standard ou personnalisé. Les soupes contiennent des éléments de soupe. Chaque élément est un objet JSON qui reflète une ligne unique de la base de données. Pour rationaliser l’accès aux données, vous définissez des index pour chaque soupe. Vous utilisez ces index pour interroger la soupe avec des méthodes d’assistance SmartStore ou le langage de requête Smart SQL de SmartStore. Les index SmartStore facilitent également votre travail en prenant en charge les requêtes de recherche en texte intégral.

Les soupes peuvent être comparées à des tableaux et les magasins à des bases de données. Vous pouvez définir autant de soupes que vous le souhaitez dans une application. En tant que jeux de données autonomes, les soupes n’ont aucune relation prédéfinie entre elles, mais vous pouvez utiliser des jointures Smart SQL pour les interroger ensemble. De plus, dans des applications natives, vous pouvez écrire à plusieurs soupes dans une seule transaction.

Remarque

Les données SmartStore sont volatiles. Dans la plupart des cas, leur durée de vie est liée à l’état de l’utilisateur authentifié et à celui du jeton OAuth. Lorsqu’un utilisateur quitte l’application, SmartStore supprime toutes les données de la soupe liées à cet utilisateur. De la même manière, lorsque le jeton d’actualisation OAuth expire ou est révoqué, l’état de l’application de l’utilisateur est réinitialisé et toutes les données contenues dans SmartStore sont effacées. Lors du développement de votre application, tenez compte de la volatilité des données de SmartStore, notamment si votre organisation a défini une durée de vie courte pour le jeton d’actualisation.

Smart SQL

SmartStore prend en charge le langage de requête Smart SQL pour des instructions SELECT libres. Seules les instructions SELECT sont prises en charge. Smart SQL associe toute la grammaire SQL SELECT standard à une syntaxe spéciale dédiée au référencement des soupes et des champs des soupes. Cette approche vous offre un contrôle et une flexibilité optimaux, en vous donnant notamment la possibilité d'utiliser des jointures.

Syntaxe

La syntaxe est identique aux spécifications SQL SELECT standard, à l'exception des adaptations suivantes :

Utilisation Syntaxe
Pour spécifier une colonne {<soupName>:<path>}
Pour spécifier une table {<soupName>}
Pour se référer à la totalité de la chaîne JSON de l'entrée de la soupe {<soupName>:_soup}
Pour se référer à l'ID interne de l'entrée de la soupe {<soupName>:_soupEntryId}
Pour se référer à la date de dernière modification {<soupName>:_soupLastModifiedDate}

Exemples de requêtes

Prenons deux soupes : l'une est nommée « Employés », l'autre « Services ». La soupe Employés contient des champs standard comme :

  • Prénom (firstName)
  • Nom (lastName)
  • Code du service (deptCode)
  • ID de l'employé (employeeId)
  • ID du responsable (managerId)

La soupe Services contient :

  • Nom (name)
  • Code du service (deptCode)

Voici quelques exemples de requêtes Smart SQL de base qui utilisent ces soupes :

select {employees:firstName}, {employees:lastName} 
 from {employees} order by {employees:lastName}
select {departments:name} 
 from {departments} 
 order by {departments:deptCode}

Jointures

Smart SQL vous permet également d’utiliser des jointures. Par exemple :

select {departments:name}, {employees:firstName} || ' ' || {employees:lastName}  
 from {employees}, {departments}  
 where {departments:deptCode} = {employees:deptCode}  
 order by {departments:name}, {employees:lastName}

Vous pouvez également joindre une table avec elle-même :

select mgr.{employees:lastName}, e.{employees:lastName}  
 from {employees} as mgr, {employees} as e  
 where mgr.{employees:employeeId} = e.{employees:managerId}
Remarque

Une jointure sur un index JSON1 nécessite une syntaxe légèrement étendue. Par exemple, au lieu de

select {soup1:path1} from {soup1}, {soup2}

utilisez

select {soup1}.{soup1:path1} from {soup1}, {soup2}

Fonctions d'agrégation

Smart SQL prend en charge l’utilisation de fonctions d’agrégation telles que :

  • COUNT
  • SUM
  • AVG

Par exemple :

select {account:name}, 
    count({opportunity:name}),
    sum({opportunity:amount}),
    avg({opportunity:amount}),
    {account:id},
    {opportunity:accountid} 
 from {account},
    {opportunity} 
 where {account:id} = {opportunity:accountid} 
 group by {account:name}

Enregistrement d’une soupe

Avant d’utiliser une soupe, enregistrez-la. Si la soupe n’existe pas, le fait de l’enregistrer permettra de la créer. Si elle existe, l’enregistrement vous y donnera accès. Pour enregistrer des soupes, il vous faut créer un fichier de configuration JSON et le charger au moment de l’exécution. Un seul fichier de configuration peut définir toutes les soupes de votre application. Mobile SDK prend en charge les fichiers de configuration dans les applications natives et hybrides.

Les fichiers de configuration enregistrent uniquement des soupes dans le magasin utilisateur par défaut ou le magasin global par défaut. Pour utiliser d’autres magasins nommés ou des magasins externes, vous devez enregistrer les soupes avec des API SmartStore. Le kit de développement mobile fournit des méthodes permettant de définir le nom et les index d’une soupe, puis de l’enregistrer.

Lorsque vous enregistrez une soupe, vous créez dans la mémoire une structure nommée vide en attente de données. Une soupe est en général initialisée au moyen de données issues d’une organisation Salesforce. Afin d’obtenir les données Salesforce, il vous faut utiliser le mécanisme de requêtes REST standard du kit de développement mobile. Lorsqu’une réponse REST positive arrive, vous extrayez les données de l’objet de la réponse et vous les ajoutez à votre soupe (upsert) :

Durant la création de la soupe, des erreurs peuvent se produire pour diverses raisons, notamment :

  • Nom de soupe erroné ou non valide
  • Pas d’index (au moins un index doit être spécifié)
  • Autres erreurs inattendues, comme une erreur de base de données

Structure de la soupe

Pour définir une soupe, vous indiquez un nom pour la soupe, ainsi qu’une liste d’une ou plusieurs spécifications pour l’index. Les index sont basés sur les champs de la soupe. Il n’est pas nécessaire de fournir une spécification d’index pour chaque champ stocké dans la soupe. Par exemple, si vous utilisez la soupe comme magasin clé-valeur, utilisez une spécification d’index unique de type chaîne. Une fois les soupes créées, SmartStore utilise les index pour suivre toutes les opérations d’insertion, de mise à jour ou de suppression.

SmartStore prend en charge les types de données d’index suivants :

  • string
  • integer
  • floating
  • full_text
  • json1

Définition des index

Dans les applications natives et hybrides, vous pouvez utiliser des fichiers de configuration pour enregistrer des soupes et définir leurs index. Dans les applications React Native, vous utilisez du code JavaScript. Quelques règles s’appliquent dans chacun des cas.

  • Les chemins d’index sont sensibles à la casse et peuvent inclure des chemins composés, comme Owner.Name.
  • Les entrées d’index auxquelles il manque des champs décrits dans un tableau de spécification d’index ne sont pas identifiées dans cet index.
  • Le type d’index ne s’applique qu’à l’index concerné. Lorsque vous effectuez une requête sur un champ indexé (par exemple, « select {soup:path} from {soup} »), la requête renvoie des données du type choisi dans la spécification de l’index.
  • Les colonnes de l’index peuvent contenir des champs « null ».
  • Depuis la version 9.1 du kit de développement mobile, les chemins d’index ne sont plus requis pour les champs référencés dans les clauses SELECT ou WHERE.
  • Vous pouvez spécifier des chemins d’index pointant vers des nœuds internes (qui ne sont pas des feuilles). Vous pouvez utiliser des chemins internes avec des requêtes like et match (texte intégral). Utilisez le type string lorsque vous définissez des chemins de nœuds internes. Prenons l’exemple de cet élément dans une soupe appelée « spies » :
    {  
       "first_name":"James",
       "last_name":"Bond",
       "address":{  
          "street_number":10,
          "street_name":"downing",
          "city":"london"
       }
     }
    Dans ce cas, « address » est un nœud interne, car il a des enfants. À partir de l’index du chemin « address », vous pouvez utiliser une requête like ou match pour obtenir la valeur de « city » (« london ») dans « address ». Par exemple :
    SELECT {spies:first_name, spies:last_name} FROM spies WHERE {spies:address} LIKE 'london'

Format du fichier de configuration

Voici un exemple théorique de fichier de configuration JSON qui définit deux soupes (soup1 et soup2) et montre l’ensemble des possibilités des types de données d’index.

{  "soups": [
    {
      "soupName": "soup1",
      "indexes": [
        { "path": "stringField1", "type": "string"},
        { "path": "integerField1", "type": "integer"},
        { "path": "floatingField1", "type": "floating"},
        { "path": "json1Field1", "type": "json1"},
        { "path": "ftsField1", "type": "full_text"}
      ]
    },
    {
      "soupName": "soup2",
      "indexes": [
        { "path": "stringField2", "type": "string"},
        { "path": "integerField2", "type": "integer"},
        { "path": "floatingField2", "type": "floating"},
        { "path": "json1Field2", "type": "json1"},
        { "path": "ftsField2", "type": "full_text"}
      ]
    }
  ]
 }

Pour plus d’informations sur l’enregistrement de vos soupes avec du code au lieu de fichiers de configuration, consultez le guide de développement du kit de développement mobile.

Remarque

Si votre code et votre fichier de configuration enregistrent tous deux une soupe portant le même nom, le kit de développement mobile ignorera la définition du fichier de configuration.

Le fichier de configuration suivant enregistre une seule soupe basée sur des enregistrements de comptes. Cette soupe a des index pour les champs de nom, d’identifiant et d’identifiant de propriétaire (ou de parent). Il n’est pas obligatoire que les noms des soupes correspondent au nom de l’objet Salesforce source, mais il est généralement recommandé d’y faire clairement référence.

{  "soups": [
    {
      "soupName": "account",
      "indexes": [
        { "path": "Name", "type": "string"},
        { "path": "Id", "type": "string"},
        { "path": "OwnerId", "type": "string"}
      ]
    }
  ]
 }

Insertion ou mise à jour des entrées d'une soupe

Pour insérer ou mettre à jour les entrées d’une soupe, en laissant SmartStore décider de l’action qui convient, il vous faut utiliser une méthode upsert. Par exemple, une application hybride peut utiliser l’une de ces versions de JavaScript :

navigator.smartStore.upsertSoupEntries(isGlobalStore, soupName, 
    entries[], successCallback, errorCallback)
navigator.smartStore.upsertSoupEntries(storeConfig, soupName, 
    entries[], successCallback, errorCallback)

Vous précisez le nom de votre soupe, un tableau d’entrées sous forme de chaînes JSON, et des fonctions de rappel facultatives de réussite et d’erreur. La seule différence entre ces deux méthodes est le premier paramètre. Si votre soupe se trouve dans un magasin nommé utilisateur ou global, vous utilisez le paramètre storeConfig pour indiquer le type de magasin et son nom. Par exemple :

{isGlobalStore:true, name:"AcmeSales"}

Si vous utilisez le magasin utilisateur ou global par défaut, vous pouvez simplement passer true pour indiquer un magasin global. Dans les autres cas, l’argument n’est pas nécessaire. Ce paramètre est facultatif et sa valeur par défaut est false. Il n’est pas présent dans les méthodes natives, qui obtiennent les mêmes informations auprès d’objets associés.

Interrogation et gestion de SmartStore

Le kit de développement mobile pour les applications natives iOS fournit des méthodes de fabrique qui créent des objets de « spécification de requête » en fonction de vos entrées. Les méthodes d’usine créent des requêtes à partir des opérateurs WHERE suivants :

  • = (opérateur « exact »)
  • LIKE
  • MATCH (extension de recherche en texte intégral)
  • BETWEEN, <=, >= (requête sur intervalle)
  • ALL

Ces objets de requête traitent les requêtes simples et directes, ce qui vous évite d’avoir à les écrire vous-même. Pour plus de nuance dans des situations complexes, vous pouvez écrire vos propres requêtes Smart SQL et les passer à la méthode d’usine Smart SQL. Vous obtenez alors un objet requête que vous passez à une méthode d’exécution qui récupère les données spécifiées de la soupe.

Gestion d'une soupe

Parfois vous voudrez nettoyer les données inutilisées, ou améliorer les performances d’une soupe en modifiant ses index. Pour les tâches de ce type, SmartStore possède un ensemble de méthodes dédiées aux tâches de diagnostic, de maintenance et de gestion. Utilisez ces méthodes pour obtenir des informations sur une soupe ou un magasin, modifier la structure d’une soupe, ou supprimer des soupes ou des magasins.

Grâce à ces méthodes, vous pouvez notamment réaliser les actions suivantes :

  • Obtenir la taille de la base de données sous-jacente
  • Obtenir une liste de tous les magasins (utilisateur ou globaux)
  • Vérifier si une soupe portant le nom indiqué existe
  • Récupérer les spécifications d’une soupe et de ses index
  • Altérer la configuration d’une soupe
  • Réindexer une soupe
  • Supprimer tous les enregistrements d’une soupe
  • Supprimer une soupe du magasin
  • Supprimer un magasin
  • Supprimer tous les magasins (utilisateur ou globaux)

Ces méthodes sont disponibles sur toutes les plates-formes et pour tous les types d’application.

Utilisation de l’inspecteur SmartStore

Durant la phase de test, il est recommandé de vérifier que votre code prend en charge les données SmartStore comme vous le souhaitiez. L’inspecteur SmartStore fournit un outil d’interface utilisateur dédié à cet usage. Avec celui-ci, vous pourrez :

  • Examiner les métadonnées de toute soupe, comme les noms et spécifications d’index
  • Effacer le contenu d’une soupe
  • Réaliser des requêtes Smart SQL

Pour un accès facile, lancez l’inspecteur SmartStore depuis la boîte de dialogue Assistance au développeur. 

La manière d’accéder au menu Assistance au développeur dépend de votre environnement de développement. Pour lancer la boîte de dialogues, utilisez l’une des options suivantes.

Android

Effectuez l’une des actions suivantes :

  • Lorsque votre application est exécutée dans l’émulateur Android, utilisez le raccourci clavier Commande+m (Mac) ou Ctrl+m (Windows).
  • Dans une invite de commandes système, exécutez : adb shell input keyevent 82

iOS

  • Sur un appareil physique, secouez légèrement l’appareil pour faire apparaître le menu Assistance au développeur, puis sélectionnez Inspecteur SmartStore.
  • Dans le simulateur iOS, sélectionnez l’élément de menu Matériel > Secousse, ou utilisez le raccourci clavier ^+Commande+z.

Utilisation de SmartStore dans des applications iOS natives

Ajouter le module SmartStore aux nouvelles applications natives iOS ne demande pas d’effort particulier. Toute application forceios native que vous créez contient automatiquement la bibliothèque SmartStore.

Enregistrement de soupes avec un fichier de configuration

Pour les applications iOS natives, le kit de développement mobile recherche les fichiers de configuration dans / (dossier principal) dans le paquet Ressources.

  1. Ajoutez des fichiers de configuration à votre projet.
    1. Dans le navigateur de projet Xcode, sélectionnez le nœud du projet.
    2. Dans la fenêtre de l’éditeur, sélectionnez Build Phases.
    3. Agrandissez Copy Bundle Resources.
    4. Cliquez sur + (« Ajouter des éléments »).
    5. Sélectionnez le fichier de configuration de votre soupe. Si votre fichier ne se trouve pas déjà dans un dossier du projet Xcode :
      1. Pour sélectionner votre fichier dans Finder, cliquez sur Add Other….
      2. Lorsque l’on vous propose de créer des groupes, cliquez sur Finish.
  2. Ajoutez une seule ligne de code par fichier fourni.
    • Pour charger un fichier userstore.json, utilisez l’une de ces méthodes :
      SmartStoreSDKManager.shared().setupUserStoreFromDefaultConfig()
    • Pour charger un fichier globalstore.json, utilisez l’une de ces méthodes :
      SalesforceManager.shared().setupGlobalStoreFromDefaultConfig()

Peupler une soupe

Lorsque vous enregistrez une soupe, vous créez dans la mémoire une structure nommée vide en attente de données. Pour la peupler à partir de données Salesforce, utilisez le mécanisme de requêtes REST standard afin d’obtenir les données. Lorsqu'une réponse REST positive arrive, extrayez les données de l'objet de la réponse et ajoutez-les à votre soupe (upsert). Pour plus de détails sur l’écriture du code, consultez l’exemple présenté à la fin de cette section iOS.

Interrogation des données d’une soupe

Sous iOS, on crée les objets de spécification de requête en appelant des méthodes de classe sur la classe SFQuerySpec. Par exemple, en Objective-C, la méthode newSmartQuerySpec:withPageSize: crée un objet SFQuerySpec qui encapsule une chaîne de requête Smart SQL donnée :

var querySpec = store.buildSmartQuerySpec(
    smartSql: "select {account:Name} from {account}",
    pageSize: 10)

Le paramètre de taille de la page détermine le nombre d’enregistrements envoyés dans chaque page de résultats. Ces méthodes offrent une plus grande flexibilité que les autres fonctions de fabrique servant aux requêtes, car vous fournissez votre propre instruction SELECT Smart SQL. Par exemple, le code suivant émet une requête qui appelle la fonction SQL COUNT. Puisque COUNT renvoie une valeur unique, la seule taille de page possible est une.

Le code suivant émet une requête qui appelle la fonction SQL COUNT. Puisque COUNT renvoie une valeur unique, la seule taille de page possible est une.

Pour exécuter une requête, passez votre objetQuerySpec à la méthode query() de l’objet SmartStore.

var querySpec = store.buildSmartQuerySpec(
    smartSql: "select count(*) from {employees}",
    pageSize: 1)

Gestion d'une soupe

Pour utiliser des API de gestion des soupes Objective-C dans une application iOS native, importez SmartStore/SFSmartStore.h. Vous appelez des méthodes de gestion des soupes sur une instance partagée SFSmartStore. Vous obtiendrez l'instance partagée grâce à l'une des méthodes de classe SFSmartStore suivantes.

Pour obtenir l’instance SmartStore pour l’utilisateur actuel :

var store = SmartStore.shared(withName:storeName)

Pour obtenir l’instance SmartStore pour un utilisateur donné :

var store = SmartStore.shared(withName:storeName, forUserAccount:user)

Par exemple, pour appeler la méthode de gestion removeSoup: :

self.store = [SFSmartStore sharedStoreWithName:kDefaultSmartStoreName];
 if ([self.store soupExists:@"Accounts"]) {
    [self.store removeSoup:@"Accounts"];
 }

Exemple

Dans cet exemple, vous créez une application Swift. Le modèle Swift natif pour forceios comprend déjà une implémentation SmartStore, nous allons donc simplement vérifier sa configuration. 

  1. En utilisant forceios, créez un projet Swift natif semblable à l'exemple suivant :
    $ forceios create Enter your application type (native_swift or native, leave empty for native_swift):<Press RETURN>
    Enter your application name:<Enter any name you like>
    Enter your package name:com.myapps.ios
    Enter your organization name (Acme, Inc.):MyApps.com
    Enter output directory for your app (leave empty for the current directory):<Press RETURN or enter a directory name>
  2. Ouvrez le fichier .xcworkspace de votre application dans Xcode.
  3. Dans le dossier du projet, développez Fichiers de support.
  4. Ouvrez le fichier userstore.json et inspectez la configuration SmartStore.
  5. Pour ajouter le fichier de configuration au paquet de l’application compilée, le modèle référence ces fichiers dans les paramètres du projet.
    1. Dans le navigateur de projet Xcode, sélectionnez le nœud principal du projet.
    2. Dans la fenêtre de l’éditeur, sélectionnez Build Phases.
    3. Agrandissez Copy Bundle Resources.
    4. Remarquez la présence dans la liste de userstore.json.
  6. Dans le dossier du code source de votre projet, sélectionnez Classes/SceneDelegate.swift.
  7. Dans la méthode scene(_:willConnectTo:options:), recherchez l’appel à setupRootViewController().
  8. Pour voir où les fichiers de configuration SmartStore sont chargés, utilisez la combinaison CTRL + clic sur setupRootViewController() et sélectionnez Accéder à la définition.

Pour afficher la configuration SmartStore de l’application au moment de l’exécution, procédez comme suit : 

  1. Lancez l’application.
  2. Après vous être connecté et avoir autorisé l’application, affichez le menu Outils de développement.
    1. Utilisez la combinaison Contrôle + Commande + z si vous utilisez le simulateur iOS, ou secouez votre appareil iOS.
    2. Cliquez sur Inspecter SmartStore.
    3. Pour obtenir une liste de vos soupes et de leur quantité d’enregistrements, cliquez sur Soupes.

Utilisation de SmartStore dans des applications Android natives

Par défaut, toutes les applications natives forcedroid comprennent des bibliothèques SmartStore et Mobile Sync. Cependant, la réalisation de quelques étapes de configuration personnalisées peut être nécessaire pour les applications Android plus anciennes.

  1. Dans votre projet natif Android, ouvrez MainApplication.java.
  2. Si elle est absente, ajoutez l'instruction d'importation suivante :
    import com.salesforce.androidsdk.mobilesync.app.MobileSyncSDKManager;
  3. Accédez à la ligne qui appelle initNative(). Par exemple :
    SalesforceSDKManager.initNative(getApplicationContext(), new NativeKeyImpl(), MainActivity.class);
  4. Si initNative() est appelée dans SalesforceSDKManager, remplacez SalesforceSDKManager par MobileSyncSDKManager :
    MobileSyncSDKManager.initNative(getApplicationContext(), new NativeKeyImpl(), MainActivity.class);

Enregistrement de soupes avec un fichier de configuration

  1. Placez vos fichiers de configuration de soupe dans le dossier de projet /res/raw/.
  2. Ajoutez une seule ligne de code par fichier fourni.
    • Pour charger un fichier userstore.json, utilisez ce qui suit :
      SmartStoreSDKManager.getInstance().setupUserStoreFromDefaultConfig();
    • Pour charger un fichier globalstore.json, utilisez ce qui suit :
      SmartStoreSDKManager.getInstance().setupGlobalStoreFromDefaultConfig();

Peupler une soupe

Lorsque vous enregistrez une soupe, vous créez dans la mémoire une structure nommée vide en attente de données. Pour la peupler à partir de données de Salesforce, utilisez le mécanisme de requêtes REST standard afin d'obtenir les données. Lorsqu'une réponse REST positive arrive, extrayez les données de l'objet de la réponse et ajoutez-les à votre soupe (upsert) :

public void populateAccounts() throws UnsupportedEncodingException {
    final RestRequest restRequest =
        RestRequest.getRequestForQuery(
            ApiVersionStrings.getVersionNumber(SalesforceSDKManager.getInstance().getAppContext()), 
            "SELECT Name, Id, OwnerId FROM Account");
    client.sendAsync(restRequest, new RestClient.AsyncRequestCallback() {
        @Override
        public void onSuccess(RestRequest request, RestResponse result) {
            result.consumeQuietly(); // always call before switching to main thread (unlike here)
            try {
                JSONArray records = result.asJSONObject().getJSONArray("records");
                insertAccounts(records);
            } catch (Exception e) {
                onError(e);
            } finally {
                Log.println(Log.INFO, "REST Success!", "\nSmartStore insertion successful");
            }
        }
        @Override
        public void onError(Exception e)
        {
            Log.e(TAG, e.getLocalizedMessage());
        }
    });
 }
/**
 * Inserts accounts into the accounts soup.
 *
 * @param accounts Accounts.
 */
 public void insertAccounts(JSONArray accounts)
 {
    try {
        if (accounts != null) {
            for (int i = 0; i < accounts.length(); i++) {
                if (accounts.get(i) != null) {
                    try {
                        smartStore.upsert("Accounts", accounts.getJSONObject(i));
                    }
                    catch (JSONException exc) {
                        Log.e(TAG, "Error occurred while attempting to insert account. "
                                +  "Please verify validity of JSON data set.");
                    }
                }
            }
        }
    }
    catch (JSONException e) {
        Log.e(TAG, "Error occurred while attempting to insert accounts. "
                + "Please verify validity of JSON data set.");
    }
 }

Lancement d’une requête sur les données de la soupe avec Smart SQL

Dans Android, on crée les objets de spécification de requête en appelant des méthodes d’usine statiques sur la classe QuerySpec. Par exemple, la méthode buildSmartQuerySpec crée un objet Smart SQL qui encapsule une chaîne de requête donnée :

public static QuerySpec buildSmartQuerySpec(String smartSql, int pageSize)

Pour exécuter la requête, vous transmettez l’objet QuerySpec renvoyé à la méthode SmartStore.query(). Cette fonction offre une plus grande flexibilité que les autres fonctions de requête standard car vous fournissez votre propre instruction SELECT Smart SQL. Le paramètre pageSize détermine le nombre d'enregistrements envoyés dans chaque page de résultats.

Pour exécuter une requête via un objetQuerySpec, passez-le à la méthode query() de l’objet SmartStore. Le code suivant émet une requête qui appelle la fonction SQL COUNT. Puisque COUNT renvoie une valeur unique, la seule taille de page possible est une.

try {
    JSONArray result =
        store.query(QuerySpec.buildSmartQuerySpec(
            "select count(*) from {Accounts}", 1), 0);
    // result should be [[ n ]] if there are n employees
    Log.println(Log.INFO, "REST Success!", "\nFound " + 
        result.getString(0) + " accounts.");
 } catch (JSONException e) {
    Log.e(TAG, "Error occurred while counting the number of account records. "
        +  "Please verify validity of JSON data set.");
 }

Gestion d'une soupe

Pour utiliser des API de gestion de soupes dans une application Android native, vous devez appeler des méthodes sur l’instance partagée de SmartStore :

SmartStore smartStore = 
    SmartStoreSDKManager.getInstance().getSmartStore();
 smartStore.clearSoup("user1Soup");

Il n’est pas difficile d’ajouter la prise en charge de SmartStore à une application native forcedroid. Reconfigurons le fichier d’importation JSON pour créer deux soupes, une pour chaque requête sObject. Nous pouvons ensuite remplir les soupes en même temps que nous remplissons la vue de liste.

  1. Ouvrez votre projet dans Android Studio.
  2. Dans le dossier app/res, créez un dossier nommé « raw ».
  3. Faites un clic droit sur app/res/raw et sélectionnez Nouveau > Fichier. Nommez ce fichier userstore.json.
  4. Ajoutez le texte suivant au fichier :
    { "soups": [
        {
        "soupName": "Account",
        "indexes": [
            { "path": "Name", "type": "string"},
            { "path": "Id", "type": "string"},
            { "path": "OwnerId", "type": "string"},
            ]
        },
        {
        "soupName": "Contact",
        "indexes": [ 
            { "path": "Name", "type": "string"},
            { "path": "Id", "type": "string"},
            { "path": "OwnerId", "type": "string"},
            ]
        }
     ]}
  5. Ouvrez MainActivity.java et importez ces fichiers :
    import com.salesforce.androidsdk.smartstore.app.SmartStoreSDKManager;
     import com.salesforce.androidsdk.smartstore.store.IndexSpec;
     import com.salesforce.androidsdk.smartstore.store.QuerySpec;
     import com.salesforce.androidsdk.smartstore.store.SmartStore;
     import com.salesforce.androidsdk.smartstore.ui.SmartStoreInspectorActivity;
  6. En haut de la classe MainActivity, déclarez une variable privée pointant vers l’instance partagée SmartStore, et une autre pour suivre quel sObject nous manipulons :
    private SmartStore smartStore;private String objectType;
  7. Dans la méthode onCreate(Bundle savedInstanceState), importez les définitions de soupe depuis votre fichier userstore.json :
    smartStore = SmartStoreSDKManager.getInstance().getSmartStore();
     if (!smartStore.hasSoup("Account") && !smartStore.hasSoup("Contact")) {
        SmartStoreSDKManager.getInstance().setupUserStoreFromDefaultConfig();
     } else {
        // Delete existing records in preparation for new server data
        smartStore.clearSoup("Account");
        smartStore.clearSoup("Contact");
     }
  8. Dans la méthode onFetchContactsClick(View v), videz la soupe Contact pour éviter de créer des enregistrements en double :
    smartStore.clearSoup("Contact");
    objectType = "Contact";
  9. Dans la méthode onFetchAccountsClick(View v), videz la soupe Account pour éviter de créer des enregistrements en double :
    smartStore.clearSoup("Account");
    objectType = "Account";
  10. Dans la méthode client.sendAsync(), appelez upsert() dans la boucle for qui insère la réponse JSON dans l’objet listAdapter :
    for (int i = 0; i < records.length(); i++) {
         listAdapter.add(records.getJSONObject(i).getString("Name"));
        try {
             smartStore.upsert((objectType, records.getJSONObject(i));
         } catch (Exception e) {
             onError(e);
         }
    }
  11. Lancez l’application, puis vérifiez votre travail dans le menu Outils de développement.
    • Pour afficher le menu, tapez Commande + m (Mac) ou Ctrl + m (Windows).
    • Cliquez sur Inspecter SmartStore.
    • Pour voir la liste de vos soupes et le nombres d’enregistrements que chacune contient, cliquez sur Soupes.
  12. Remarque : si vous recevez le message « Requête : Aucune soupe trouvée », il y a vraisemblablement une erreur dans votre fichier userstore.json.

Vous avez maintenant créé et rempli deux soupes SmartStore, mais pour l’instant, elles n’ont pas encore d’utilité concrète. Dans un scénario réel, vous créeriez une interface de modification pour les listes Account et Contact, puis vous inséreriez les modifications du client dans SmartStore. Au moment où l’appareil du client aurait retrouvé du réseau, vous pourriez fusionner les changements vers le serveur avec Mobile Sync.

Utilisation de SmartStore dans des applications hybrides

Enregistrement de soupes avec un fichier de configuration

Dans les applications hybrides, le kit de développement mobile charge automatiquement les fichiers de configuration de SmartStore. C’est vous qui devez placer les fichiers de configuration au bon emplacement, comme suit :

  1. Copiez le fichier de configuration dans le dossier www/ à la racine de votre projet hybride (par exemple, MyProject/www/).
  2. Dans une fenêtre de terminal ou une invite de commande Windows, utilisez cd pour atteindre le dossier de votre projet (par exemple, MyProject/).
  3. Exécutez cordova prepare

Peupler une soupe

Pour obtenir des enregistrements Salesforce, les applications hybrides utilisent la fonction standard force.query() de la bibliothèque JavaScript. Vous utiliserez des fonctions de rappel de réussite pour faire un upsert de données du jeu d’enregistrements vers la soupe.

force.query("SELECT Name,Id FROM Contact", 
    onSuccessSfdcContacts, onErrorSfdc); 
var sfSmartstore = function() {
    return cordova.require("com.salesforce.plugin.smartstore");};
function onSuccessSfdcContacts(response) {
    logToConsole()("onSuccessSfdcContacts: received " + 
        response.totalSize + “ contacts");
    var entries = [];
    response.records.forEach(function(contact, i) {
           entries.push(contact);
    });
    if (entries.length > 0) {
        sfSmartstore().upsertSoupEntries(CONTACTS_SOUP_NAME,
            entries,
            function(items) {
                var statusTxt = "upserted: " + items.length + 
                    " contacts";
                logToConsole()(statusTxt);
            }, 
         onErrorUpsert);
    }
 }
function onErrorSfdc(param) {
    logToConsole()("onErrorSfdc: " + param);
 }
function onErrorUpsert(param) {
    logToConsole()("onErrorUpsert: " + param);
 }

Lancement d’une requête sur les données de la soupe avec Smart SQL

Dans les applications hybrides, on crée des objets de spécification de requête en appelant des fonctions sur l’objet SmartStore du plug-in com.salesforce.plugin.smartstore. Par exemple, la fonction buildSmartQuerySpec() exécute une requête Smart SQL :

smartstore.buildSmartQuerySpec(smartSql, [pageSize])

smartSql est la requête devant être exécutée. Cette fonction offre davantage de flexibilité que les autres fonctions de fabrique servant aux requêtes, car vous fournissez votre propre instruction SELECT. Le paramètre pageSize est facultatif et défini sur 10 par défaut.

Le code suivant émet une requête qui appelle la fonction SQL COUNT sur une soupe appelée « employés ».

var querySpec = 
    navigator.smartstore.buildSmartQuerySpec(
        "select count(*) from {employees}", 1);
navigator.smartstore.runSmartQuery(querySpec, function(cursor) { 
    // result should be [[ n ]] if there are n employees
 });

Gestion d'une soupe

Chaque fonction de gestion de soupe dans JavaScript comporte deux fonctions de rappel : un rappel de réussite, qui renvoie les données demandées, et un rappel d'erreur. Les rappels de réussite varient selon les fonctions de gestion de la soupe qui les utilisent. Les rappels d'erreur prennent un argument simple, qui contient une chaîne de description de l'erreur. Vous pouvez par exemple définir une fonction de rappel d'erreur de la manière suivante :

function(e) { alert(“ERROR:“ + e);}

Pour appeler une fonction de gestion de soupe dans JavaScript, invoquez d’abord le plug-in Cordova afin d’initialiser l’objet SmartStore. Vous devez ensuite utiliser l’objet SmartStore pour appeler la fonction de gestion de soupe. L'exemple suivant définit séparément des fonctions de rappel nommées, mais vous pouvez également les définir en ligne et de manière anonyme.

var sfSmartstore = function() {
    return cordova.require("com.salesforce.plugin.smartstore");};
function onSuccessRemoveSoup(param) {
    logToConsole()("onSuccessRemoveSoup: " + param);
    $("#div_soup_status_line").html("Soup removed: " 
        + SAMPLE_SOUP_NAME);
 }
function onErrorRemoveSoup(param) {
    logToConsole()("onErrorRemoveSoup: " + param);
    $("#div_soup_status_line").html("removeSoup ERROR");
 }
sfSmartstore().removeSoup(SAMPLE_SOUP_NAME,
     onSuccessRemoveSoup, 
     onErrorRemoveSoup);

Utilisation de SmartStore dans les applications React Native

Les applications React Native ont beaucoup de points communs avec les applications hybrides. Généralement, les fonctionnalités SmartStore des deux plates-formes partagent des signatures identiques. Cependant, il y a plusieurs différences significatives.

  • Les applications React Native utilisent du code JavaScript ES2015. Si vous pouvez utiliser la même syntaxe JavaScript que dans les applications hybrides, vous pouvez également tirer profit des nouvelles conventions de code rationalisées.
  • En plus de JavaScript, les applications React Native prennent également en charge TypeScript pour la saisie statique. Vous pouvez choisir d’utiliser ou non TypeScript, et si vous souhaitez y avoir peu ou bien beaucoup recours.
  • Dans React Native, SmartStore n’utilise pas backbone.js.
  • Vous ne pouvez pas utiliser de bibliothèques hybrides Cordoba ni de plug-ins dans React Native. À la place, vous devez importer des modules SmartStore React Native.

Pour utiliser l’API SmartStore, il vous faut importer le module smartstore. Pour utiliser l’API Salesforce (surtout pour effectuer des requêtes afin de récupérer des enregistrements Salesforce), il faudra importer le module net. Il est possible d’importer les deux modules d’un seul coup :

import {net, smartstore} from 'react-native-force';

Enregistrement d’une soupe

Avec React Native, vous utilisez du code JavaScript au lieu de fichiers de configuration pour configurer les soupes SmartStore. Par exemple :

smartstore.registerSoup(false,
    "contacts", 
    [ {path:"Id", type:"string"}, 
    {path:"FirstName", type:"full_text"}, 
    {path:"LastName", type:"full_text"},    
    {path:"__local__", type:"string"} ],
    () => syncDown()
 );

Peupler une soupe

Pour remplir votre soupe avec des données Salesforce, commencez par demander des enregistrements grâce à l’API Salesforce standard. Le module net dispose d’un ensemble de fonctions wrapper qui simplifient les appels réseau. Vous leur passez une chaîne de requête et des fonctions de rappels de réussite et d’erreur. Dans la fonction de rappel de réussite, utilisez le module smartstore pour insérer les enregistrements obtenus en réponse à la requête dans votre soupe. (Si cette stratégie vous rappelle quelque chose, vous avez sans doute lu la section sur les applications hybrides !)

net.query("SELECT Name,Id FROM Contact", 
        onSuccessSfdcContacts, onErrorSfdc);

Voici un exemple de fonction de rappel de réussite.

function onSuccessSfdcContacts(response) {
    logToConsole()("onSuccessSfdcContacts: received " + 
        response.totalSize + “ contacts");
    var entries = [];
    $.each(response.records, function(i, contact) {
           entries.push(contact);
           logToConsole()("name: " + contact.Name);
    });
    if (entries.length > 0) {
        smartstore().upsertSoupEntries(CONTACTS_SOUP_NAME,
            entries,
            function(items) {
                var statusTxt = "upserted: " + items.length + 
                    " contacts";
                logToConsole()(statusTxt);
            }, 
            onErrorUpsert);
    }
 }

Lancement d’une requête sur les données de la soupe avec Smart SQL

Dans React Native, on crée des objets de spécification de requête en appelant des fonctions du module smartstore. Par exemple, la fonction buildSmartQuerySpec() construit un objet de requête Smart SQL :

buildSmartQuerySpec(smartSql, [pageSize])

Dans cette fonction, smartSql est la requête à exécuter. Cette fonction offre davantage de flexibilité que les autres fonctions de fabrique servant aux requêtes, car vous fournissez votre propre instruction SELECT. Le paramètre pageSize est facultatif et défini sur 10 par défaut.

Une fois l’objet de requête intelligente construit, vous le passez à la fonction runSmartQuery(), en donnant une fonction de rappel de réussite pour traiter la réponse. L’exemple de code suivant construit et exécute une requête qui appelle la fonction SQL COUNT.

var querySpec = 
    smartstore.buildSmartQuerySpec(
        "select count(*) from {employees}", 1);
// Note that the first parameter--a storeConfig object, or a Boolean indicating whether to use 
// the default global store or the default user store--is required in React Native apps
// but is optional in hybrid apps
smartstore.runSmartQuery(false, querySpec, function(cursor) { 
    // result should be [[ n ]] if there are n employees
 });

Utilisation des fonctions de gestion SmartStore

Les fonctions de gestion des soupes fonctionnent sur le même modèle que d’autres fonctions React Native. Vous définissez des fonctions de rappel de réussite et d’erreur, et vous appelez la fonction sur le module smartstore. Le nombre de paramètres passés à la fonction de rappel de réussite peut varier selon la fonction. Les fonctions de rappel d’erreur prennent toujours uniquement une chaîne de caractères décrivant l’erreur.

Ressources

Formez-vous gratuitement !
Créez un compte pour continuer.
Qu’est-ce que vous y gagnez ?
  • Obtenez des recommandations personnalisées pour vos objectifs de carrière
  • Mettez en pratique vos compétences grâce à des défis pratiques et à des questionnaires
  • Suivez et partagez vos progrès avec des employeurs
  • Découvrez des opportunités de mentorat et de carrière