Depuis Windows 8 Preview, nous avons accès à une base de données déployable et interne, facile d’accès directement dans votre package WinRT.

On aurait pu s’attendre à voir débarquer SQL Server Compact, mais c’est bien SQLite qui sera supporté et accessible dans Windows 8.

Nous allons voir ici comment installer et travailler avec ce petit moteur de base de données extrêmement connu dans le monde du web notamment.

Installation

Cette première partie d’installation est inspirée d’un article écrit par Tim Heuer, que vous pouvez retrouver sur son blog, in english in the text Sourire

L’installation de SQLite se fait directement depuis le menu TOOLS de Visual Studio et le sous-menu Extensions And Updates.

Par ce biais, vous aurez accès plus tard directement aux mises à jour de SQLite, sans avoir à vous en préoccuper. Deuxième chose, ce package est capable de correctement cibler votre configuration, que ce soit x86, x64 ou ARM.

Tools

Faites une recherche sur SQLite, vous devriez trouver facilement l’extension, qui s’installe via VSIX :

ExtensionsAndUpdates VSIX Installer VSIX Installer 2

Il ne reste plus qu’à :

  • Créer un projet de type Windows Store (XAML C# dans mon cas)
  • Référencer l’assembly SQLite
  • Référencer le C++ runtime. (Obligatoire si la machine cible ne le possède pas, trés rare, et qui potentiellement vous ferait échouer la validation de votre apps)

 

AddReference

Avant d’aller plus loin, si vous lancez la compilation de votre projet, vous risquez fortement d’avoir deux erreurs, pour le moins explicite:

ErrorBuildOnAnyCpu

Autant SQLite va savoir déployer la bonne dll suivant votre configuration, autant il vous faudra quand même avoir en target la bonne version (x86, x64 ou ARM)

Exit donc la configuration si pratique ANY CPU. Dommage …

Où en sommes nous ?

Nous avons installé SQLite, tout du moins le moteur et la runtime, compatible avec WinRT.

Il nous faut maintenant un Framework d’accès à SQLite. Il en existe plusieurs et j’ai choisi pour l’instant d’utiliser un projet Github, accessible via NuGet : sqlite-net.

(Je surveille de prés aussi le projet Sytem.Data.SQlite for WinRT. Il semble en bonne voie, je vous en reparle plus tard)

L’installation de sqlite-net est simple, elle vous rajoute 2 classes SQLite.cs, et SQLiteAsync.cs

N’hésitez pas d’ailleurs à y jeter un coup d’œil, c’est une mine d’informations.

addSQLiteNetReference sqliteclasses

A partir de là, votre environnement de travail est prêt et vous pouvez commencer la partie la plus intéressante : votre code Sourire

Connexion

Il faut savoir qu’ouvrir une connexion à SQLite crée un lien avec votre base de données locale mais aussi, crée la dite base de données si celle ci n’existe pas !

Pour créer une base de données SQLite, il vous faut cependant bien “placer” le fichier sqlite au bon endroit, soit le Windows Local Folder du package.

Voici un code minimaliste d’ouvertur de connexion (et donc de création de la base locale)

// Open a new Connection to SQLite.
using (var connection = new SQLite.SQLiteConnection(dbPath))
{}

 

Note : J’ai eu quelques soucis avec cette méthode, notamment si vous avez un caractère unicode dans le chemin d’accès de votre package.

Par exemple, mon compte utilisateur contenant un accent, “Sébastien”, cette méthode d’ouverture ne fonctionne pas !

Je vous conseille donc de passer par la surcharge du constructeur, qui elle, fonctionne Sourire

// Open a new Connection to SQLite.
using (var connection = new SQLite.SQLiteConnection(dbPath, SQLite.SQLiteOpenFlags.Create | SQLite.SQLiteOpenFlags.ReadWrite))
{}

 

A partir de là, votre base de données est créée. Certes elle est vide pour le moment Sourire

Outil d’administration

Pour ouvrir une base de données sqlite et l’administrer, il existe une multitude de produits. Je vous conseille SQLite Spy qui est loin d’être le plus complet, mais qui est celui qui semble le plus léger et surtout qui fonctionne a peu prés correctement avec la dernière version de SQLite (si vous avez mieux, je suis preneur Sourire)

 

image

Notre base de données se trouve dans le répertoire où sont stockées les packages Windows 8. (AppData / Local / Packages / ID Package / LocalState)

Dans mon exemple, il se trouve ici :

image

Travailler avec des tables SQLite

Pour faire simple dans cette première présentation, nous allons via SQLite Spy, créer une table Client et tenter de la requêter depuis notre application WinRT.

image

Note : Nous verrons plus tard que sqlite-net contient des outils de mapping permettant de directement créer une table à partir d’une entité. Mais pour le moment, continuons avec les bases…

Requête de sélection non paramétrée

Une fois la connexion ouverte, il suffit de :

  • Construire une requête
  • Préparer la commande (qui renvoie un IntPtr que nous appelerons SQLite3Statement)
  • Parcourir l’ensemble des lignes retournées
  • Récupérer les valeurs
  • Finaliser la commande
List<Client> lstClients = new List<Client>();

// Open a new Connection to SQLite.
using (var connection = new SQLite.SQLiteConnection(dbPath, SQLite.SQLiteOpenFlags.Create | SQLite.SQLiteOpenFlags.ReadWrite))
{

    const string querySelect = "Select * from Client";

    Sqlite3Statement stmt = Sqlite3Statement.Zero;
    try
    {
        // Prepare command
        stmt = SQLite3.Prepare2(connection.Handle, querySelect);

        // While row is available
        while (SQLite3.Step(stmt) == SQLite3.Result.Row)
        {
            Client client = new Client();

            // Get values
            client.ClientId = SQLite3.ColumnInt(stmt, 0);
            client.FirstName = SQLite3.ColumnString(stmt, 1);
            client.LastName = SQLite3.ColumnString(stmt, 2);
            client.CreationDate = DateTime.Parse(SQLite3.ColumnString(stmt, 3));
            client.Age = SQLite3.ColumnInt(stmt, 4);

            lstClients.Add(client);

        }
    }
    catch (SQLiteException ex)
    {
        Debug.WriteLine(ex.Message);
    }
    finally
    {
        // Finalize statement
        SQLite3.Finalize(stmt);
    }
}

 

 

Requête de sélection non paramétrée

Le passage de paramètre est relativement classique avec

D’une part la construction de la requête prenant un paramètre, représenté par un point d’interrogation :

Select * from Client where LastName = ?

 

D’autre part un mécanisme de Bind de paramètre coté code (le paramètre étant repéré via son index, attention à ce détail)

Attention : Index de base 1 !!!!

// Bind parameter
 SQLite3.BindText(stmt, 1, lastName, -1, new IntPtr(-1));
 SQLite3.BindInt(stmt, 2, 12);
 SQLite3.BindDouble(stmt, 3, (double)12);
 SQLite3.BindNull(stmt, 4);

 

sqlite-net apporte une méthode globable, plus simple à utiliser et qui prend en compte tous les types de données classiques:

SQLiteCommand.BindParameter(stmt, 1, lastName, false);

 

Le code de récupération des clients par le nom devient du coup :

List<Client> lstClients = new List<Client>();

// Open a new Connection to SQLite.
using (var connection = new SQLite.SQLiteConnection(dbPath, SQLite.SQLiteOpenFlags.Create | SQLite.SQLiteOpenFlags.ReadWrite))
{
    const string querySelect = "Select * from Client where LastName = ?";

    Sqlite3Statement stmt = Sqlite3Statement.Zero;
    try
    {
        // Prepare command
        stmt = SQLite3.Prepare2(connection.Handle, querySelect);

        // Bind parameter
        SQLiteCommand.BindParameter(stmt, 1, lastName, connection.StoreDateTimeAsTicks);

    
        // While row is available
        while (SQLite3.Step(stmt) == SQLite3.Result.Row)
        {
            Client client = new Client();

            // Get values
            client.ClientId = SQLite3.ColumnInt(stmt, 0);
            client.FirstName = SQLite3.ColumnString(stmt, 1);
            client.LastName = SQLite3.ColumnString(stmt, 2);
            string date = SQLite3.ColumnString(stmt, 3);
            client.CreationDate = String.IsNullOrEmpty(date) ? (DateTime?)null : DateTime.Parse(date);
            client.Age = SQLite3.ColumnInt(stmt, 4);

            lstClients.Add(client);
        }
    }
    catch (SQLiteException ex)
    {
        Debug.WriteLine(ex.Message);
    }
    finally
    {
        // Finalize statement
        SQLite3.Finalize(stmt);
    }
}

 

Dans une prochaine partie, nous verrons plus longuement les particularités de SQLite dans WinRT, un peu de mapping OR et quelques astuces relatives aux performances Sourire

Happy coding avec SQLite et WinRT !