Pb sur TableAdapter.Update -> Vous ne pouvez pas ajouter ou modifier un enregist [Résolu]

v.massip 48 Messages postés mardi 7 octobre 2003Date d'inscription 9 décembre 2008 Dernière intervention - 9 janv. 2008 à 16:35 - Dernière réponse : v.massip 48 Messages postés mardi 7 octobre 2003Date d'inscription 9 décembre 2008 Dernière intervention
- 25 janv. 2008 à 11:16
Bonjour à tous et bonne année 2008 !

Voici mon problème.

Mon appli développée en VB.NET sous VS2005 se connecte à une base de donnée Access.
J'accède aux données et les modifie via un DataSet, des BindingSource et des TableAdapter générés automatiquement lors de l'insertion de la base dans le projet.

Jusque là, pas de problème, j'arrive à créer des enregistrements simples, à les modifier et à les supprimer.

Or, je souhaite sur une fenêtre de mon application pouvoir créer-modifier-supprimer des enregistrements 'composés' venant de 2 tables différentes.

J'ai donc créé la fenêtre suivante :

Chaque tableau pointe sur le BindingSource correspondant à la bonne table.

Les boutons + permettent d'afficher dans le cadre en haut ou en bas le formulaire d'ajout d'un enregistrement (respectivement pour Parent et Enfant).
Les boutons EDIT permettent d'afficher dans le cadre en haut ou en bas le formulaire de modification d'un enregistrement (respectivement pour Parent et Enfant).

Chaque formulaire possède un bouton OK qui valide dans le DataSet les modifications, et un bouton Annuler qui efface le formulaire sans rien faire au niveau des données.

Les boutons - permettent de supprimer un enregistrement (respectivement pour Parent et Enfant).

Le bouton Annuler permet de ne pas enregistrer les modifications dans la base de données (on refuse les changement)
Le bouton Valider permet d'enregistrer les modifications dans la base de données (on accepte les modifications) et de revenir sur la page principale.

Actuellement, cela fonctionne, mais un cas particulier me fait planter l'appli.
En effet, mes 2 tables sont liées, et donc, un enregistrement ENFANT ne peut être créé que si l'enregistrement PARENT existe déjà.
Or, avec l'incrément automatique d'Access (et d'autres SGBD), si l'on a les enregistrements 1-2-3-4 et que l'on supprime le 4, l'incrément auto reprendra alors à 5 (1-2-3-5 si l'on ajoute un nouvel enregistrement).

----------------------------------------
Voici un exemple de mon problème :

1) Situation initiale :
PARENT :
ID-NOM
1-Youpi
2-Youpla
ENFANT :
ID-NOM-ID_PARENT
1-Boum-1
2-Bim-1
3-Ploum-2
4-Plim-2

2) Je supprime l'enregistrement PARENT d'ID=2 --> J'ai une suppression automatique des enregistrements ENFANT d'ID=3 et ID=4 :
PARENT :
ID-NOM
1-Youpi
ENFANT :
ID-NOM-ID_PARENT
1-Boum-1
2-Bim-1

3.1) Je ne valide pas mon formulaire (pas d'enregistrement en base de données) --> Si je rajoute un enregistrement PARENT puis un enregistrement ENFANT qui lui est rattaché, j'obtiens la situation correcte suivante :
PARENT :
ID-NOM
1-Youpi
3-PloumPloum
ENFANT :
ID-NOM-ID_PARENT
1-Boum-1
2-Bim-1
5-Pim-3

3.2.) En revanche, si je valide mon formulaire (enregistrement en base de données) --> Si je rajoute un enregistrement PARENT puis un enregistrement ENFANT qui lui est rattaché, j'obtiens la situation INCORRECTE suivante :
PARENT :
ID-NOM
1-Youpi
2-PloumPloum
ENFANT :
ID-NOM-ID_PARENT
1-Boum-1
2-Bim-1
3-Pim-2

> L'auto incrémentation ne se fait plus correctement.

