4-Les procédures stockées .
Il n’y pas de convention de nommage à proprement parler seulement quelques bonnes pratiques et « maladresses » à éviter
use [dbDemo] go CREATE PROCEDURE [dbo].[GetAllFromClient] AS SELECT [Id],[Name],[Email] FROM dbo.[Client] go
CREATE PROCEDURE [dbo].[GetClient] ( @Id int ) AS SELECT [Id],[Name],[Email] FROM dbo.[Client] WHERE [Id]=@Id go
CREATE PROCEDURE [dbo].[InsertClient](@Name char(100),@Email char(100),@CategoryId int) AS INSERT INTO [Client]([Name] ,[Email] ,[CategoryId] ) VALUES(@Name,@Email,@CategoryId) SELECT SCOPE_IDENTITY(); go
CREATE PROCEDURE [dbo].[UpdateClient] ( @Id int, @Name nchar(100), @Email nchar(100) ) AS UPDATE dbo.[Client] SET [Name]=@Name,[Email]=@Email WHERE [Id]=@Id go
CREATE PROCEDURE [dbo].[DeleteClient] ( @Id int ) AS DELETE FROM [dbo].[Client] WHERE [Id]=@Id go |
5-DBNULL et nullables
Pour gérer les champs pour être « null » en base de données
- Du côté de de l’application on stockera les données lues dans des nullables(System.Nullables<T>) (rappel System.String n’a pas de nullable)
- DBNULL permettra au contraire de tester si une ligne lue avec le datareader est « null »
Exemple : Dans la classe Client.cs
public Nullable<int> Age { get; set; } |
Dans la classe d’accès aux données
if(reader["Age"] != DBNull.Value) client.Age = Convert.ToInt32(reader["Age"]); |
- Il est également possible d’affecter la valeur de défaut du type et ne pas avoir besoin des nullables
if (reader["Email"] == DBNull.Value) client.Email = default(string); else client.Email=reader["Email"].ToString(); // ou client.Email = reader["Email"] == DBNull.Value ? default(string) : reader["Email"].ToString(); |
6-Construction de l’application – Couches
Il y a :
- La couche d’accès aux données(DAL) avec les classes (exemple ClientDAO) permettant de se connecter à une source de données/base
- La couche des objets métiers (business objects contenant les classes comme Client.cs) qui servent à stocker temporairement les données que l’on récupère de la base
- La couche interface utilisateur (Gui : windows form,pages web,…) qui permet d’afficher les informations (consultation) et la mise à jour
A cela on peut ajouter une couche « Manager »(BLL), une sorte de chef d’orchestre entre l’ui ,la couche métier et la couche d’accès aux données .
7-Binding
Avec Windows forms il est possible d’utiliser BindingList<T> et INotifyPropertyChanged
Il est possible de convertir une liste générique List<T> en BindingList<T> ainsi
List<Client> clients = new List<Client>(); BindingList<Client> bindingClients = new BindingList<Client>(clients); |
La bindingList permet de notifier les changements au niveau de la collection(ajout,suppression d’un élément)et INotifyPropertyChanged permet de notifier les changements au niveau d’un élément(exemple : on modifie l’email d’un client) .L’interface utilisateur se mettra à jour « automatiquement »
public class Client :INotifyPropertyChanged { // ... code enlevé pour la clarté de l'exemple
private string _email;
public string Email { get { return _email; } set { _email = value; this.OnPropertyChanged("Email"); } }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } |
Avec WPF on préfèrera utiliser ObservableCollection donc j’ai parlé dans un article précédent.
8-Vue Liste/détail :
utile pour afficher une liste dans une grille(comme le datagridView) et le détail(en vue de modifier par exemple) .Il est possible également de permettre l’édition dans le datagridView (readonly) .
On met à jour après vérification que la ligne respecte les contraintes (exemple une valeur n’acceptant pas les valeurs nulles, un email devant respecter un format avec une regex,un champ age n’acceptant que des chiffres,etc.)
Exemple je vérifie la cellule venant d’être modifiée.Si elle est vide j’affiche un message d’erreur,si tout est bon je mets à jour la base de données . J’affiche également à l’utilisateur la valeur de la cellule avant son édition (dataGridView1.CurrentCell.Value)
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { if (string.IsNullOrEmpty(e.FormattedValue.ToString().Trim())) {
//afficher l'erreur au niveau de la ligne // dataGridView1.Rows[e.RowIndex].ErrorText ="message d'erreur";
// ou au niveau de la cellule courante dataGridView1.CurrentCell.ErrorText = string.Format("Cette cellule a été modifiée .Une Valeur est nécessaire.La modification n'a pas été enregistrée en base de données .Valeur d'origine : {0} ",dataGridView1.CurrentCell.Value);
//e.Cancel = true; } else { if (loading == false) { // on met à jour la base Client client = (Client)dataGridView1.SelectedRows[0].DataBoundItem; clientDAO.UpdateClient(client); } } |
Pour aller plus loin :
On pourra parler des générateurs de code,d’entreprise Library,ADO Entity,MVVM et tellement de pistes .
Je parlerai aussi de DbProvider