• Aucun résultat trouvé

Ecriture des commandes avec des requêtes paramétrées

Je vais ici donner des exemples de requêtes de DataAdapter. Accrochez-vous car à partir d'ici, il vaut mieux avoir intégré correctement ce que nous avons déjà vu.

Pour commencer, nous allons travailler sur la table Titles dont le schéma est le suivant :

Titles

Nom champ Type de données Longueur Précision Commentaires

Title AdWChar 255 0 Not NULL Year Published AdSmallInt 0 5

ISBN adWChar 20 0 Clé primaire PubId AdInteger 0 10 Clé étrangère Description AdWChar 20 0

Notes AdWChar 50 0 Subject AdWChar 50 0

Comments AdLongVarWChar 0 0 Mémo La première chose est de créer notre Dataset.

Private WithEvents tblTitres As DataTable

Private WithEvents dtAdTitre As New OleDbDataAdapter Private dtsBiblio As New DataSet

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim MaConn As New

OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Data Source=C:\tutoriel\biblio.mdb;")

Dim MaCommand As New OleDbCommand("SELECT ISBN, Title, [Year Published], Subject, Description, Notes, PubID FROM Titles", MaConn) dtAdTitre.SelectCommand = MaCommand

dtAdTitre.MissingSchemaAction = MissingSchemaAction.AddWithKey dtAdTitre.Fill(dtsBiblio, "Titres")

tblTitres = dtsBiblio.Tables("Titres")

Dim dtAdComment As New OleDbDataAdapter("SELECT ISBN FROM Titles", MaConn) dtAdComment.MissingSchemaAction = MissingSchemaAction.AddWithKey tblTitres.Columns("Title").AllowDBNull = False dtAdComment.Fill(dtsBiblio, "Comments") dtsBiblio.Tables("Comments").Columns.Add("Comments", System.Type.GetType("System.String")) dtsBiblio.Relations.Add(New DataRelation("unAun", dtsBiblio.Tables("Titres").Columns("ISBN"), dtsBiblio.Tables("Comments").Columns("ISBN"), True)) With dtsBiblio.Relations("unAun").ChildKeyConstraint .AcceptRejectRule = AcceptRejectRule.Cascade .UpdateRule = Rule.None .DeleteRule = Rule.Cascade End With

Jusque là rien de bien complexe. Je crée une table 'Titres' qui regroupe tous les champs courts.

Je crée une seconde table contenant juste le champ clé primaire, et j'ajoute un champ 'Comment' de type Mémo ne contenant rien.

Enfin je mets mes deux tables en relation.

Suppression

Commençons par la plus simple pour nous chauffer.

Comme je vous l'ai déjà dit, pour ma part je n'intègre que les champs clé dans la clause WHERE. Ma requête sera alors :

DELETE Titles WHERE ISBN=?

J'utilise pour l'instant des espaces réservés. Si je travaillais avec SQL-Server, je serais obligé d'utiliser des paramètres nommés. Ce n'en serait d'ailleurs que plus simple.

Je crée la fonction suivante

Private Function CreateDeleteCommand(ByVal LaConnexion As OleDbConnection) As OleDbCommand

Dim strSQL As String = "DELETE Titles WHERE ISBN=?" Dim cmdDel As New OleDbCommand(strSQL, LaConnexion) Dim MonParam As New OleDbParameter

With MonParam .ParameterName = "OrISBN" .OleDbType = OleDbType.VarWChar .Size = 20 .Direction = ParameterDirection.Input .IsNullable = False .SourceColumn = "ISBN" .SourceVersion = DataRowVersion.Original End With cmdDel.Parameters.Add(MonParam) Return cmdDel End Function

Je détaille ici bien les propriétés de mon paramètre. Profitez-en car lorsqu'il y a beaucoup de paramètres à définir comme nous allons le voir plus loin, je tends à utiliser la notation suivante :

cmdDel.Parameters.Add(New OleDbParameter("OrISBN", OleDbType.VarWChar, 20, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "ISBN", DataRowVersion.Original, Nothing))

Dans le cas des espaces réservés, je définis le nom du paramètre par pure bonté d'âme. Je définis par contre correctement le type et la taille, puisqu'il s'agit d'une chaîne, la taille est obligatoire. Je définis surtout le nom de la colonne source et la version. C'est là que se joue tout le travail du DataAdapter. Lors de l'appel de la méthode Update, chaque fois qu'il trouvera une ligne dont l'état est 'Deleted', il récupérera la valeur originale de la colonne ISBN pour valoriser le paramètre, puis il exécutera la requête définie par strSQL.