Cela ne pose pas de problème pour la table PARENT car lors de l'update, l'ID sera automatiquement modifié.
Cependant, cela pose un problème pour la table ENFANT car elle référence alors un enregistrement PARENT qui n'existe plus (ID_PARENT=2 au lieu de ID_PARENT=3).
Lors de l'update, j'obtiens donc le message d'erreur OleDbException suivant : "Vous ne pouvez pas ajouter ou modifier un enregistrement car l'enregistrement associé est requis dans la table 'PARENT'."
----------------------------------------

----------------------------------------
Voici le code utilisé (je ne mets pas les paramètres des procédures pour ne pas trop alourdir) :

Private Sub FRM_Load
        Me.ENFANTTableAdapter.Fill(Me.MYDATASET.ENFANT)
        Me.PARENTTableAdapter.Fill(Me.MYDATASET.PARENT)
End Sub

Private Sub BOUTON_PLUS_Click (La procédure pour la table ENFANT est sur le même modèle)
        If Me.MYDATASET.PARENT.Select("NOM='" & Me.TBX_Nom.Text & "'").Length = 0 Then
            'Si l'enregistrement n'existe pas déjà, on le crée
            Me.MYDATASET.PARENT.AddPARENTRow(Me.TBX_Nom.Text, Me.TBX_Desc.Text)
        Else
            'Sinon, on prévient
            MsgBox("Attention", MsgBoxStyle.Exclamation, "Alerte")
            Me.TBX_Nom.Focus()
        EndIf
End Sub



Private Sub BOUTON_MOINS_Click (La procédure pour la table ENFANT est sur le même modèle)
        If Me.DataGridView_PARENT.SelectedRows.Count <> 1 Then
            'Si aucune ligne n'est sélectionnée
            MsgBox("Sélectionner une ligne", MsgBoxStyle.Exclamation, "Alerte")
        Else
            If MsgBox("Sûr?", MsgBoxStyle.YesNo + MsgBoxStyle.Exclamation, "Alerte") = MsgBoxResult.Yes Then
                'Définition de l'enregistrement à supprimer
                Dim DataToDel As MYDATASET.PARENTRow = MYDATASET.PARENT.FindByID(Me.DGV_PARENT.SelectedRows.Item(0).Cells(0).Value)
                'Suppression de l'enregistrement dans le dataset
                DataToDel.Delete()
            End If
        End If
End Sub

Private Sub BOUTON_EDIT_Click(La procédure pour la table ENFANT est sur le même modèle)
        'Définition de l'enregistrement à modifier
        Dim DataToModif As MYDATASET.PARENTRow = MYDATASET.PARENT.FindByID(Me.DataGridView_PARENT.SelectedRows.Item(0).Cells(0).Value)
        If Me.MYDATASET.PARENT.Select("NOM='" & Me.TBX_Nom.Text & "'").Length = 0 Or _
           DataToModif.NOM = Me.TBX_Nom.Text Then
            'Si l'enregistrement n'existe pas déjà, on le modifie
            DataToModif.NOM = Me.TBX_Nom.Text
            DataToModif.DESCRIPTION = Me.TBX_Desc.Text
        Else
            'Sinon, on prévient
            MsgBox("Attention", MsgBoxStyle.Exclamation, "Alerte")
            Me.TBX_Nom.Focus()
        End If
End Sub

Private Sub BOUTON_ANNULER_Click
        'Rejet des changements effectués sur le dataset
        Me.PNG_ETCreatorDataSet.PARENT.RejectChanges()
        Me.PNG_ETCreatorDataSet.ENFANT.RejectChanges()
        'Retour à la fenêtre principale
        Me.Close()
End Sub

Private Sub BOUTON_VALIDER_Click
        'Sauvegarde des changements dans la base de données
        Me.PARENTTableAdapter.Update(Me.MYDATASET)
        Me.ENFANTTableAdapter.Update(Me.MYDATASET)
        'Retour à la fenêtre principale
        Me.Close()
End Sub
----------------------------------------

