Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zéro > Les tutoriels > Non-Officiels > Programmation > C# / .NET > Utilisez les bases de données dans vos programmes C# > Lecture du tutoriel

Utilisez les bases de données dans vos programmes C#

Vous vous apprêtez à lire un tutoriel rédigé par un membre de ce site. Malgré tout le soin que ce membre a pu apporter au tutoriel, nous ne pouvons pas garantir que les informations contenues sur cette page sont exactes à 100%. Merci de garder cela en tête lorsque vous lirez cette page ;o)
Avatar
Auteur : Artefact2
Visualisations : 2 176

Plus d'informations Plus d'informations
Salut !

Les bases de données sont des moyens très puissants de gérer des flots importants de données.

Nous allons donc nous y intéresser. Comment les différents SGBD sont-ils implémentés à l'aide du .NET Framework ? Comment s'en sert-on ?

Pour expliquer tout ça avec un exemple pratique, nous utiliserons l'API SQLite, qui vous permettra d'exploiter simplement et facilement une base de données en moins de 10 minutes.
Sommaire du tutoriel :
Icône du chapitre

Présentation d'ADO.NET

ADO.NET regroupe l'ensemble des classes permettant d'accéder aux bases de données, ainsi que celles permettant de rapatrier et de traiter les données.

Il est inclus dans le .NET Framework, son fonctionnement est donc similaire pour tous les langages .NET (C# et VB.NET principalement).

On peut utiliser les bases de données de deux façons avec ADO.NET. Le mode connecté et le mode déconnecté.

Mode connecté



Dans ce mode, l'application reçoit les données progressivement, en fonction de ses besoins. Elle est connectée en permanence à la base et enregistre les modifications directement. Cette façon de procéder a l'avantage d'être facile à implémenter. Malheureusement, elle génère beaucoup d'accès à la base de données, et génère donc plus de trafic réseau. Concrètement, c'est un goulet d'étranglement pour les performances. ADO.NET était conçu à l'origine pour travailler en mode connecté.

Mode déconnecté



Ce mode a pour spécificité de ne pas rester connecté en permanence avec la base de données. L'application rapatrie une partie de la base de données puis la stocke en mémoire. Elle peut donc travailler sur ces données, éventuellement les modifier puis appliquer les changements en envoyant les nouvelles données vers la base. Cette méthode a aussi ses avantages et ses inconvénients : elle permet de minimiser les connexions à la base, et donc d'optimiser les performances ; en revanche cette méthode est beaucoup plus complexe à implémenter, et cela nécessite beaucoup de mémoire (l'application doit stocker une partie de la base en mémoire). De plus, si la base de données est modifiée une fois que le programme en a récupéré une partie, cela risque de poser des problèmes car l'application travaille alors sur des données obsolètes.

Les providers



Les providers, ou fournisseurs, sont une couche (concrètement, un groupe de classes) permettant d'accéder à un certain type de bases de données. Par exemple, il y a un provider pour les bases SQL Server, un provider Oracle, un provider ODBC, ... La bibliothèque SQLite que nous utiliserons par la suite n'est rien d'autre qu'un autre provider.

Chaque provider propose des classes différentes permettant d'accéder aux données. Pour éviter de devoir réécrire tout le code en cas de changement de base de données (donc de provider), il existe des classes génériques DbConnection , DbCommand fournies par le service DbProviderFactory . Leur utilisation ne sera pas détaillée ici, cependant vous pouvez vous renseigner par vous-même.

Installation de l'API SQLite

Passons maintenant à la pratique. Nous allons installer le provider SQLite. Il en existe plusieurs, mais nous allons choisir celui-ci : System.Data.SQLite. Rendez vous sur le site officiel, et installez la dernière version. Prenez bien soin de cocher la case correspondant à Visual Studio (ou VSExpress) lors de l'installation.

Ensuite, créez un nouveau projet (j'ai choisi un projet console par souci de simplicité). Il vous faut ajouter la référence à la bibliothèque. Dans l'explorateur de solution, faites un clic droit "References", puis choisissez "Ajouter une référence".

Image utilisateur


Une fenêtre s'ouvre et affiche les bibliothèques disponibles. Choisissez donc System.Data.SQLite.

Image utilisateur


Enfin, il faut indiquer à Visual Studio de copier la bibliothèque dans le répertoire de destination. C'est un fichier DLL d'environ 800 Kio. Cela permettra d'exécuter le programme sans forcément installer la bibliothèque. Déroulez les références, séléctionnez System.Data.SQLite, puis dans les propriétés, choisissez "True" pour "Copie locale".

Image utilisateur


Vous êtes donc prêts à utiliser ce provider. Un dernier détail tout de même, vous devez ajouter using System.Data.SQLite au début de votre fichier.

Voici donc notre code qui nous servira à apprendre à exploiter une base de données avec SQLite.

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SQLite;

namespace SimpleSQLite
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}


Maintenant, passons au vif du sujet !

Connexion, création d'une BDD

Établir une connexion



Avant de s'amuser avec les requêtes, nous devons nous connecter à une base. Avec SQLite, les bases de données sont stockées dans un seul fichier. Une connexion peut donc se résumer à définir un fichier seul. Il est possible de protéger l'accès avec un mot de passe.

Toute connexion s'écrit sous la forme d'une ConnectionString , c'est une chaîne de caractères qui a la syntaxe suivante :
Code : Autre
1
Param1 = Valeur1 ; Param2 = Valeur2 ;


Il est possible de s'amuser à faire cette chaîne à la main, il est cependant plus pratique de demander à une classe de le faire pour nous. L'objet SQLiteConnectionStringBuilder est conçu spécialement pour ça. Il va générer une chaîne qui sera nécessaire pour l'objet SQLiteConnection . On initialise l'objet SQLiteConnectionStringBuilder , puis on remplit les attributs qu'on a besoin (au minimum le fichier de la BDD à utiliser). On appelle ensuite la méthode ToString() , qui va générer la ConnectionString à partir des paramètres qu'on lui a donnés. Il suffit ensuite de créer un objet SQLiteConnection avec le constructeur (surchargé) qui prend en paramètre la chaîne de connection. Ensuite, la connection s'ouvre et se ferme avec les méthodes Open() et Close() de cet objet SQLiteConnection . Voici un exemple de code, qui explique mieux que des mots :

Code : C#
 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
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SQLite;

namespace SimpleSQLite
{
    class Program
    {
        static void Main(string[] args)
        {
            // Encapsulons tout cela dans un bloc try, au cas où une erreur se produirait.
            try
            {
                // On crée un nouvel objet SQLiteConnectionStringBuilder.
                SQLiteConnectionStringBuilder SQLCSB = new SQLiteConnectionStringBuilder();

                // On définit nos paramètres.
                SQLCSB.DataSource = "Base.db3"; // La base de données à utiliser
                SQLCSB.FailIfMissing = false; // Si la base n'existe pas, alors on la crée automatiquement
                SQLCSB.Password = "kze3sgDJ"; // Permet de définir le mot de passe à utiliser pour l'accès à la BDD

                // Obtenons cette ConnectionString !
                string ConnectionString = SQLCSB.ToString();

                // On crée une connexion, le constructeur prend en paramètre la ConnectionString.
                SQLiteConnection SQLC = new SQLiteConnection(ConnectionString);

                // On ouvre la connexion.
                SQLC.Open();

                // 
                // C'est ici qu'il faut faire des requêtes.
                //

                // On ferme la connexion.
                SQLC.Close();
            }
            catch (Exception Ex)
            {
                // On affiche l'erreur.
                Console.WriteLine(string.Format("*** Une exception a été lancée : {0} ***", Ex.Message));
            }
        }
    }
}


Tout ceci n'est pas compliqué à comprendre. On a ouvert une connexion à l'aide d'une ConnectionString générée par le SQLiteConnectionStringBuilder . Ca fait des noms de classe un peu longs, mais c'est comme ça ;)

Vous aurez remarqué qu'on se connecte à une base de données qui n'existe pas : nous ne l'avons pas préalablement créée. Cela n'est pas un problème : la classe SQLiteConnection va se charger de le faire pour nous. Si la base de données n'existe pas et que l'attribut FailIfMissing est à false , alors la base sera créée automatiquement, avec le mot de passe spécifié dans l'attribut Password s'il est spécifié.


Vous pouvez essayer de compiler et de lancer l'exemple ci-dessus. Si tout fonctionne, vous verrez une fenêtre de console apparaître, puis se fermer. C'est normal, on a initialisé une connexion, on la referme, puis le programme se termine. Nous n'avons pas mis de routine d'affichage.


ExecuteNonQuery() : pour les requêtes du type INSERT INTO , UPDATE , ALTER TABLE , DELETE FROM , ...



Pour l'instant, notre base est vide. Nous allons corriger cela en ajoutant des tables et des données. Comment ? En exécutant une requête SQL !

L'objet permettant d'exécuter des requêtes SQL sur des bases est SQLiteCommand . Il ne s'instancie pas directement, car il ne saurait pas dans quelle base effectuer les requêtes qu'on lui spécifie. Il faut donc demander à notre objet SQLiteConnection de nous fournir un objet SQLiteCommand grâce à la méthode CreateCommand() .

Une fois que nous avons notre objet SQLiteCommand , nous devons spécifier l'attribut CommandText qui n'est autre que la requête SQL à effectuer.

Toutes vos requêtes doivent elles aussi se terminer avec un point virgule (";").


Une fois que nous avons spécifié notre requête, on peut l'exécuter en appelant ExecuteNonQuery() . Cette méthode exécute la requête, puis renvoie un entier correspondant au nombre de rows (entrées) affectées par la requête. Elle permet donc d'exécuter des requêtes ne demandant pas de retour, par exemple les INSERT INTO , UPDATE , ALTER TABLE , DELETE FROM , etc. Voici un exemple de code, qui crée une table fictive "Employes" et qui insère des données à l'intérieur :

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Ce code est à placer entre SQLC.Open() et SQLC.Close().

// On demande à notre connection de nous créer un objet SQLiteCommand.
SQLiteCommand SQLCmd = SQLC.CreateCommand();

// Créons une table fictive.
SQLCmd.CommandText = "CREATE TABLE Employes (Nom VARCHAR(255), Prenom VARCHAR(255), Salaire INTEGER);";
SQLCmd.ExecuteNonQuery();

// Insérons des données fantaisistes...
SQLCmd.CommandText = "INSERT INTO Employes (Nom, Prenom, Salaire) VALUES ('John', 'Doe', 2100);";
Console.WriteLine(SQLCmd.ExecuteNonQuery()); // Cela nous permettra de voir combien d'entrées auront été affectées
SQLCmd.CommandText = "INSERT INTO Employes (Nom, Prenom, Salaire) VALUES ('Sam', 'Linston', 3600);";
Console.WriteLine(SQLCmd.ExecuteNonQuery()); // Idem.

// Pour éviter qu'elle se ferme instantanément.
Console.ReadKey();


Voici le résultat produit :

Image utilisateur


Ouf, nos requêtes ont bien affecté une entrée. Ce qui est parfaitement logique puisque ce sont des requêtes du type INSERT INTO !

Travail en mode connecté

La méthode ExecuteNonQuery() est pratique, mais elle n'est pas adaptée aux requêtes de type SELECT . En effet, on se fiche bien du nombre d'entrées affectées, on veut les données de la table ! Heureusement, il existe les méthodes ExecuteReader() et ExecuteScalar() qui vont nous faciliter la vie.

ExecuteScalar() : pour les requêtes SELECT ne renvoyant qu'une valeur



ExecuteScalar() est une méthode de l'objet SQLiteCommand . Lorsqu'on a rempli le champ CommandText et qu'on fait appel à cette méthode, l'objet va exécuter la requête et la première valeur de la première colonne que renvoie la requête sera renvoyée. Cela est donc parfaitement adapté aux requêtes du type SELECT COUNT() , SELECT SUM() , SELECT AVG() , ... qui ne renvoient qu'une seule valeur.

Voici un petit exemple pour illustrer l'utilisation de cette méthode :

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Ce code est à placer entre SQLC.Open() et SQLC.Close().

// On crée une SQLiteCommand
SQLiteCommand SQLCmd = SQLC.CreateCommand();

// On spécifie notre requête
SQLCmd.CommandText = "SELECT COUNT(*) FROM Employes;";

Console.WriteLine(string.Format("Nombre d'entrées dans la table Employes : {0}", SQLCmd.ExecuteScalar().ToString()));

// Pour pouvoir lire les résultats...
Console.ReadKey();


Et voici le résultat :

Image utilisateur


Cette méthode est donc pratique à utiliser car elle évite d'utiliser le mastodon SQLiteDataReader, que nous allons voir tout de suite, pour une seule valeur.

ExecuteReader() : pour les requêtes SELECT classiques



Lorsqu'on effectue des requêtes du type SELECT plus classiques, on a besoin d'accéder à plusieurs cellules. Or, ni ExecuteNonQuery() ni ExecuteScalar() ne permettent de faire ça. C'est là qu'on va utiliser la méthode ExecuteReader() de notre objet SQLiteCommand .

Cette méthode renvoie un objet SQLiteDataReader . Comme son nom l'indique, il sert à lire les données renvoyées par la requête. Comment s'en servir ? Tout simplement en utilisant sa méthode Read() . A chaque appel de cette méthode, l'objet lit une entrée renvoyée par la requête, puis renvoie true s'il reste encore des données à lire, false sinon. On accède ensuite aux données avec l'accesseur [] sur cet objet. Concrètement, si on a un objet SQLiteDataReader nommé SQLDR et qu'on a spécifié une requête de type SELECT , alors on peut accéder aux données en utilisant la notation SQLDR["NomDeLaColonne"] ou encore SQLDR[0] si on souhaite accéder à la première colonne (tout ceci après lui avoir demandé de lire une entrée avec Read() bien sûr).

Le fait que la méthode Read() renvoie true ou false est très pratique, ça permet de s'en servir dans une simple boucle while() . Dans l'exemple ci-dessous, nous affichons le contenu de notre table Employes. Remarquez comment on accède aux données : SQLDR["Nom"] , SQLDR["Prenom"] , ...

Code : C#
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Ce code est à placer entre SQLC.Open() et SQLC.Close().

// On demande à notre connection de nous créer un objet SQLiteCommand.
SQLiteCommand SQLCmd = SQLC.CreateCommand();

SQLCmd.CommandText = "SELECT Nom, Prenom, Salaire, ROWID FROM Employes";

// On affiche les en-têtes (facultatif, mais ça permet d'y voir plus clair)
Console.WriteLine("Nom\t\tPrénom\t\tSalaire\t\tROWID");
Console.WriteLine("-------------------------------------------------------");

// On crée un objet SQLiteDataReader
SQLiteDataReader SQLDReader = SQLCmd.ExecuteReader();

// La méthode Read() lit l'entrée actuelle puis renvoie true tant qu'il y a des entrées à lire.
while (SQLDReader.Read())
{
    // On affiche les données...
    Console.WriteLine(string.Format("{0}\t\t{1}\t\t{2}\t\t{3}", 
        SQLDReader["Nom"], SQLDReader["Prenom"], SQLDReader["Salaire"], SQLDReader["ROWID"]));
}

// Pour pouvoir lire les résultats...
Console.ReadKey();


Cet exemple fonctionne très bien, et produit le résultat suivant :

Image utilisateur


On voit bien ici qu'on travaille en mode connecté : la méthode Read() lit bien les données au fur et à mesure qu'on en a besoin, directement dans la base de données.


Remarquez la colonne ROWID , nous ne l'avons pas crée lors de la création de la table mais SQLite se charge de la créer automatiquement. C'est un entier 64 bits non signé, défini en tant que clé primaire et en auto incrément. Sa valeur maximale est donc de 9223372036854775807. Elle remplace avantageusement les colonnes "Id" habituelles avec les autres SGBD (MySQL par exemple). Plus d'informations sont disponibles sur cette page : http://www.sqlite.org/autoinc.html.

Récapitulatif

Voici un petit récapitulatif, pour vous aider à retenir l'essentiel.

Avant de commencer à programmer



Se connecter / déconnecter à la BDD



SQLiteCommand en mode connecté



Amusez-vous bien avec SQLite dans vos programmes ! Cela vous simplifiera grandement la vie.

Une partie sur le travail en mode déconnecté est en cours de rédaction.

Ce tutoriel touche à sa fin, j'espère que vous saurez faire bon usage de cette API qui est à la fois très simple et très puissante.
Retour en haut Retour en haut


Créé : le 09/08/2008 à 23:10:22
Modifié : le 22/08/2008 à 16:08:33
Avancement : 100%
Licence : Copie non autorisée

Changer de design | En savoir plus | Plan du site | Politique d'accessibilité | Règles | RSS tutoriels | RSS news
Édité par Simple IT SARL : Nous contacter | Notre blog | Revue de presse | Publicité

Y'a plus rien à lire, faut remonter maintenant !

Hébergement web - Correction de tutoriels - Créer un site
Vous souhaitez apparaître ici ? Contactez-nous.

Nombre de connectés 223 Zéros connectés | Requêtes SQL 8 requêtes | Temps de génération de la page : Total (SQL) 0.2436s (0.2324s)