Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

UWP/.UAP : Gérer des données avec SQLite

Dès qu’une application mérite ce nom et dépasse le stade de démo elle a généralement besoin de gérer des données. UWP est une plateforme jeune et les outils et librairies tiers ne sont pas tous encore à niveau. SQLite a bonne réputation mais c’est le produit le plus mal documenté du monde… Comment s’en servir ?

Pourquoi SQLite ?

D’abord SQLite est une base de données simple possédant un petit moteur embarqué sans installation qui sied parfaitement à une majorité de développements. Toute application n’a pas besoin d’un serveur dédié avec un SQL Server dernier cri et des téraoctets de disponibles. Même en entreprise cela se rencontre fréquemment. Par habitude on préfère toujours tout centraliser sur un serveur parce que les machines faisant tourner ces logiciels sont des PC. Mais ce temps est révolu, smartphones et tablettes font partie du décor. Alors on peut soit utiliser des bases dans le Cloud tel Azure, ce qui est une excellente solution, soit laisser chaque utilisateur gérer ses données qui seront simplement sauvegardées régulièrement sur un serveur. Et s’il s’agit d’applications personnelles la centralisation n’a plus aucun sens, le partage et la sauvegarde oui, mais cela se règle autrement qu’en ADO.NET avec un SQL Server derrière (Google Drive, OneDrive, DropBox…).

Ensuite SQLite est cross-plateforme. C’est aujourd’hui essentiel. S’il faut changer le code de gestion des données pour chaque cible visée le cout est trop important.

Enfin SQLite a très bonne réputation et est mise à jour régulièrement pour toutes les cibles. C’est un produit vivant et c’est essentiel aussi.

On terminera par le fait qu’elle est gratuite et simple à utiliser ce qui ne gâche rien.

Son seul point noir la documentation. Le pire étant que bien entendu le code original même un peu documenté n’est pas utilisable tel quel et qu’il faut y ajouter des librairies supplémentaires qui elles-mêmes sont encore moins bien documentées… Mais avec un peu d’acharnement et beaucoup d’essais on finit par trouver ce qui marche !

Installer l’extension UWP

Il faut d’abord ce procurer l’extension UWP, le moteur écrit en mode portable. Heureusement l’équipe de SQLite a été réactive et on trouve depuis peu un setup VSIX en version finale sur le site SQLite.org, page des téléchargements :

image

C’est celui-là que vous devez prendre. Ou plus récent bien entendu si c’est le cas quand vous lirez cet article.

une fois téléchargé, exécutez le setup. VS 2015 disposera désormais de l’extension UWP. Nous verrons comment l’utiliser plus loin.

C’est tout pour les préparatifs. Maintenant c’est dans chaque projet qui utilisera SQLite que le reste aura lieu.

Utiliser SQLite

Ne reste plus qu’à utilise SQLite dans un véritable projet. C’est ce que nous allons faire en créant un projet UWP “blank”.

Une fois celui-ci créé, il faut ajouter un paquet Nuget. Mais pas n’importe lequel ! C’est un souk innommable dans les paquets SQLite, une vraie foire d’empoigne avec même des noms de paquets dupliqués  … Et un seul fonctionnera. Saurez-vous le trouver ? Non, je rigole, je me suis assez enquiquiner je vais vous livrer la solution :

image

C’est celui-là. SQLite.Net-PCL des trois auteurs dont les noms sont inscrits à droite. Tim Heuer est bien connu des fans de feu Silverlight, gage d’une librairie bien écrite.

Cliquez sur Install et laisser Nuget faire son travail.

Maintenant c’est là que la fameuse extension UWP entre en scène. Toujours dans les références du projet cette fois-ci n’appelez pas le gestionnaire de paquets Nuget mais bien l’ajout de référence.

Dans la section (à gauche) Universal Windows, sélectionnez “Extensions”. C’est ici que se trouve les extensions UWP qui permettent par exemple d’atteindre des fonctions spécifiques à telle ou telle autre famille de machines tout en restant portable. Dans la liste qui s’affiche au centre vous devez alors cocher l’extension “SQLite for Universal App Platform”.

Mais ce n’est pas tout. En tout cas au moment où j’écris ces lignes il y a un avertissement du compilateur si on n’ajoute pas aussi l’extenstion “Visual C++ 2015 Runtime for Universal Windows …”. Peut-on laisser passer le warning sans conséquence ? Dans le doute ajoutez l’extension :

image

Nous voici paré pour notre test !

Ca parait si simple quand je relis ces quelques explications… Si vous saviez comment il faut galérer pour trouver la combinaison gagnante !

Ne reste plus qu’à écrire un peu de code qui va nous prouver que tout marche.

Je vais tout coder dans le code-behind de MainPage car il n’y aura aucune fioriture. C’est le code brut de fonderie pour utiliser SQLite qui compte ici. D’abord créons une classe qui sera persistée dans SQLite :

 public class Message
    {
        public string Title { get; set; }
        public DateTime Stamp { get; set; }
    }