> Auriez-vous des idées pour que mes ID dasn mon DataSet s'incrémentent correctement ?

Merci d'avance !
Afficher la suite 

Votre réponse

2 réponses

Meilleure réponse
v.massip 48 Messages postés mardi 7 octobre 2003Date d'inscription 9 décembre 2008 Dernière intervention - 25 janv. 2008 à 11:16
3
Merci
Même si ça n'a l'air d'intéresser personne, voici la solution que j'ai trouvée :
- Visual Studio me génère automatiquement 1 DataSet (DTS), 2 TableAdapter (PARENT_TBA et ENFANT_TBA), 1 BindingSource pointant sur PARENT (PARENT_BSC) et 1 BindingSource pointant sur les ENFANT correspondant au PARENT sélectionné (PARENTENFANT_BSC) lorsque j'insère mes 2 DataGridView (DGV_PARENT et DGV_ENFANT).
- Afin de pouvoir modifier la totalité des enregistrements ENFANT dans mon environnement de modification, j'insère une nouvelle DataGridView (DGV_E) non visible sur la form, ce qui me crée automatiquement un nouveau BindingSource (ENFANT_BSC).

> Donc, lorsque je sélectionne un PARENT dans le premier DataGridView, il n'est uniquement affiché que les ENFANT correspondant dans le second DataGridView. Les enregistrements, modifications ou suppressions se font alors en cascade, ce qui simplifie grandement le code. Le second DataGridView n'affichant qu'une partie des ENFANT disponible, le troisième DataGridView permet toutefois d'y accéder.

Et le code qui va avec :
'Variable permettant d'enregistrer le dernier ID PARENT lors du chargement de la Form puis de le récupérer à la sauvegarde et fermeture de la Form
Private VAR_LastID AsInteger = Nothing
'Chargement de la Form
Private Sub FRM_Load
'Mise à jour des données
Me.PARENT_TBA.Fill(Me.DTS.PARENT)
Me.ENFANT_TBA.Fill(Me.DTS.ENFANT)
'Récupération du dernier ID
Dim PRows() As MYDATASET.PARENT.PARENTRow
PRows = Me.DTS.PARENT.Select()
Me.VAR_LastID = PRows(PRows.Length - 1).ID
End Sub

'Ajout d'un PARENT dans le DGV_PARENT
Private Sub BOUTON_PLUS_Click (La procédure pour la table ENFANT est sur le même modèle)
IfMe.DTS.PARENT.Select("NOM ='" & Me.TBX_Nom.Text & "'").Length = 0 Then
'Si l'enregistrement n'existe pas déjà, on le crée
Me.DTS.PARENT.AddPARENTRow(Me.TBX_Nom.Text, Me.TBX_Desc.Text)
Else
'Sinon, on prévient
MsgBox("Attention", MsgBoxStyle.Exclamation, "Alerte")
Me.TBX_Nom.Focus()
EndIf
End Sub

'Suppression d'un PARENT dans le DGV_PARENT
Private Sub BOUTON_MOINS_Click (La procédure pour la table ENFANT est sur le même modèle)
IfMe.DGV_PARENT.SelectedRows.Count <> 1 Then
'Si aucune ligne n'est sélectionnée
MsgBox("Sélectionner une ligne", MsgBoxStyle.Exclamation, "Alerte")
Else
If MsgBox("Sûr?", MsgBoxStyle.YesNo + MsgBoxStyle.Exclamation, "Alerte") = MsgBoxResult.Yes Then
'Définition de l'enregistrement à supprimer
Dim DataToDel As MYDATASET.PARENTRow = Me.DTS.PARENT.FindByID(Me.DGV_PARENT.SelectedRows.Item(0).Cells(0).Value)
'Suppression de l'enregistrement dans le dataset
DataToDel.Delete()
End If
End If
End Sub