Bref, du tout automatique.

Notez que dans une requête de suppression, on passe toujours la version originale car il n'existe pas de valeurs courantes

Insertion

Dans mon exemple, celle-ci va être à peine plus complexe, mais croyez bien qu'avant la fin de ce cours, vous la verrez d'un tout autre œil.

Ma requête va être de la forme :

INSERT INTO Titles(ISBN, Title, [Year Published], Subject, Description, Notes, PubID) VALUES (?, ?, ?, ?, ?, ?, ?)

Private Function CreateInsertCommand(ByVal LaConnexion As OleDbConnection) As OleDbCommand

Dim strSQL As String = "INSERT INTO Titles(ISBN, Title, [Year Published], Subject, Description, Notes, PubID) VALUES (?, ?, ?, ?, ?, ?, ?)"

Dim cmdIns As New OleDbCommand(strSQL, LaConnexion) Dim ParISBN As New OleDbParameter

With ParISBN .ParameterName = "CurISBN" .OleDbType = OleDbType.VarWChar .Size = 20 .Direction = ParameterDirection.Input .IsNullable = False .SourceColumn = "ISBN" .SourceVersion = DataRowVersion.Current End With cmdIns.Parameters.Add(ParISBN) Dim parTitles As New OleDbParameter With parTitles .ParameterName = "CurTitle" .OleDbType = OleDbType.VarWChar .Size = 255 .Direction = ParameterDirection.Input .IsNullable = False .SourceColumn = "Titles" .SourceVersion = DataRowVersion.Current End With cmdIns.Parameters.Add(parTitles) Dim parYear As New OleDbParameter With parYear .ParameterName = "CurYear" .OleDbType = OleDbType.UnsignedSmallInt .Precision = 5 .Direction = ParameterDirection.Input .IsNullable = True

.SourceColumn = "year published"

.SourceVersion = DataRowVersion.Current End With

cmdIns.Parameters.Add(parYear)

cmdIns.Parameters.Add(New OleDbParameter("curSubject",

OleDbType.VarWChar, 50, ParameterDirection.Input, True, CType(0, Byte), CType(0, Byte), "Subject", DataRowVersion.Current, Nothing))

cmdIns.Parameters.Add(New OleDbParameter("curDescription", OleDbType.VarWChar, 20, ParameterDirection.Input, True, CType(0, Byte), CType(0, Byte), "Description", DataRowVersion.Current, Nothing))

cmdIns.Parameters.Add(New OleDbParameter("curNotes",

OleDbType.VarWChar, 50, ParameterDirection.Input, True, CType(0, Byte), CType(0, Byte), "Notes", DataRowVersion.Current, Nothing))

cmdIns.Parameters.Add(New OleDbParameter("PubId",

OleDbType.Integer, 0, ParameterDirection.Input, False, 10, CType(0, Byte), "PubId", DataRowVersion.Current, Nothing))

Return cmdIns End Function

Bien sur ce code est un peu fastidieux à écrire, mais vous pouvez utiliser le code généré par l'assistant et le modifier. J'ai détaillé le début du code pour indiquer deux trois précisions.

Lorsqu'un champ utilise un caractère réservé comme l'espace, vous ne devez pas le mettre entre crochet dans la propriété SourceColumn.

Vous n'êtes pas obligé de définir la précision pour les types numériques qui ne sont pas du type OleDbType.Decimal.

Attention de bien mettre la propriété IsNullable du paramètre PubId à false, puisqu'il s'agit d'une clé étrangère pour une autre table.

Vous n'êtes pas tenu de déclarer la version, puisque la version courante est la valeur par défaut

Modification

C'est hélas la plus fastidieuse à écrire (j'en vois qui regrettent déjà le moteur de curseur). Il n'y a qu'un piège avec elle, et comme il est évident, il suffit juste d'y penser.

La requête va être de la forme

UPDATE Titles SET ISBN = ?, Title = ?, [Year Published] = ?, Subject = ?, Description = ?, Notes = ?, PubID = ? WHERE ISBN = ? AND Description = ? AND Notes = ? AND PubID = ? AND Subject = ? AND Title = ? AND [Year Published] = ?

Oui je sais, cela fait mal aux yeux. Mais dites-vous bien, que le pire est que cette requête est fausse. En effet, certaines valeurs des champs d'origine peuvent être NULL. Or si vous écrivez une égalité de la forme Champ=NULL cela sera toujours faux. Ce qui revient à dire que toute ligne ayant une valeur d'origine NULL ne pourrait être identifier par cette requête. Le code correcte est donc :

