Vous êtes sur la page 1sur 14

Visual Studio .

NET C# Partie 3

SOMMAIRE

1 Application multicouches ............................................................................... 2


1.1 Le problème .............................................................................................. 2
1.2 Les différentes couches............................................................................. 2
2 Mise en œuvre ................................................................................................ 3
2.1 Couche des objets métier ......................................................................... 3
2.2 Couche d’accès aux données .................................................................... 5
2.3 Couche métier ........................................................................................... 8
2.4 Couche interface graphique ...................................................................... 9
2.5 Avantages................................................................................................ 13

Professeur : ASSALE Adjé Louis 1/14 INP-HB


Visual Studio .NET C# Partie 3

1 Application multicouches

Nous allons présenter le développement d’une application à plusieurs couches.

1.1 Le problème

Nous allons réaliser une application de gestion de bibliothèque. Cette


application accédera à une base de données. Les éléments à gérer dans la base
sont les suivants : Classe(Code_cl varchar(7), Libelle varchar(50), Effectif int) –
Etudiant(Matricule varchar(10), Nom varchar(15), Prenoms varchar(50), Sexe
char(1), Code_c#l varchar(7)) – Livre(Code_liv varchar(15), Titre varchar(50),
Auteur varchar(25), Edition varchar(30), Nbre_ex int) – Emprunt(Matricule#
varchar(7), Code_liv# varchar(15), Sortie date, Retour date).

L’application sera à interface graphique : un formulaire Windows principale


pourvu d’un menu qui fait appel à des formulaires Windows secondaires pour
chaque élément à gérer.

1.2 Les différentes couches

Notre application sera composée de 4 couches :

Une couche graphique (CG) qui servira à afficher les données provenant de la base de
données et servira aussi à envoyer des données vers la base. Cette couche communiquera avec
la base de données par l’intermédiaire d’une couche qu’on appellera couche métier.

La couche métier (CM) est la couche qui gère toutes les données issues de la base de données
comme de l’interface graphique. Elle sert de couche intermédiaire entre l’interface utilisateur
et la couche d’accès aux données.

La couche d’accès aux données (CAD) dispose de tous les mécanismes pour récupérer les
informations à partir de la base données et d’en envoyer à la base.

Enfin la couche des objets métier (COM) qui comprendra des classes correspondant aux
tables disponible dans la base de données. Cette couche sera accessible à toutes les 3 autres
couches. On pourra mettre dans cette couche la classe de connexion à la base de données.

Ce qui conduit au référencement suivant :


CG

CM COM

CAD

Professeur : ASSALE Adjé Louis 2/14 INP-HB


Visual Studio .NET C# Partie 3

2 Mise en œuvre

On créera une solution qui contiendra plusieurs projets. Parmi ces projets, un
projet celui de l’interface graphique servira de point de démarrage de
l’application. A part le projet de démarrage, tous les autres projets seront des
projets de type Bibliothèque de classes. Un projet de type Bibliothèque de
classes définit un espace de nom. Les classes d’un même projet peuvent être soit
dans un seul fichier ou étendues sur plusieurs fichiers. Pour ajouter une nouvelle
classe à un projet soit dans l’espace de nom correspondant au projet on saisit la
classe par : public classe <Nom_classe>{ … }
Soit étant sur le projet on fait Menu Projet/Ajouter une classe ; ce qui engendre
un nouveau fichier de classe
Le référencement à un projet (espace de nom) s’effectue en ajoutant dans
l’entête du fichier la mention using <espace_de_nom> et en faisant Menu
Projet/Ajouter une référence on choisit le projet concerné.

2.1 Couche des objets métier

Elle contiendra des classes pour chaque élément géré au niveau de la base de
données. Elle contiendra également une classe pour la connexion à la base de
données. Cette classe de connexion doit implémenter une seule instance, elle
sera définie de ce fait à l’aide du design pattern Singleton.
On trouvera ci-après quelques éléments de cette couche :

Professeur : ASSALE Adjé Louis 3/14 INP-HB


Visual Studio .NET C# Partie 3

Cette couche définit l’espace de nom ObjetsMetier qui contient un fichier de


classe Classe.cs refermant les différents éléments à gérer à savoir les classes
Classe, Etudiant, Livre, Emprunt, … et Connexion.

Le code pour la classe Connexion est le suivant :

public class Connexion


{
private OleDbConnection laConnexion;
private String m_chaineconnexion;
private static Connexion S_Instance;
public String chaineconnexion
{
get { return m_chaineconnexion; }
set { m_chaineconnexion = value; }
}
//Singleton
public static Connexion Instance()
{
if (S_Instance == null)
S_Instance = new Connexion();
return S_Instance;
}
public OleDbConnection OuvrirConnexion()
{
if (laConnexion == null)
laConnexion = new OleDbConnection();

if (laConnexion.State ==
System.Data.ConnectionState.Closed)
{
laConnexion.ConnectionString =
chaineconnexion;
laConnexion.Open();
}
return laConnexion;
}
public void FermerConnexion()
{
if (laConnexion != null)
if (laConnexion.State !=
System.Data.ConnectionState.Closed)
laConnexion.Close();
}
public OleDbConnection cnx
{
get { return this.OuvrirConnexion(); }
}
}

Professeur : ASSALE Adjé Louis 4/14 INP-HB


Visual Studio .NET C# Partie 3

Le design pattern Singleton est une technique qui permet d’avoir une unique
instance de la classe. Si la classe est instanciée plusieurs fois les différentes
instances sont identiques. Comme la classe Connexion est utilisée à chaque fois
que l’on voudrait accéder à la base elle sera alors instanciée plusieurs fois. Or il
ne faudrait pas que les connexions diffèrent les unes des autres.
Le code pour la classe Classe encapsulant les informations d’une ligne de la
table Classe est :

public class Classe


{
public String lecode="";
private String m_Code_cl;

public String Code_cl


{
get { return m_Code_cl; }
set { m_Code_cl = value; }
}

private String m_Libelle;

public String Libelle


{
get { return m_Libelle; }
set { m_Libelle = value; }
}

private int m_Effectif;

public int Effectif


{
get { return m_Effectif; }
set { m_Effectif = value; }
}
}

Remarquons que dans les deux classes, nous avons utilisé des propriétés pour
accéder à des champs non publics à l’aide de get et set. En particulier le
Singleton Connexion définit 2 propriétés une de type String pour la chaine de
connexion et l’autre de type OleDbConnection pour la connexion elle même

2.2 Couche d’accès aux données

Cette couche définit pour chaque élément de la base de données une classe
permettant de gérer les données de cet élément. A savoir récupérer les données

Professeur : ASSALE Adjé Louis 5/14 INP-HB


Visual Studio .NET C# Partie 3

d’une table, en insérer, modifier ou supprimer. Par exemple pour la table Classe
de la base de données, on définit la classe ClasseDAO dont le code se présente
comme suit :

public class ClasseDAO


{

public static void DelUneClasseToDB(Classe uneclasse)


{
String larequete;
Connexion lacon = Connexion.Instance();
OleDbConnection cnx = lacon.cnx;
if (uneclasse.lecode != "")
{
larequete = "delete from classe where
code_cl='" + uneclasse.Code_cl+ "'";
OleDbCommand laCommande = new
OleDbCommand(larequete, lacon.cnx);
laCommande.ExecuteNonQuery();
}
}
public static void UpUneClasseToDB(Classe uneclasse)
{
String larequete;
Connexion lacon = Connexion.Instance();
OleDbConnection cnx = lacon.cnx;
larequete = "update classe set code_cl='" +
uneclasse.Code_cl + "', libelle='" +
uneclasse.Libelle + "', effectif=" +
uneclasse.Effectif + " where code_cl='" +
uneclasse.lecode + "'";
OleDbCommand laCommande = new
OleDbCommand(larequete, lacon.cnx);
laCommande.ExecuteNonQuery();
}
public static void SetUneClasseToDB(Classe uneclasse)
{
String larequete;
Connexion lacon = Connexion.Instance();
OleDbConnection cnx = lacon.cnx;
larequete = " insert into classe values('" +
uneclasse.Code_cl +
"','" + uneclasse.Libelle + "'," +
uneclasse.Effectif + ")";
OleDbCommand laCommande = new
OleDbCommand(larequete, lacon.cnx);
laCommande.ExecuteNonQuery();
}
public static void SetClassesToDB(List<Classe> lesclasses)
{

Professeur : ASSALE Adjé Louis 6/14 INP-HB


Visual Studio .NET C# Partie 3

String larequete;
Connexion lacon = Connexion.Instance();
OleDbConnection cnx = lacon.cnx;
Classe uneclasse = new Classe();
int num=0;
while(num<lesclasses.Count)
{
uneclasse=lesclasses[num];
if (uneclasse.lecode != "")
larequete = "update classe set code_cl='" +
uneclasse.Code_cl + "', libelle='" +
uneclasse.Libelle + "', effectif=" +
uneclasse.Effectif + " where code_cl='" +
uneclasse.lecode + "'";
else
{
larequete = " insert into classe values('" +
uneclasse.Code_cl +
"','" + uneclasse.Libelle + "'," +
uneclasse.Effectif + ")";
uneclasse.lecode = uneclasse.Code_cl;
}
OleDbCommand laCommande = new
OleDbCommand(larequete,lacon.cnx);
laCommande.ExecuteNonQuery();
}

public static List<Classe> GetClassesDeBD(String larequete)


{
//appel de l’unique instance du Singleton Connexion
Connexion lacon = Connexion.Instance();
List<Classe> lesclasses = new List<Classe>();
OleDbCommand laCommande = new
OleDbCommand(larequete, lacon.cnx);
OleDbDataReader leDataReader=
laCommande.ExecuteReader();
while (leDataReader.Read())
{
Classe laclasse = new Classe();
laclasse.lecode =
leDataReader["Code_cl"] == DBNull.Value ? default(String) :

leDataReader["Code_cl"].ToString();
laclasse.Code_cl =
leDataReader["Code_cl"] == DBNull.Value ? default(String) :

leDataReader["Code_cl"].ToString();
laclasse.Libelle =
leDataReader["Libelle"] == DBNull.Value ? default(String) :

Professeur : ASSALE Adjé Louis 7/14 INP-HB


Visual Studio .NET C# Partie 3

leDataReader["Libelle"].ToString();
laclasse.Effectif =
leDataReader["Effectif"] == DBNull.Value ? default(int) :

int.Parse(leDataReader["Effectif"].ToString());
lesclasses.Add(laclasse);
}
leDataReader.Close();
return lesclasses;
}
}

Les méthodes de cette classe ont l’attribut static qui signifie qu’elles sont
identiques pour toutes les instances. La méthode GetClassesDeBD récupère
toutes les lignes de la table Classe et les mettre dans un objet liste de Classe. Les
méthodes SetUneClasseToDB, UpUneClasseToDB et DelUneClasseToDB
respectivement insèrent, modifient et suppriment une ligne dans la base de
données. La méthode SetClassesToDB met à jour toutes les données d’un objet
liste de Classe dans la base de données.

2.3 Couche métier

Cette couche renferme toute la logique métier, elle définit une classe pour
chaque élément à gérer dans la base. Ces classes définissent des méthodes pour
échanger des informations avec la couche d’accès aux données. Ci-après le code
pour le gestionnaire de la classe Classe.

public class GestClasse


{
private String lachaine;

public GestClasse(String chaine)


{
lachaine = chaine;
}
public List<Classe> GetClasses()
{
List<Classe> lesclasses = null;
lesclasses= ClasseDAO.GetClassesDeBD(lachaine);
return lesclasses;
}
public static List<Classe> AjouterClasse(Classe
uneclasse, List<Classe> lesclasses)
{
lesclasses.Add(uneclasse);
ClasseDAO.SetUneClasseToDB(uneclasse);
return lesclasses;

Professeur : ASSALE Adjé Louis 8/14 INP-HB


Visual Studio .NET C# Partie 3

}
public static List<Classe> ModifierClasse(Classe
uneclasse, List<Classe> lesclasses, int num)
{
lesclasses[num]=uneclasse;
ClasseDAO.UpUneClasseToDB(uneclasse);
return lesclasses;
}
public static List<Classe> SupprimerClasse(Classe
uneclasse, List<Classe> lesclasses, int num)
{
lesclasses.RemoveAt(num);
ClasseDAO.DelUneClasseToDB(uneclasse);
return lesclasses;
}
}

2.4 Couche interface graphique

Elle dispose des différents formulaires accessibles par l’utilisateur. Chaque


formulaire définit une classe. Le formulaire connexion définit la classe
connexion que voici :

Ici on se connecte à une base de données SQL Server. L’événement Click du


bouton Ok contient le code suivant :

public partial class connexion : Form


{
public static String chaine;
Connexion lacon = Connexion.Instance(); //appel de
l'instance unique du Singleton Connexion
OleDbConnection cnx;
public connexion()
{
InitializeComponent();
}

private void Ok_Click(object sender, EventArgs e)

Professeur : ASSALE Adjé Louis 9/14 INP-HB


Visual Studio .NET C# Partie 3

{
chaine = "Provider = SQLOLEDB; Data Source =" +
textBox3.Text + "; User Id=" + textBox1.Text +
"; password=" + textBox2.Text + "; Initial
Catalog=" + textBox4.Text;
try
{
//définition de la chaine de connexion
lacon.chaineconnexion = chaine;
//ouverture de la connexion
cnx =lacon.OuvrirConnexion(); //l'unique
instance est ainsi définie

MessageBox.Show("connexion réussie");
this.Close();
}
catch (Exception ex) { MessageBox.Show("connexion
non effectuée: " + ex.Message); }
}

Ce code définit les propriétés chaineconnexion (pour la chaine de connexion) et


cnx (pour l’objet Connection lui-même). Ainsi, l’unique instance vient d’être
définie. Pour les autres connexions à la base, on appellera simplement la
propriété cnx pour obtenir une connexion à l’aide d’une nouvelle instanciation.

L’interface graphique pour la classe Classe est la suivante :

L’événement Load du formulaire fait appel à la méthode GetClasses de la classe


GestClasse de la couche métier pour obtenir les données.
Les événements Click des boutons Supprimer et Enregistrer font appel aux
méthodes correspondantes de la classe GestClasse la couche métier en vue de
gérer les données de la base.
La classe de l’interface graphique dispose des méthodes lireClasse,
modifierClasse et afficherClasse qui respectivement récupère les données d’une
nouvelle classe saisie, d’une classe modifiée ou affiche les données d’une classe.
Le code pour cette classe est le suivant :

Professeur : ASSALE Adjé Louis 10/14 INP-HB


Visual Studio .NET C# Partie 3

public partial class Classe : Form


{
List<ObjetsMetier.Classe> lesclasses ;
ObjetsMetier.Classe laclasse;
GestClasse gererClasse;
int num;
public ObjetsMetier.Classe lireClasse()
{
laclasse = new ObjetsMetier.Classe();
laclasse.Code_cl = TextBox1.Text;
laclasse.Libelle = TextBox2.Text;
laclasse.Effectif = int.Parse(TextBox3.Text);
return laclasse;
}
public ObjetsMetier.Classe
modifierClasse(ObjetsMetier.Classe uneclasse)
{
uneclasse.Code_cl = TextBox1.Text;
uneclasse.Libelle = TextBox2.Text;
uneclasse.Effectif = int.Parse(TextBox3.Text);
return uneclasse;
}
public void afficherClasse(ObjetsMetier.Classe uneclasse)
{
TextBox1.Text = uneclasse.Code_cl;
TextBox2.Text = uneclasse.Libelle;
TextBox3.Text = uneclasse.Effectif.ToString();
}
public Classe()
{
InitializeComponent();
}

private void Classe_Load(object sender, EventArgs e)


{
try
{
String requete = "select * from classe";
gererClasse = new GestClasse(requete);
lesclasses = gererClasse.GetClasses();
num = 0;
if (lesclasses.Count != 0)
{
laclasse = lesclasses[num];
afficherClasse(laclasse);
}
else MessageBox.Show("pas d'enregistrement
trouvé");
}
catch (Exception ex) {
MessageBox.Show(ex.Message); }

Professeur : ASSALE Adjé Louis 11/14 INP-HB


Visual Studio .NET C# Partie 3

private void Enregistrer_Click(object sender, EventArgs e)


{
try
{
if (laclasse == null)
{
laclasse = lireClasse();
laclasse.lecode = laclasse.Code_cl;
lesclasses =
GestClasse.AjouterClasse(laclasse, lesclasses);
num = lesclasses.Count - 1;
}
else
{
laclasse=modifierClasse(laclasse);
lesclasses =
GestClasse.ModifierClasse(laclasse, lesclasses,num);
laclasse.lecode = laclasse.Code_cl;
}
MessageBox.Show("Enregistrement effectué");
}
catch (Exception ex) { MessageBox.Show("erreur: "
+ ex.Message); }
}

private void Nouveau_Click(object sender, EventArgs e)


{
laclasse = null;
TextBox1.Text = "";
TextBox2.Text = "";
TextBox3.Text = "";
TextBox1.Focus();
}

private void Suivant_Click(object sender, EventArgs e)


{
if (num < lesclasses.Count)
{
num += 1;
if (num < lesclasses.Count)
{
laclasse = lesclasses[num];
AfficherClasse(laclasse);
}
}
}

private void Precedent_Click(object sender, EventArgs e)


{

Professeur : ASSALE Adjé Louis 12/14 INP-HB


Visual Studio .NET C# Partie 3

if (num > 0)
{
num -= 1;
if (num >= 0)
{
laclasse = lesclasses[num];
afficherClasse(laclasse);
}
}

private void Supprimer_Click(object sender, EventArgs e)


{
lesclasses = GestClasse.SupprimerClasse(laclasse,
lesclasses, num);
laclasse = lesclasses[num];
afficherClasse(laclasse);
}
}

2.5 Avantages

Développer en utilisant des couches présente les avantages suivants :

 Maintenance des données est indépendante du support de stockage

En effet, la manière dont les données sont gérées ne dépend pas du support de
stockage du fait qu’on fait appel à une couche intermédiaire. De même changer
de support de stockage n’entraine que la modification de la couche d’accès aux
données dont n’influence pas la gestion des données

 Maintenance des traitements est simplifiée

La modification des traitements d’une couche n’entraine pas de modification en


cascade pourvu qu’on maintienne la signature des méthodes.

 Gestion des traitements depuis la couche présentation est facilitée

En fait dans la couche présentation, on fait appel aux méthodes des classes de la
couche métier ce qui facilite l’écriture du code.

 Travail en équipe est optimisé

Professeur : ASSALE Adjé Louis 13/14 INP-HB


Visual Studio .NET C# Partie 3

Des membres de l’équipe peuvent travailler sur différentes couches.

 Migration d’un environnement graphique à un autre est relativement


simple

Du fait qu’on ne redéveloppe que la couche graphique quand on passe d’une


interface graphique à l’autre.

Professeur : ASSALE Adjé Louis 14/14 INP-HB

Vous aimerez peut-être aussi