'Edition d'un PARENT du DGV_PARENT
Private Sub BOUTON_EDIT_Click (La procédure pour la table ENFANT est sur le même modèle)
'Définition de l'enregistrement à modifier
Dim DataToModif As MYDATASET.PARENTRow = Me.DTS.PARENT.FindByID(Me.DGV_PARENT.SelectedRows.Item(0).Cells(0).Value)
IfMe.DTS.PARENT.Select("NOM='" & Me.TBX_Nom.Text & "'").Length = 0 Or _
DataToModif.NOM = Me.TBX_Nom.Text Then
'Si l'enregistrement n'existe pas déjà, on le modifie
DataToModif.NOM = Me.TBX_Nom.Text
DataToModif.DESCRIPTION = Me.TBX_Desc.Text
Else
'Sinon, on prévient
MsgBox("Attention", MsgBoxStyle.Exclamation, "Alerte")
Me.TBX_Nom.Focus()
End If
End Sub

'Annulation des différentes modifications apportées à PARENT et ENFANT
Private Sub BOUTON_ANNULER_Click
'Rejet des changements effectués sur le dataset
Me.DTS.PARENT.RejectChanges()
Me.DTS.ENFANT.RejectChanges()
'Retour à la fenêtre principale
Me.Close()
End Sub

'Enregistrement des modifications apportées à PARENT et ENFANT
Private Sub BOUTON_VALIDER_Click
'Définition des variables de test
Dim VAR_TabID_BS AsNew Collection 'BS = BeforeSave
Dim VAR_TabID_AS AsNew Collection 'AS = AfterSave
'Tri des enregistrement par ID ... On ne sait jamais !
Me.DGV_PARENT.Sort(Me.DGV_PARENT.Columns(0), System.ComponentModel.ListSortDirection.Ascending)
'Enregistrement des ID des PARENT avant la sauvegarde
ForEach DgvRow As DataGridViewRow InMe.DGV_PARENT.Rows
If DgvRow.Cells(0).Value > Me.VAR_LastID Then VAR_TabID_BS.Add(DgvRow.Cells(0).Value)
Next
'Enregistrement des PARENT
Me.PARENT_TBA.Update(Me.DTS)
'Récupération des nouveaux ID access dans le DGV_PARENT
Me.PARENT_TBA.Fill(Me.DTS.PARENT)
'Enregistrement des ID des PARENT après la sauvegarde
ForEach DgvRow As DataGridViewRow InMe.DGV_PARENT.Rows
If DgvRow.Cells(0).Value > Me.VAR_LastID Then VAR_TabID_AS.Add(DgvRow.Cells(0))
Next
'Modification, le cas échéant, des ENFANT pour un enregistrement correct (traitement sur la totalité des enregistrements ENFANT donc via la DataGridView DGV_E2)
Dim i AsInteger = 0
For i = VAR_TabID_BS.Count To 1 Step -1
If VAR_TabID_BS.Item(i) <> VAR_TabID_AS.Item(i) Then
ForEach DGVRow As DataGridViewRow InMe.DGV_E.RowsIf DGVRow.Cells(2).Value VAR_TabID_BS.Item(i) Then DGVRow.Cells(2).Value VAR_TabID_AS.Item(i)
Next
EndIf
Next
Try
'Enregistrement des ENFANT
Me.ENFANT_TBA.Update(Me.DTS)
CatchexAsDBConcurrencyException
'Gestion de l'accès concurrentiel ==> On laisse faire
'C'est une erreur spécifique due au fait que je modifie un enregistrement enfant avant de l'enregistrer :
'Ce n'est pas très propre mais je n'ai trouvé que cette solution pour que cela marche fonctionnellement.
EndTry
'Retour à la fenêtre principale
Me.Close()
End Sub

Merci v.massip 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 69 internautes ce mois-ci

Commenter la réponse de v.massip
v.massip 48 Messages postés mardi 7 octobre 2003Date d'inscription 9 décembre 2008 Dernière intervention - 9 janv. 2008 à 16:43
0
Merci
Petit raté sur l'image, elle se trouve ici.
Commenter la réponse de v.massip

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.