Aucune astuce particulière, une classe vraiment de base. Je n’utilise pas ici certaines possibilités de SQLite comme les clés primaires, index etc. Nous verrons cela plus tard.

Maintenant il faut ouvrir une base de données dans l’espace privé de l’application, créer la table si elle n’existe pas, la remplir un peu et tenter de retrouver les données. Tout cela sera codé “sauvagement” dans le constructeur de MainPage derrière le InitializeComponents() :

public MainPage()
        {
            this.InitializeComponent();

            var path = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "db.sqlite");

            using (SQLite.Net.SQLiteConnection conn = 
new SQLite.Net.SQLiteConnection(new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT(), path)) { conn.CreateTable<Message>(); conn.DeleteAll<Message>(); for (var i = 0; i < 5; i++) { var m = new Message {Title = "Titre n° " + i, Stamp = DateTime.Now}; conn.Insert(m); Task.Delay(500).Wait(); } var query = from m in conn.Table<Message>() orderby m.Stamp descending select m; var s = query.Aggregate("", (current, message) => current +
(message.Stamp + " " + message.Title + Environment.NewLine)); new MessageDialog(s).ShowAsync(); }

La première étape consiste à créer le chemin d’accès la base de données et lui donner un nom. Le résultat est stocké dans la variable “path”.

Ensuite on ouvre une connexion dans un bloc “using” parce que c’est une bonne pratique et qu’on s’assure que le Dispose sera effectué dans tous les cas.

Cette connexion est créée en mode “WinRT”.

Ensuite le code tente de créer la table si elle n’existe pas (sans danger si elle existe). La méthode CreateTable utilise le type de la classe qui sera persistée. Il existe des moyens de personnaliser les noms de table, de champs, etc. Pour le moment je me concentre sur l’efficace.

Derrière la création de la table on voir un DeleteAll, cela ne sert que dans ma démo pour vider la table à chaque run afin de n’avoir toujours que les 5 enregistrements de démo.

Enregistrements qui sont créés ensuite dans une boucle. Le titre du message est numéroté, le stamp utilise l’horloge classique. C’est par la méthode Insert de la connexion que les enregistrements sont créés.

J’ai ajouté une attente de 500 ms pour que le stamp ne soit pas le même dans chaque enregistrement sinon ça va très vite…

Nous avons créé une base de données SQLite, nous avons créé une table Message, nous avons créé des enregistrements… Ne reste plus qu’à se prouver que tout cela peut être récupérer dans une requête LINQ !

C’est le but de la variable “query” qui extrait tous les enregistrements de la table en les classant par ordre décroissant de leur stamp.

Comme j’ai dit qu’il n’y aurai pas d’UI mais qu’il faut bien afficher le résultat pour le vérifier je construit par concaténation une chaîne qui contient tous les records qui viennent d’être lus par la requête LINQ. Et j’affiche cette chaîne en utilisant un MessageDialog de façon très brutale là aussi (notamment je n’attends pas par await, je ne lis pas le résultat, etc, c’est vraiment du sauvage).

Et quand on exécute cette merveilleuse application voilà ce qu’on obtient :

image

Fascinant ! Aurait ajouter ce regretté M. Spock… les cinq messages sont bien listés dans l’ordre décroissant des stamps, donc dans l’ordre décroissant des numéros de titre aussi par le fait même.

Plus ?

Oui bien sûr on peut faire plus. Même beaucoup plus. Mais là on dispose déjà du minimum vital. Créer une base, une table, la remplir et retrouver les données. C’est peu mais c’est énorme !

D’autant que normalement, juste en changeant la cible dans VS et en choisissant un Windows Phone 10 5” notre code doit fonctionner sans rien toucher… On essaye ?

image

 

C’est bluffant UWP quand même ? non ? Le même code, rigoureusement le même, le même exécutable, et voici une application pour PC qui tourne directement sur un smartphone ou une Xbox…

Encore Plus ?

Maintenant que vous avez vu cela vous avez envie de développer plein de trucs, c’est trop fun. On retrouve le plaisir de Silverlight. L’envie de faire des choses. Ca faisant un moment que plus rien de neuf ne donnait cette envie chez Microsoft il faut avouer. Le cauchemar est terminé !

Pour aller plus loin il faudrait mieux connaitre les possibilités de SQLite, voir s’il est possible de gérer automatiquement des relations entre les tables, etc; Ca serait bien hein ?

Conclusion

A chaque jour suffit sa peine !

Demain je vous parlerai des SQLite extensions qui gèrent les relations entre tables et un peu plus des possibilités de base de SQLite lui-même. Gérer des données est tellement important pour la majorité des applications que cela mérite bien deux articles !

Stay Tuned !

blog comments powered by Disqus