ADO.NET en Mode Déconnecté avec DataGrid en C# et SQL Server : Guide Complet
Ce guide explore l'utilisation d'ADO.NET en mode déconnecté pour interagir avec une base de données SQL Server, en se concentrant sur le contrôle DataGrid en C#. Le mode déconnecté est une approche puissante pour gérer les données, permettant aux applications de travailler avec des copies locales de données sans maintenir une connexion constante à la base de données. Cela améliore la scalabilité et les performances, surtout dans les environnements distribués.
Objectifs et Concepts Clés
L'objectif principal est de démontrer comment exploiter une base de données en mode déconnecté en utilisant le contrôle DataGrid. Les classes ADO.NET fondamentales utilisées sont :
SqlConnection: Gère la connexion à la base de données.SqlDataAdapter: Agit comme un pont entre unDataSetet la base de données, permettant de remplir leDataSetet de mettre à jour la base de données.SqlCommand: Exécute des commandes SQL (SELECT, INSERT, UPDATE, DELETE) sur la base de données.DataSet: Une représentation en mémoire des données de la base de données, capable de contenir plusieurs tables et leurs relations.DataRow: Représente une ligne de données dans uneDataTableau sein d'unDataSet.
Scénario d'Application : Gestion des Enseignants
Nous allons illustrer ces concepts à travers la gestion d'une table "Enseignants" dans une base de données SQL Server 2000. L'application permettra de se connecter, consulter, ajouter, modifier et supprimer des enregistrements.
Interface Utilisateur et Menus
L'interface de l'application est structurée avec des menus pour les actions principales. Voici un exemple de structure de menus :
Connection Consultation Action
------------ -------------- ------------
Connecter Premier Select
Déconnecter Précédent Insert
Suivant Update
Dernier Delete
Ces éléments de menu correspondent à des gestionnaires d'événements Click qui exécutent les opérations décrites ci-dessous.
Implémentation du Mode Déconnecté avec DataGrid
Déclaration des Variables Globales
Pour gérer les opérations en mode déconnecté, plusieurs variables statiques sont déclarées. Elles seront accessibles par les différentes méthodes de l'application.
using System.Data;
using System.Data.SqlClient;
static SqlConnection MySqlConn;
static SqlCommand MySelectCmd, MyInsertCmd, MyUpdateCmd, MyDeleteCmd;
static SqlDataAdapter MySqlDataAdapter;
static DataSet MyDataSet;
static DataRow MyWorkRow;
static int NumEnreg, NbEnreg;
static string MyStrConn, MyStrSelect, MyStrInsert, MyStrUpdate, MyStrDelete;
Méthode de Connexion à la Base de Données (Connecter)
La méthode Connecter initialise la connexion à la base de données et configure les commandes SQL pour les opérations de sélection, insertion, mise à jour et suppression. Elle prépare également le SqlDataAdapter.
private void Connecter(object sender, System.EventArgs e)
{
MyStrConn = "Server = Localhost; Integrated Security = SSPI; Initial Catalog = SQLNotation";
MySqlConn = new SqlConnection(MyStrConn);
MySqlConn.Open();
MyStrSelect = "SELECT CodeEnseignant, Nom, Prenom, DateNaissance FROM Enseignants";
MySelectCmd = new SqlCommand(MyStrSelect, MySqlConn);
MyStrInsert = "INSERT INTO Enseignants " +
"(CodeEnseignant, Nom, Prenom, DateNaissance) " +
"Values (@CodeEnseignant, @Nom, @Prenom, @DateNaiss)";
MyInsertCmd = new SqlCommand(MyStrInsert, MySqlConn);
MyInsertCmd.Parameters.Add("@CodeEnseignant", SqlDbType.TinyInt, 0, "CodeEnseignant");
MyInsertCmd.Parameters.Add("@Nom", SqlDbType.VarChar, 25, "Nom");
MyInsertCmd.Parameters.Add("@Prenom", SqlDbType.VarChar, 15, "Prenom");
MyInsertCmd.Parameters.Add("@DateNaiss", SqlDbType.SmallDateTime, 0, "DateNaissance");
MyStrUpdate = "UPDATE Enseignants SET CodeEnseignant=@CodeEnseignant, " +
"Nom = @Nom, Prenom = @Prenom, DateNaissance = @DateNaiss " +
"Where CodeEnseignant = @CodeEns";
MyUpdateCmd = new SqlCommand(MyStrUpdate, MySqlConn);
MyUpdateCmd.Parameters.Add("@CodeEnseignant", SqlDbType.TinyInt, 0, "CodeEnseignant");
MyUpdateCmd.Parameters.Add("@Nom", SqlDbType.VarChar, 25, "Nom");
MyUpdateCmd.Parameters.Add("@Prenom", SqlDbType.VarChar, 15, "Prenom");
MyUpdateCmd.Parameters.Add("@DateNaiss", SqlDbType.SmallDateTime, 0, "DateNaissance");
SqlParameter WorkParam = MyUpdateCmd.Parameters.Add("@CodeEns", SqlDbType.TinyInt);
WorkParam.SourceColumn = "CodeEnseignant";
WorkParam.SourceVersion = DataRowVersion.Original; // Important pour la gestion de la concurrence optimiste
MyStrDelete = "DELETE Enseignants WHERE CodeEnseignant = @CodeEnseignant";
MyDeleteCmd = new SqlCommand(MyStrDelete, MySqlConn);
MyDeleteCmd.Parameters.Add("@CodeEnseignant", SqlDbType.TinyInt, 0, "CodeEnseignant");
MyDataSet = new DataSet();
MySqlDataAdapter = new SqlDataAdapter();
MySqlDataAdapter.SelectCommand = MySelectCmd;
MySqlDataAdapter.UpdateCommand = MyUpdateCmd;
MySqlDataAdapter.InsertCommand = MyInsertCmd;
MySqlDataAdapter.DeleteCommand = MyDeleteCmd;
}
Notez l'utilisation de paramètres dans les requêtes SQL pour prévenir les injections SQL et faciliter la gestion des types de données. Le paramètre @CodeEns avec DataRowVersion.Original est essentiel pour identifier la ligne à mettre à jour, même si sa clé primaire a été modifiée, et pour la gestion de la concurrence optimiste.
Sélection et Affichage des Enregistrements (SelectEnreg, AfficheEnreg)
Ces méthodes sont responsables du remplissage du DataSet et de l'affichage des données dans le contrôle DataGrid, ainsi que dans des champs de texte individuels pour la navigation.
private void SelectEnreg(object sender, System.EventArgs e)
{
MySqlDataAdapter.Fill(MyDataSet, "Enseignants");
NbEnreg = MyDataSet.Tables["Enseignants"].Rows.Count;
// DgEnseignant représente le contrôle DataGrid dans l'interface utilisateur.
DgEnseignant.SetDataBinding(MyDataSet, "Enseignants");
}
private void AfficheEnreg(int Num)
{
MyWorkRow = MyDataSet.Tables["Enseignants"].Rows[NumEnreg];
TxtCodeEns.Text = MyWorkRow["CodeEnseignant"].ToString();
TxtNom.Text = MyWorkRow["Nom"].ToString();
TxtPrenom.Text = MyWorkRow["Prenom"].ToString();
TxtDateNaiss.Text = MyWorkRow["DateNaissance"].ToString();
TxtNumNbEnreg.Text = (NumEnreg + 1).ToString() + "/ " + NbEnreg.ToString();
}
Navigation dans les Enregistrements
Ces méthodes permettent de parcourir les enregistrements chargés dans le DataSet.
private void PremierEnreg(object sender, System.EventArgs e)
{
NumEnreg = 0;
AfficheEnreg(NumEnreg);
}
private void PrecedentEnreg(object sender, System.EventArgs e)
{
if (NumEnreg > 0)
{
NumEnreg--;
AfficheEnreg(NumEnreg);
}
else
{
MessageBox.Show("Vous êtes sur le premier enregistrement.");
}
}
private void SuivantEnreg(object sender, System.EventArgs e)
{
if (NumEnreg < NbEnreg - 1) // L'opérateur "<-" a été corrigé en "<"
{
NumEnreg++;
AfficheEnreg(NumEnreg);
}
else
{
MessageBox.Show("Vous êtes sur le dernier enregistrement.");
// Ces lignes peuvent vider les champs après avoir atteint la fin
// ou préparer l'ajout d'un nouvel enregistrement.
TxtCodeEns.Clear();
TxtNom.Clear();
TxtPrenom.Clear();
TxtDateNaiss.Clear();
}
}
private void DernierEnreg(object sender, System.EventArgs e)
{
NumEnreg = NbEnreg - 1;
AfficheEnreg(NumEnreg);
}
Déconnexion de la Base de Données (Deconnecter)
Ferme la connexion à la base de données. En mode déconnecté, cette action n'est généralement effectuée qu'une fois les opérations de lecture et de mise à jour du SqlDataAdapter terminées.
private void Deconnecter(object sender, System.EventArgs e)
{
MySqlConn.Close();
}
Opérations CRUD : Insertion, Mise à Jour et Suppression
Ces méthodes gèrent les opérations de modification des données dans le DataSet, puis utilisent le SqlDataAdapter pour synchroniser ces changements avec la base de données.
private void InsertEnreg(object sender, System.EventArgs e)
{
// Crée une nouvelle ligne dans la table du DataSet
MyWorkRow = MyDataSet.Tables["Enseignants"].NewRow();
// Affecte les valeurs des champs de l'interface à la nouvelle ligne
MyWorkRow["CodeEnseignant"] = byte.Parse(TxtCodeEns.Text);
MyWorkRow["Nom"] = TxtNom.Text;
MyWorkRow["Prenom"] = TxtPrenom.Text;
MyWorkRow["DateNaissance"] = DateTime.Parse(TxtDateNaiss.Text);
// Ajoute la nouvelle ligne au DataSet
MyDataSet.Tables["Enseignants"].Rows.Add(MyWorkRow);
// Met à jour la base de données avec les modifications du DataSet
MySqlDataAdapter.Update(MyDataSet, "Enseignants");
NbEnreg++;
NumEnreg++; // Positionne l'index sur le nouvel enregistrement
TxtNumNbEnreg.Text = (NumEnreg + 1).ToString() + "/ " + NbEnreg.ToString();
}
private void UpdateEnreg(object sender, System.EventArgs e)
{
// Récupère la ligne courante du DataSet
MyWorkRow = MyDataSet.Tables["Enseignants"].Rows[NumEnreg];
// Met à jour les valeurs de la ligne avec celles des champs de l'interface
MyWorkRow["CodeEnseignant"] = byte.Parse(TxtCodeEns.Text);
MyWorkRow["Nom"] = TxtNom.Text;
MyWorkRow["Prenom"] = TxtPrenom.Text;
MyWorkRow["DateNaissance"] = DateTime.Parse(TxtDateNaiss.Text);
// Synchronise les modifications avec la base de données
MySqlDataAdapter.Update(MyDataSet, "Enseignants");
TxtNumNbEnreg.Text = (NumEnreg + 1).ToString() + "/ " + NbEnreg.ToString();
}
private void DeleteEnreg(object sender, System.EventArgs e)
{
// Marque la ligne courante pour suppression
MyDataSet.Tables["Enseignants"].Rows[NumEnreg].Delete();
// Synchronise la suppression avec la base de données
MySqlDataAdapter.Update(MyDataSet, "Enseignants");
NbEnreg--;
// Ajuste l'index de l'enregistrement courant après suppression
if (NumEnreg == NbEnreg)
{
NumEnreg = NbEnreg - 1;
}
// Affiche l'enregistrement restant
AfficheEnreg(NumEnreg);
}
Deuxième Scénario : Gestion Simplifiée avec Gestion des Erreurs
Un deuxième exemple d'interface propose une interaction simplifiée avec la base de données, en intégrant des mécanismes de gestion des erreurs pour une meilleure robustesse.
Structure des Menus Simplifiée
Cette interface se concentre sur la connexion, la consultation et la mise à jour globale de la base de données.
Connection Action
------------ ------------------
Connecter Consulter la base
Déconnecter Mettre à jour la base
Variables Globales pour le Deuxième Scénario
Les variables sont similaires au premier scénario, mais DataRow, NumEnreg et NbEnreg ne sont pas nécessaires si l'objectif n'est pas la navigation ligne par ligne.
static SqlConnection MySqlConn;
static SqlCommand MySelectCmd, MyInsertCmd, MyUpdateCmd, MyDeleteCmd;
static SqlDataAdapter MySqlDataAdapter;
static DataSet MyDataSet;
static string MyStrConn, MyStrSelect, MyStrInsert, MyStrUpdate, MyStrDelete;
Méthode de Connexion avec Gestion des Erreurs (Connecter)
Cette version de la méthode Connecter inclut un bloc try-catch pour capturer et afficher les erreurs potentielles lors de l'établissement de la connexion ou de la préparation des commandes SQL. Notez également le paramètre de mise à jour @OldCodeEns, une pratique recommandée pour clarifier l'originalité de la clé primaire lors de la mise à jour.
private void Connecter(object sender, System.EventArgs e)
{
try
{
MyStrConn = "Server = Localhost; Integrated Security = SSPI; Initial Catalog = SQLNotation";
MySqlConn = new SqlConnection(MyStrConn);
MySqlConn.Open();
MyStrSelect = "SELECT CodeEnseignant, Nom, Prenom, DateNaissance FROM Enseignants";
MySelectCmd = new SqlCommand(MyStrSelect, MySqlConn);
MyStrInsert = "INSERT INTO Enseignants " +
"(CodeEnseignant, Nom, Prenom, DateNaissance) " +
"Values (@CodeEnseignant, @Nom, @Prenom, @DateNaiss)";
MyInsertCmd = new SqlCommand(MyStrInsert, MySqlConn);
MyInsertCmd.Parameters.Add("@CodeEnseignant", SqlDbType.TinyInt, 0, "CodeEnseignant");
MyInsertCmd.Parameters.Add("@Nom", SqlDbType.VarChar, 25, "Nom");
MyInsertCmd.Parameters.Add("@Prenom", SqlDbType.VarChar, 15, "Prenom");
MyInsertCmd.Parameters.Add("@DateNaiss", SqlDbType.SmallDateTime, 0, "DateNaissance");
MyStrUpdate = "UPDATE Enseignants SET CodeEnseignant=@CodeEnseignant, " +
"Nom = @Nom, Prenom = @Prenom, DateNaissance=@DateNaiss " +
"Where CodeEnseignant = @OldCodeEns";
MyUpdateCmd = new SqlCommand(MyStrUpdate, MySqlConn);
MyUpdateCmd.Parameters.Add("@CodeEnseignant", SqlDbType.TinyInt, 0, "CodeEnseignant");
MyUpdateCmd.Parameters.Add("@Nom", SqlDbType.VarChar, 25, "Nom");
MyUpdateCmd.Parameters.Add("@Prenom", SqlDbType.VarChar, 15, "Prenom");
MyUpdateCmd.Parameters.Add("@DateNaiss", SqlDbType.SmallDateTime, 0, "DateNaissance");
SqlParameter WorkParam = MyUpdateCmd.Parameters.Add("@OldCodeEns", SqlDbType.TinyInt);
WorkParam.SourceColumn = "CodeEnseignant";
WorkParam.SourceVersion = DataRowVersion.Original;
MyStrDelete = "DELETE Enseignants WHERE CodeEnseignant = @CodeEnseignant";
MyDeleteCmd = new SqlCommand(MyStrDelete, MySqlConn);
MyDeleteCmd.Parameters.Add("@CodeEnseignant", SqlDbType.TinyInt, 0, "CodeEnseignant");
MyDataSet = new DataSet();
MySqlDataAdapter = new SqlDataAdapter();
MySqlDataAdapter.SelectCommand = MySelectCmd;
MySqlDataAdapter.UpdateCommand = MyUpdateCmd;
MySqlDataAdapter.InsertCommand = MyInsertCmd;
MySqlDataAdapter.DeleteCommand = MyDeleteCmd;
}
catch (Exception MyE)
{
MessageBox.Show(MyE.Message);
}
}
Consultation et Mise à Jour Globale
Ces méthodes simplifiées se concentrent sur le remplissage du DataGrid et la mise à jour de la base de données pour toutes les modifications en attente dans le DataSet.
private void Consulter(object sender, System.EventArgs e)
{
MySqlDataAdapter.Fill(MyDataSet, "Enseignants");
DgEnseignant.SetDataBinding(MyDataSet, "Enseignants");
}
private void Deconnecter(object sender, System.EventArgs e)
{
MySqlConn.Close();
}
private void MettreAjourLaBase(object sender, System.EventArgs e)
{
try
{
MySqlDataAdapter.Update(MyDataSet, "Enseignants");
}
catch (Exception MyE)
{
MessageBox.Show(MyE.Message);
}
}
FAQ - Questions Fréquentes sur ADO.NET en Mode Déconnecté
Qu'est-ce que le mode déconnecté ADO.NET et pourquoi l'utiliser ?
Le mode déconnecté ADO.NET permet aux applications de manipuler des données locales (stockées dans un
DataSet) sans maintenir une connexion constante à la base de données. Cela est bénéfique pour la scalabilité, la performance (réduction de la charge sur le serveur de base de données) et la résilience, car l'application peut continuer à fonctionner même en cas de perte temporaire de connectivité.Quel est le rôle du
SqlDataAdapterdans le mode déconnecté ?Le
SqlDataAdapterest l'élément central du mode déconnecté. Il agit comme un pont entre leDataSet(les données en mémoire de l'application) et la base de données. Il utilise les commandesSelectCommandpour remplir leDataSetet les commandesInsertCommand,UpdateCommand,DeleteCommandpour synchroniser les modifications duDataSetavec la base de données via la méthodeUpdate().Comment gérer les erreurs et la concurrence en mode déconnecté ?
La gestion des erreurs est cruciale, comme illustré par l'utilisation de blocs
try-catchautour des opérations critiques. Pour la concurrence, ADO.NET utilise les versions originales des données pour vérifier si une ligne a été modifiée par un autre utilisateur avant de tenter une mise à jour. C'est pourquoi l'attributDataRowVersion.Originalest spécifié pour certains paramètres des commandesUpdateCommandetDeleteCommand, permettant de comparer les valeurs actuelles en base avec les valeurs originales duDataSet.