Développer avec une architecture en Csharp

Apprenez à développer avec une architecture en C#

Landry Bogbé

Une architecture est un ensemble de règles établies permettant à un développeur de concevoir des applications selon une organisation particulière.

Commentez

- Titre : Développer avec une architecture en Csharp

- Auteur : Landry Bogbé

- Parution : 30 novembre 2014

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2014 landry161. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Préambule

- III. Présentation d'un modèle d'architecture

- IV. Explication

- IV-A. La couche interface

- IV-B. La couche métier

- IV-C. La couche d'accès aux données

- IV-D. La couche physique

- V. Miniprojet par la pratique

- VI. Base de données

- VI-A. Le script de création de la table

- VI-B. Le script de création des procédures stockées

- VI-B-I. L'insertion

- VI-B-II. La modification

- VI-B-III. La sélection

- VI-B-IV. La suppression

- VI-B-V. La vérification

- VII. Projet en Csharp

- VIII. Code

- VIII-A. La description (couche d'accès aux données)

- VIII-B. Les méthodes d'accès aux données

- IX. Couche métier

- X. Couche interface

- X-A. L'insertion et la vérification

- X-B. La sélection

- X-C. La modification

- X-D. La suppression

- XI. Remerciements

I - Introduction

Comme énoncé plus haut, le but de ce tutoriel est de nous permettre de faire une application basée sur une architecture. Je tenais à préciser que ce tutoriel n'est pas le premier du genre pour la simple et bonne raison qu'un auteur a déjà publié trois articles Partie 1, Partie 2 et Partie 3. Au moment de la rédaction, je n'ai nullement l'intention de critiquer ou déprécier son article, seulement le présent tutoriel aborde le même principe de développement, mais d'une autre manière.

II - Préambule

Ce qu'il faut retenir, c'est qu'une architecture est élaborée selon les besoins et aspirations de celui qui l'a écrite, j'ai eu à bosser avec un ami sur une architecture compliquée. Pourquoi ? Simplement parce qu'elle répondait à ses exigences. Dans les parties suivantes, nous expliquerons les principes de base d'une architecture, cependant vous devriez obligatoirement vous familiariser à certains mots et concepts tels que la Programmation Orientée, couche métier, couche physique, couche d'accès aux données et bien d'autres. Avant de vous lancer je vous conseille de faire un tour sur ces articles Programmation orientée objet, TSQL. Vous serez ensuite prêt pour vous lancer dans ce tutoriel.

III - Présentation d'un modèle d'architecture

La présentation consistera en l'énumération des grandes parties de notre architecture et comment elle fonctionne. Voici donc un schéma qui retrace son fonctionnement.

IV - Explication

Selon l'image ci-dessus, nous prenons connaissance de la couche métier, couche d'accès aux données, couche physique et la couche interface.

IV-A - La couche interface

Cette couche se matérialise par les interfaces utilisateur (les fenêtres, boutons, les zones de texte). Dans la couche interface, nous ne ferons qu'instancier les méthodes des objets de la couche métier.

IV-B - La couche métier

La couche métier contient des méthodes qui seront utilisées par les utilisateurs. Lorsqu'un utilisateur procède par exemple à une insertion ou une modification, ce sont ces méthodes créées dans la couche métier qui seront appelées. Elle permet de définir aussi les règles de validation de formulaire.

IV-C - La couche d'accès aux données

Cette couche se scinde en deux parties. Une première qui permet de décrire les entités de notre base de données (comme entité nous pourrons avoir des classes, des structs dont les propriétés devront être identiques à celles de vos tables au niveau de votre base de données) et une deuxième dans laquelle nous écrirons des méthodes qui sont relatives aux bases de données. Dans cette seconde couche, nous écrirons des fonctions qui porteront sur des opérations de base telles que l'insertion, la modification, la sélection et la suppression. L'écriture de ces méthodes dépendra du Système de Gestion de Base de Données. Étant donné que nous utiliserons le langage Csharp et une base de données SQL Server Express, nous utiliserons également des espaces de noms qui sont spécifiques à notre base de données. Pour une base de données SQL Server nous aurons System.Data, System.Data.SqlClient et MySql.Data, MySql.Data.MySqlClient pour une base de données MySQL et vice versa. Vos méthodes dépendront du SGBD que vous utiliserez. Cependant, sachez que les méthodes de la couche d'accès aux données sont créées en fonction des scripts que nous aurons écrits au niveau de notre base de données, la couche physique.

IV-D - La couche physique

Elle contient les scripts de création de notre base de données et les opérations du CRUD (Create Read Update and Delete) et d'autres requêtes selon les fonctionnalités de l'application ou les besoins des utilisateurs. De façon plus simple, la couche physique c'est notre Système de Gestion de Base de Données (SGBD).

V - Miniprojet par la pratique

Pour mieux appréhender le développement avec une architecture, je vous propose de concevoir une petite application qui nous permettra d'enregistrer des clients avec leurs contacts. La table client possédera les propriétés nom, prénom, téléphone et adresse.

À partir de ce modèle, nous créerons notre base de données sous SQL Server Express avec les scripts suivants :

- Insertion ;

- Modification ;

- Sélection ;

- Suppression ;

- Vérification avant insertion (cette procédure stockée permettra de vérifier les numéros des clients avant leur insertion).

VI - Base de données

Ouvrez Microsoft SQL Server et créez la base de données. Faites un clic droit sur Databases et cliquez sur New Database et nommez la base de données architecture.

VI-A - Le script de création de la table

Script de création de la table

CREATE TABLE client(
id int primary key identity(1,1),--La colonne étant auto-incrémentée
nom varchar(20),
prenom varchar(30),
tel varchar(15),
adresse varchar(50)
);

VI-B - Le script de création des procédures stockées

Nous allons donc créer nos procédures stockées, elles sont faites au niveau de notre SGBD, pour notre tutoriel, il s'agit de SQL Server Express.

VI-B-I - L'insertion

Insertclient

CREATE PROCEDURE InsertClient
(
/*Définition des paramètres
en Transact-SQL les variables doivent être précédées du caractère @
*/
@nom varchar(20),
@prenom varchar(30),
@tel varchar(15),
@adresse varchar(50)
)
AS
INSERT INTO client(nom,prenom,tel,adresse) VALUES (@nom,@prenom,@tel,@adresse)

VI-B-II - La modification

Procédure UPDATE

CREATE PROCEDURE UpdateClient(
--Définition des paramètres de notre procédure
@id int,
@nom varchar(20),
@prenom varchar(30),
@tel varchar(15),
@adresse varchar(50)
)
AS
UPDATE Client
SET
nom=@nom,
prenom=@prenom,
tel=@tel,
adresse=@adresse
WHERE(client.id=@id)

VI-B-III - La sélection

Procédure Select

CREATE PROCEDURE SelectClient
AS
SELECT id,nom,prenom,tel,adresse from client;

VI-B-IV - La suppression

Procédure Delete

CREATE PROCEDURE DeleteClient
(
@Id int
)
AS
DELETE FROM client
WHERE(client.id=@Id);

VI-B-V - La vérification

Procédure de vérification

CREATE PROCEDURE VerifNumeroBeforeInsert
(
@Numero varchar(15)
)
AS
SELECT COUNT(*) as 'Nombre' FROM client
WHERE(client.tel=@Numero);

VII - Projet en Csharp

Après création des méthodes, nous aborderons la partie code de notre tutoriel. Pour cela, nous allons créer notre solution sous Visual Studio, nommez-la architecture et ensuite vous y ajouterez trois projets de classe nommés respectivement client_metier, client_data, client_structure. À la fin vous devriez avoir une structure comme celle ci-dessous.

VIII - Code

Maintenant que notre solution est créée, nous procéderons à l'écriture de nos couches. Pour ce faire, nous commencerons par la couche d'accès aux données. Cette couche se subdivise en deux parties. Une partie qui permettra de décrire les objets (classes ou structures de données) et une deuxième dans laquelle nous définirons les méthodes qui implémenteront les scripts que nous avons précédemment créés au niveau de la base de données.

VIII-A - La description (couche d'accès aux données)

Voici un exemple de la structure. Cette partie nous permettra de définir les objets que nous utiliserons dans notre application. Notez que ces objets sont créés en tenant compte des structures des tables de notre base de données. Pour notre minitutoriel, nous utiliserons des struct plutôt que des classes (Classes et structures).

Nous avons commencé par cette partie, car l'écriture des couches métier, les méthodes d'accès aux données en dépend.

VIII-B - Les méthodes d'accès aux données

Pour notre exemple, nous n'avons que cinq méthodes, mais elles peuvent varier selon le projet sur lequel vous travaillerez. Nous allons donc créer nos méthodes, lesquelles serviront d'intermédiaire entre notre application et notre moteur de base de données. Ouvrez votre éditeur, ajoutez une classe au projet client_data que vous nommerez clientdata et nous ajouterons nos codes.

- L'insertion

insertclient

public int insertclient(client notreclient)
{
SqlConnection cnx = new SqlConnection(connexion);
cnx.Open();
SqlCommand cmd = new SqlCommand("insertclient",cnx);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter prmnom = new SqlParameter("nom",SqlDbType.VarChar,20);
prmnom.Value = notreclient.nom;
cmd.Parameters.Add(prmnom);
SqlParameter prmprenom = new SqlParameter("prenom", SqlDbType.VarChar, 20);
prmprenom.Value = notreclient.prenom;
cmd.Parameters.Add(prmprenom);
SqlParameter prmtel = new SqlParameter("tel", SqlDbType.VarChar, 20);
prmtel.Value = notreclient.tel;
cmd.Parameters.Add(prmtel);
SqlParameter prmadresse = new SqlParameter("adresse", SqlDbType.VarChar, 20);
prmadresse.Value = notreclient.adresse;
cmd.Parameters.Add(prmadresse);
int resultat = Convert.ToInt32(cmd.ExecuteNonQuery());
return resultat;
}

- La mise à jour

updateclient

public int updateclient(client notreclient)
{
SqlConnection cnx = new SqlConnection(connexion);
cnx.Open();
SqlCommand cmd = new SqlCommand("updateclient", cnx);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter prmid = new SqlParameter("id", SqlDbType.Int, 20);
prmid.Value = notreclient.nom;
cmd.Parameters.Add(prmid);
SqlParameter prmnom = new SqlParameter("nom", SqlDbType.VarChar, 20);
prmnom.Value = notreclient.nom;
cmd.Parameters.Add(prmnom);
SqlParameter prmprenom = new SqlParameter("prenom", SqlDbType.VarChar, 20);
prmprenom.Value = notreclient.prenom;
cmd.Parameters.Add(prmprenom);
SqlParameter prmtel = new SqlParameter("tel", SqlDbType.VarChar, 20);
prmtel.Value = notreclient.tel;
cmd.Parameters.Add(prmtel);

SqlParameter prmadresse = new SqlParameter("adresse", SqlDbType.VarChar, 20);
prmadresse.Value = notreclient.adresse;
cmd.Parameters.Add(prmadresse);
int resultat = Convert.ToInt32(cmd.ExecuteNonQuery());
return resultat;
}

- La suppression

deleteclient

public void deleteclient(int notreclient)
//On passe l'identifiant du client en paramètre
{
SqlConnection cnx = new SqlConnection(connexion);
cnx.Open();
SqlCommand cmd = new SqlCommand("deleteclient", cnx);
cmd.CommandType = CommandType.StoredProcedure;

//Ajout des paramètres
SqlParameter prmid = new SqlParameter("id", SqlDbType.Int, 0);
prmid.Value = notreclient;
cmd.Parameters.Add(prmid);

//Exécution
cmd.ExecuteNonQuery();
}

- La sélection

selectclient

public DataTable selectclient()
{
SqlConnection cnx = new SqlConnection(connexion); //Notre connexion à la base de données
cnx.Open(); //Ouverture de la connexion
SqlCommand cmd = new SqlCommand("selectclient", cnx); //Initialisation de la commande
cmd.CommandType = CommandType.StoredProcedure; //Ici nous précisons le type de notre commande qui est en fait une procédure stockée

DataTable dt = new DataTable(); //Une table de données en mémoire
SqlDataAdapter adaptater = new SqlDataAdapter(cmd);
adaptater.Fill(dt);
return dt;
}

- La vérification

vérification

/*Cette méthode permettra de vérifier l'existence d'un numéro
C'est-à-dire que lorsque nous ajouterons un nouveau client, nous allons
nous assurer que ce numéro n'est pas déjà utilisé par quelqu'un d'autre*/
public DataTable verifclientbeforeinsert(string paramNumero)
{
SqlConnection cnx = new SqlConnection(connexion); //Notre connexion à la base de données
cnx.Open(); //Ouverture de la connexion
SqlCommand cmd = new SqlCommand("VerifNumeroBeforeInsert", cnx); //Initialisation de la commande
cmd.CommandType = CommandType.StoredProcedure; //Ici nous précisons le type de notre commande qui est en fait une procédure stockée
DataTable dt = new DataTable(); //Une table de données en mémoire
SqlDataAdapter adaptater = new SqlDataAdapter(cmd);
adaptater.Fill(dt);
return dt;
}

IX - Couche métier

Pour notre couche métier, nous allons donc décrire nos objets. Cela doit être fait selon les tables de notre base de données. Voici un exemple de notre couche métier.

Couche métier

using System;
using System.Collections.Generic;
using System.Linq;
using client_structure; //Notre couche de destruction
using client_data; //On inclue notre couche d'accès aux données
using System.Text;

namespace client_metier
{
public class clientmetier
{
#region Propriétés publiques

public int id
{
get { return _id; }
set { _id = value; }
}

public string nom
{
get { return _nom; }
set { _nom= value; }
}

public string prenom
{
get { return _prenom; }
set { _prenom = value; }
}

public string tel
{
get { return _tel; }
set { _tel = value; }
}

public string adresse
{
get { return _adresse; }
set { _adresse = value; }
}
#endregion
#region Propriétés privées
int _id;
string _nom;
string _prenom;
string _tel;
string _adresse;
#endregion
}
}

Comme vous le voyez, nous avons deux sortes de déclarations. Celles commençant par le mot-clé public(qui seront accessibles partout) et celles avec le mot private(qui ne seront accessibles que par les objets de la classe). En plus de la description, nous allons également utiliser un objet dans cette couche qui permettra de faire le mapping entre la couche métier et la couche interface. C'est-à-dire que cet objet servira d'intermédiaire en quelque sorte. Dans l'exemple ci-dessous, vous avez la déclaration de notre objet.

Couche métier

#region Objet de mapping
client NotreClient
{
//On déclare donc ces propriétés uniquement en lecture
get
{
client LeClient;
LeClient.id = this._id;
LeClient.nom = this._nom;
LeClient.prenom=this._prenom;
LeClient.adresse = this.adresse;
LeClient.tel = this._tel;
return LeClient;
}
}
#endregion

Après avoir défini notre objet, nous allons donc écrire les méthodes de notre traditionnel CRUD (entendez par là l'insertion, la lecture, la modification et la suppression).

Méthodes du CRUD

#region Les méthodes de notre CRUD

//Méthode d'insertion
public int Insertclient()
{
unclientdata = new clientdata();
return unclientdata.insertclient(NotreClient); //La méthode d'insertion retourne un entier
}

//Méthode de modification
public int Updateclient()
{
unclientdata = new clientdata();
return unclientdata.updateclient(NotreClient);
}

//Méthode de suppression
public void Deleteclient(int idclient)
{
unclientdata = new clientdata();
unclientdata.deleteclient(idclient);
}

public DataTable Selectclient()
{
unclientdata = new clientdata();
return unclientdata.selectclient();
}

public int VerifNumero(string Numero)
{
unclientdata = new clientdata();
return unclientdata.verifclientbeforeinsert(Numero);
}

#endregion

X - Couche interface

Ajoutez un projet de type WindowsFormsApplication à votre projet et faites en sorte que votre formulaire ressemble à quelque chose comme l'image ci-dessous.

Nous allons donc procéder aux différentes opérations sur notre base de données.

Pour cela, nous devrons impérativement instancier un objet de la classe métier. Voici donc un extrait du code de notre bouton, mais avant n'oubliez pas d'importer les espaces de noms requis et d'ajouter une référence à notre couche métier (clic droit sur le projet et sélectionner « Ajouter référence » et sélectionner la couche métier) ensuite vous devrez l'inclure comme l'exemple ci-dessous.

Inclusion de notre couche métier

using client_metier;//Référence à la couche métier

Instanciation d'un objet métier

#region Propriétés privées
clientmetier unclient = null;
#endregion

X-A - L'insertion et la vérification

En ce qui concerne l'insertion, nous devons nous assurer que le numéro entré n'est utilisé par aucun client. Avec le code l'explication sera beaucoup plus facile.

Méthode d'insertion

public void insertclient(string numero, string nom, string prenom, string adresse)
{
unclient = new clientmetier();
int verif = unclient.VerifNumero(numero); //Méthode vérification des numéros avant insertion que nous avons écrite dans la couche métier
if (verif == 0) //Si vrai alors le numéro n'existe pas
{
//Assignation
unclient.nom = nom;
unclient.prenom = prenom;
unclient.tel = numero;
unclient.adresse = adresse;

//Insertion
unclient.Insertclient(); //Méthode d'insertion
cleanfields(); //Cette méthode vide le contenu des champs
}
else
{
//Sinon on affiche un message d'erreur à l'utilisateur
MessageBox.Show("Ce numéro existe déjà", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

Et pour finir, la méthode d'insertion est appelée derrière le bouton comme suit

Bouton Insert

private void button1_Click(object sender, EventArgs e)
{
insertclient(txttel.Text,txtnom.Text,txtprenom.Text,txtadresse.Text);
cleanfields();
loaddata(); //Méthode d'affichage des données.
}

X-B - La sélection

Pour effectuer une sélection, cela est possible grâce à un espace de noms qui est le system.Data. C'est pourquoi nous avons cette ligne.

system,Data

using System.Data;

Voici la méthode sélection

Sélection

public void loaddata()
{
AllClient = new System.Data.DataTable();
unclient = new clientmetier();
AllClient = unclient.Selectclient();//Notre méthode écrite dans la couche d'accès aux données retourne un DataTable
listView1.Items.Clear(); //Suppression de la liste avant d'y afficher les données
foreach (DataRow dtr in AllClient.Rows)
{
//Le DataRow nous permet de parcourir chaque ligne du DataTable(qui est une table de données en mémoire)
int id =0;
string nom = null;
string prenom = null;
string tel = null;
string adresse = null;
//Nous recueillons les valeurs en fonction du nom des colonnes et nous procédons à l'assignation
id = (int)dtr["id"];
nom = (string)dtr["nom"].ToString();
prenom = (string)dtr["prenom"].ToString();
adresse = (string)dtr["adresse"].ToString();
tel = (string)dtr["tel"].ToString();
//Fin assignation
ListViewItem itm = listView1.Items.Add(nom);
itm.SubItems.Add(prenom);
itm.SubItems.Add(tel);
itm.SubItems.Add(adresse);
itm.Tag = id;
}
}

X-C - La modification

Modification

private void btnUpdate_Click(object sender, EventArgs e)
{
try
{
unclient = new clientmetier();
unclient.id = (int)listView1.SelectedItems[0].Tag; //Récupération de l'identifiant
unclient.nom = txtnom.Text;
unclient.prenom = txtprenom.Text;
unclient.tel = txttel.Text;
unclient.adresse = txtadresse.Text;
unclient.Updateclient();
cleanfields();
//Rafraichissement
loaddata();
}
catch (Exception ex)
{
MessageBox.Show("Erreur vérifiez les champs SVP "+ex.Message);
}
}

X-D - La suppression

Suppression

private void btnDelete_Click(object sender, EventArgs e)
{
clientmetier unclient = new clientmetier();
try
{
unclient.id = (int)listView1.SelectedItems[0].Tag; //Récupération de l'identifiant
unclient.Deleteclient(unclient.id); //Suppression
cleanfields();
//Rafraichissement
loaddata();
}
catch (Exception ex)
{
MessageBox.Show("Aucune sélection effectuée");
}
}

XI - Remerciements

Je voudrais remercier mon professeur Monsieur Innocent Apkatou, tous les membres du site en particulier djibril, Lana.Bauer, Viduc, ClaudeLELOUP et f-leb.