UPDATE Titles SET ISBN = ?, Title = ?, [Year Published] = ?, Subject = ?, Description = ?, Notes = ?, PubID = ? WHERE (ISBN = ?) AND (Description = ? OR ? IS NULL AND Description IS NULL) AND (Notes = ? OR ? IS NULL AND Notes IS NULL) AND (PubID = ?) AND (Subject = ? OR ? IS NULL AND Subject IS NULL) AND (Title = ?) AND ([Year Published] = ? OR ? IS NULL AND [Year Published] IS NULL)

A chaque fois qu'un champ peut être NULL le critère doit être écrit sous la forme : (Champ = ? OR ? IS NULL AND Champ IS NULL)

Que l'on peut lire sous la forme, le champ est égal au paramètre ou le champ et le paramètre sont NULL. Il faut bien sur passer tous les paramètres. Dans cette requête qui concerne neuf champs il y a dix-neuf paramètres à transmettre. Cela peut sembler abominable, mais vous allez bientôt voir que le jeu en vaut la chandelle.

J'aurais alors ma fonction.

Private Function CreateUpdateCommand(ByVal LaConnexion As OleDbConnection) As OleDbCommand

Dim strSQL As String = "UPDATE Titles SET ISBN = ?, Title = ?, [Year Published] = ?, Subject = ?, Description = ?, Notes = ?, PubID = ? WHERE (ISBN = ?) AND (Description = ? OR ? IS NULL AND Description IS NULL) AND (Notes = ? OR ? IS NULL AND Notes IS NULL) AND (PubID = ?) AND (Subject = ? OR ? IS NULL AND Subject IS NULL) AND (Title = ?) AND ([Year Published] = ? OR ? IS NULL AND [Year Published] IS NULL)" Dim cmdUpd As New OleDbCommand(strSQL, LaConnexion)

cmdUpd.Parameters.Add(New OleDbParameter("ISBN", OleDbType.VarWChar, 20, "ISBN"))

cmdUpd.Parameters.Add(New OleDbParameter("Title", OleDbType.VarWChar, 255, "Title"))

cmdUpd.Parameters.Add(New OleDbParameter("Year_Published", OleDbType.SmallInt, 0, "Year Published"))

cmdUpd.Parameters.Add(New OleDbParameter("Subject", OleDbType.VarWChar, 50, "Subject"))

cmdUpd.Parameters.Add(New OleDbParameter("Description", OleDbType.VarWChar, 50, "Description"))

cmdUpd.Parameters.Add(New OleDbParameter("PubID", OleDbType.Integer, 0, "PubID"))

cmdUpd.Parameters.Add(New OleDbParameter("Original_ISBN",

OleDbType.VarWChar, 20, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "ISBN", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New OleDbParameter("Original_Description", OleDbType.VarWChar, 50, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Description", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New OleDbParameter("Original_Description1", OleDbType.VarWChar, 50, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Description", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New OleDbParameter("Original_Notes",

OleDbType.VarWChar, 50, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Notes", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New OleDbParameter("Original_Notes1", OleDbType.VarWChar, 50, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Notes", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New OleDbParameter("Original_PubID", OleDbType.Integer, 0, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "PubID", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New OleDbParameter("Original_Subject", OleDbType.VarWChar, 50, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Subject", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New OleDbParameter("Original_Subject1", OleDbType.VarWChar, 50, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Subject", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New OleDbParameter("Original_Title",

OleDbType.VarWChar, 255, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Title", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New

OleDbParameter("Original_Year_Published", OleDbType.SmallInt, 0,

ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Year Published", DataRowVersion.Original, Nothing))

cmdUpd.Parameters.Add(New

OleDbParameter("Original_Year_Published1", OleDbType.SmallInt, 0, ParameterDirection.Input, False, CType(0, Byte), CType(0, Byte), "Year Published", DataRowVersion.Original, Nothing))

Return cmdUpd End Function

Bien sur, je n'ai pas écrit ce code. Je l'ai généré à l'aide de l'assistant et légèrement adapté, cela ne m'a pas pris plus de deux minutes. Maintenant je n'ai plus qu'à ajouter après mon code de création

dtAdTitre.DeleteCommand = CreateDeleteCommand(MaConn) dtAdTitre.InsertCommand = CreateInsertCommand(MaConn) dtAdTitre.UpdateCommand = CreateUpdateCommand(MaConn)

Et mon DataAdapter possède sa logique de mise à jour. Ce n'est pas bien compliqué, mais ce n'est que le début.