BasicZx81
Messages postés140Date d'inscriptionsamedi 5 mars 2011StatutMembreDernière intervention13 août 2013
-
12 févr. 2012 à 10:32
BasicZx81
Messages postés140Date d'inscriptionsamedi 5 mars 2011StatutMembreDernière intervention13 août 2013
-
13 févr. 2012 à 10:43
Bonjour à tous,
j'ai suivi l'excellent tuto de J.M Rabilloud sur Devellopez.com pourtant je me heurte à un problème :
D'aprés le Tuto il est tout à fait possible de bénéficier des relations entre les tables Mères/Filles dans un Dataset dans le but d'obtenir des mises en jours en cascade dans ce Dataset (Exemple si je supprime un enregistrement de la table mère, tous les enregistrements liés par une clé étrangère de la table fille vont se supprimer automatiquement sans aucune ligne de code). Je peux donc reproduire les contraintes et comportement de la base source dans mon Dataset.
Dans le cas de colonne Auto-incrementé c'est la base de données source qui fourni les numéros correspondant aux clés primaire de chaque table (Mère/Fille) au moment de l'enregistrement du Dataset.
Mon premier essai à fonctionné mais sans les relations et sans les clés primaire, c'est à dire que je laisse les champs auto-incrementé vide et je recupére ces numéros au moment de l'enregistrement grace à la commande "SELECT @@IDENTITY". Donc ce premier essai fonctionne mais sans bénéficier des mises à jours en cascade du Dataset.
A partir de là j'ai un doute, j'espère que vous me corrigerais : Pour créer une relation dans mon Dataset cela m'oblige à créer une clé primaire sur la table Mère (sur la colonne correspondante à la colonne source auto-incrementé), ensuite je declare une relation entre 2 colonnes des tables Mère/Fille. C'est donc ce que j'ai fait lors de mon deuxieme essai. Problème : Après la mise en place des clés primaire les colonnes correspondante n'acceptent plus les champs vide et m'oblige à renseigner les colonnes un numéro quelconque mais ça plante au moment d'enregistrer (je suppose que la source n'accepte pas autre chose que les champs vide puisque c'est elle qui fourni les numéros).
Y a t'il un moyen pour que cela fonctionne comme lors de mon premier essai mais avec les relations et mises à jour en cascade ?
LE CODE POUR CHARGER LE DATASET :
Private sub Load Dataset()
Call OpenConnection()
'Initialisation de la chaîne contenant l'instruction SQL
Dim sqlMère As String = "SELECT * FROM MERE"
DBDataAdapterMère = New OleDbDataAdapter(sqlMère, DBconnection)
Dim sqlFille As String = "SELECT * FROM FILLE"
DBDataAdapterFille = New OleDbDataAdapter(sqlFille, DBconnection)
objDBDataSet.Clear()
objDBDataSet.EnforceConstraints = False
'Avec l'aide de la propriété Fill du DataAdapter charger le DataSet
DBDataAdapterMère.Fill(objDBDataSet, "MERE")
' Ajout de la contrainte de clé primaire :
Dim maTable As DataTable = objDBDataSet.Tables("MERE")
maTable.Constraints.Add("pk1", maTable.Columns("ID_MERE"), True)
DBDataAdapterFille.Fill(objDBDataSet, "FILLE")
maTable = objDBDataSet.Tables("FILLE")
maTable.Constraints.Add("pk1", maTable.Columns("ID_FILLE"), True)
' Ajout de la relation entre la table MERE et FILLE :
Dim DRelat As New DataRelation("Rl1", objDBDataSet.Tables("MERE").Columns("ID_MERE"), objDBDataSet.Tables("FILLE").Columns("ID_MERE"), True)
objDBDataSet.Relations.Add(DRelat)
Dim FKCont As ForeignKeyConstraint = maTable.Constraints.Item(1)
With FKCont
.AcceptRejectRule = AcceptRejectRule.Cascade
.DeleteRule = Rule.Cascade
.UpdateRule = Rule.Cascade
End With
objDBDataSet.EnforceConstraints = True
Call CloseConnection()
End Sub
LE CODE POUR RECUPERER LES NUMEROS AUTO-INCREMENTES DE LA BASE SOURCE :
Private Sub DBAdapterMère_RowUpdate(ByVal sender As Object, ByVal e As System.Data.OleDb.OleDbRowUpdatedEventArgs)
If e.StatementType = StatementType.Insert Then
Dim MaComRecup As New OleDb.OleDbCommand("SELECT @@IDENTITY", e.Command.Connection)
'MaComRecup.Transaction = MaTransaction
e.Row.Item("ID_MERE") = MaComRecup.ExecuteScalar
e.Row.AcceptChanges()
End If
End Sub
LE CODE POUR ENREGISTRER LE DATASET :
Public Sub SaveDataset()
Call OpenConnection()
Dim bldr10 = New OleDbCommandBuilder(DBDataAdapterMère)
Dim MéreDelete As OleDbCommand = bldr10.GetDeleteCommand()
Dim MéreInsert As OleDbCommand = bldr10.GetInsertCommand
Dim MéreUpdate As OleDbCommand = bldr10.GetUpdateCommand
Dim bldr20 = New OleDbCommandBuilder(DBDataAdapterFille)
Dim FilleDelete As OleDbCommand = bldr20.GetDeleteCommand()
Dim FilleInsert As OleDbCommand = bldr20.GetInsertCommand
Dim FilleUpdate As OleDbCommand = bldr20.GetUpdateCommand
' On instancie une transaction (si besoin)
'MaTransaction = DBconnection.BeginTransaction()
'MèreDelete.Transaction = MaTransaction
'MèreInsert.Transaction = MaTransaction
'MèreUpdate.Transaction = MaTransaction
'FilleDelete.Transaction = MaTransaction
'FilleInsert.Transaction = MaTransaction
'FilleUpdate.Transaction = MaTransaction
Try
' IL faut effectuer les commandes dans l'ordre :
' 1 - Envoyer les enregistrements ajoutés à la table mère :
DBDataAdapterMére.Update(objDBDataSet.Tables("MERE").Select(Nothing, Nothing, DataViewRowState.Added))
' 2 - Envoyer les enregistrements ajoutés à la table fille :
DBDataAdapterFille.Update(objDBDataSet.Tables("FILLE").Select(Nothing, Nothing, DataViewRowState.Added))
' 3 - Envoyer les enregistrements modifiés à la table mère :
DBDataAdapterMére.Update(objDBDataSet.Tables("MERE").Select(Nothing, Nothing, DataViewRowState.ModifiedCurrent))
' 4 - Envoyer les enregistrements modifiés à la table fille :
DBDataAdapterFille.Update(objDBDataSet.Tables("FILLE").Select(Nothing, Nothing, DataViewRowState.ModifiedCurrent))
' 5 - Envoyer les enregistrements supprimés à la table fille :
DBDataAdapterFille.Update(objDBDataSet.Tables("FILLE").Select(Nothing, Nothing, DataViewRowState.Deleted))
' 5 - Envoyer les enregistrements supprimés à la table Mére :
DBDataAdapterMére.Update(objDBDataSet.Tables("MERE").Select(Nothing, Nothing, DataViewRowState.Deleted))
'MaTransaction.Commit()
objDBDataSet.AcceptChanges()
MessageBox.Show("L'enregistrement à réussi.", "Enregistrement réussi.", MessageBoxButtons.OK, MessageBoxIcon.Information)
Catch ex As DBConcurrencyException
'MaTransaction.Rollback()
objDBDataSet.RejectChanges()
MessageBox.Show("Modifications rejetées par la base.", "Echec de l'enregistrement.", MessageBoxButtons.OK, MessageBoxIcon.Error)
Catch ex As Exception
MsgBox(ex.Message)
End Try
Call CloseConnection()
End Sub
A voir également:
Mise à jour en cascade (Tables Mère/Fille) avec colonnes auto-incrementés
BasicZx81
Messages postés140Date d'inscriptionsamedi 5 mars 2011StatutMembreDernière intervention13 août 2013 13 févr. 2012 à 10:43
Après la mise en place des clés primaire les colonnes correspondante n'acceptent plus les champs vide et m'oblige à renseigner les colonnes avec un numéro quelconque mais ça plante au moment d'enregistrer (je suppose que la source n'accepte pas autre chose que les champs vide puisque c'est elle qui fourni les numéros).
Je me réponds à moi-même, ça pourra servir à d'autres personnes.
La solution est de créer des colonnes auto-incrémentées aussi dans le Dataset, cela pour plusieurs raisons :
- Pour éviter de laisser des champs vide (ceux-ci ne sont plus acceptés dés lors que l'on veux paramétrer une relation entre 2 tables qui utilisent forcement des clés primaire dans son fonctionnement.)
- Ensuite pour le fonctionnement interne de l'application qui à besoin de ces numéros de clés pour pouvoir liées les enregistrements de 2 tables. (Ces numéros ne sont que provisoire puisque au moment d'enregistrer ils sont remplacés et attribués par la base source)
Changer la base et l’incrémentation des colonnes IncrementSeed et IncrementStep à -1 (Ne me demandé pas pourquoi il faut mettre des valeurs négative je n'ai pas encore compris pourquoi mais il parait qu'il y a une raison et comme cela fonctionne je le laisse comme ça).
PS : j'espère que le code est assez propre, il y peut-être d'autre facon de faire mais l'essentiel est d'arriver au résultat souhaité.
Le bout de code qui sert à créer les colonnes incrémentées et les relations nécessaires :
Private Sub InitDataSet()
' Création d'un Dataset Typé au demarrage de l'application
' On crée juste les colonnes et relations dont on à besoin
objDBDataSet = New DataSet
Dim MaTable As New DataTable("MERE")
MaTable.Columns.Add("ID_MERE", Type.GetType("System.Int32")).AutoIncrement = True
With MaTable.Columns("ID_MERE")
.AutoIncrementSeed = -1
.AutoIncrementStep = -1
.Unique = True
.AllowDBNull = False
End With
objDBDataSet.Tables.Add(MaTable)
MaTable = New DataTable("FILLE")
MaTable.Columns.Add("ID_FILLE", Type.GetType("System.Int32")).AutoIncrement = True
With MaTable.Columns("ID_FILLE")
.AutoIncrementSeed = -1
.AutoIncrementStep = -1
.Unique = True
.AllowDBNull = False
End With
MaTable.Columns.Add("ID_MERE", Type.GetType("System.Int32"))
objDBDataSet.Tables.Add(MaTable)
' Ajout de la relation entre la table MERE et FILLE :
Dim DRelat As New DataRelation("Rl1", objDBDataSet.Tables("MERE").Columns("ID_MERE"), objDBDataSet.Tables("FILLE").Columns("ID_MERE"), True)
objDBDataSet.Relations.Add(DRelat)
Dim FKCont As ForeignKeyConstraint = MaTable.Constraints.Item(1)
With FKCont
.AcceptRejectRule = AcceptRejectRule.Cascade
.DeleteRule = Rule.Cascade
.UpdateRule = Rule.Cascade
End With
End Sub
Remplacer le code du LoadDataSet par celui-ci :
Public Sub LoadDataSet()
Call OpenConnection()
'Initialisation de la chaîne contenant l'instruction SQL
Dim sqlMERE As String = "SELECT * FROM " & MERE
DBDataAdapterMére = New OleDbDataAdapter(sqlMERE, DBconnection)
Dim sqlFILLE As String = "SELECT * FROM " & FILLE
DBDataAdapterFille = New OleDbDataAdapter(sqlFILLE, DBconnection)
objDBDataSet.Clear()
objDBDataSet.EnforceConstraints = False
'Avec l'aide de la propriété Fill du DataAdapter charger le DataSet
DBDataAdapterMére.Fill(objDBDataSet, "MERE")
DBDataAdapterTaches.Fill(objDBDataSet, "FILLE")
objDBDataSet.EnforceConstraints = True
Call CloseConnection()
AddHandler DBDataAdapterMére.RowUpdated, AddressOf DBAdapterMére_RowUpdate
End Sub