IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

[DataSet] Update une table oracle dynamiquement


Sujet :

VB.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Avril 2010
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Avril 2010
    Messages : 52
    Par défaut [DataSet] Update une table oracle dynamiquement
    Hello tout le monde!

    Donc voici mon petit défi du moment sur lequel je plante depuis quelques heures... !

    J'ai les mêmes tables sur une DB Access qui est utilisée lorsque l'application est locale, sur un portable, pour des usagers en déplacement.

    Lorsque ces mêmes usagers reviennent parmi nous, ils peuvent (doivent) synchronisé leurs données avec nos BD Oracle serveur.

    J'ai donc exactement le même schema Access et Oracle, et je dois récupéré les données d'Access plus récentes dans Oracle.

    Je me suis dit, allez, soyons fou, ce sont les même tables, il doit avoir moyen d'évité de se taper 12 Select/Insert/Update avec ADO.NET.

    Voici mon bout de code actuel;`

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    'Opérations de transfert
                Dim TableAcc As DataTable
                Dim TableOra As DataTable
                Dim Requetes() As String = {Array de nom des tables}
                Dim ds As New DataSet
                For x As Integer = 0 To Requetes.Length - 1
    'Appel des fonctions SELECT stockées sous l'appélation "Transfert_nomtable"
                    Dim ressource As String = "Transfert_" + Requetes(x)
                    Dim rm As New ResourceManager("ApplicationTransfert.RequeteAccess", Assembly.GetExecutingAssembly)
                    Dim sql As String = rm.GetString(ressource)
                    TableAcc = connAccess.executerRequete(sql, CommandType.Text)
                    TableOra = connOra.executerRequete(sql, CommandType.Text)
                    For Each row As DataRow In TableAcc.Rows
                        Dim conflit As Boolean
                        For Each rowOra As DataRow In TableOra.Rows
    'On compare les premieres colonnes, qui sont toutes le ID
    'On vérifie donc qu'il n'y a pas eu de modifications faites en local
                            If rowOra.Item(0).ToString = row.Item(0).ToString Then
                                conflit = True
                            End If
                        Next
                        If Not conflit Then
                            TableOra.ImportRow(row)
                        Else
                            ' Gestion des conflits encore a faire - pas d'existants encore
                        End If
                    Next
                    ds.Tables.Add(TableOra)
                Next
                ' On applique les modifications sur la Table Oracle
                Dim adapter As New Oracle.DataAccess.Client.OracleDataAdapter("SELECT 1 FROM DUAL", ApplicationSomVac.obtenirConnexionOracle.connexionString.ConnectionString)
                adapter.Fill(ds)
                Dim commbuilder As New Oracle.DataAccess.Client.OracleCommandBuilder(adapter)
                For Each dstable As DataTable In ds.Tables
                    adapter.Update(ds, dstable.TableName)
                Next
                MessageBox.Show("La synchronisation à été effectuée avec succès!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
    et je remettrais donc l'accent sur ce bout de code LÀ:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    ' On applique les modifications sur la Table Oracle
                Dim adapter As New Oracle.DataAccess.Client.OracleDataAdapter("SELECT 1 FROM DUAL", ApplicationSomVac.obtenirConnexionOracle.connexionString.ConnectionString)
                adapter.Fill(ds)
                Dim commbuilder As New Oracle.DataAccess.Client.OracleCommandBuilder(adapter)
                For Each dstable As DataTable In ds.Tables
                    adapter.Update(ds, dstable.TableName)
                Next
                MessageBox.Show("La synchronisation à été effectuée avec succès!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
    je sais pas trop pourquoi j'ai un select dual, le adapter.fill me déclenchait une erreur comme quoi je n'avais pas de Select Command en place. Ça fait parti de mes essais sans résultat... mais c'est le code dans lequel je suis actuellement.

    Donc voilà... au final tout ce que je cherche a faire c'est planté les données stockés dans le DataSet "ds" dans ma DB Oracle. Y'a surement un petit truc dans le jeu DataSet/Adapter/Source[...] que j'ai zappé, mais j'arrive pas a comprendre où/comment/pourquoi. J'ai rechercher pas mal sur le web, et je vois leurs bout de code presque identique au miens, et tout semble fonctionner chez eu, ca m'énerve un peu

    Merci d'avance pour le coup de main,
    Amuny.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    le CommandBuilder se base sur la SelectCommand pour savoir comment générer les autres commandes, donc si tu lui passes juste "SELECT 1 FROM DUAL", il ne risque pas de deviner ce qu'il doit faire... Tu ne lui donnes même pas le nom de la table, donc ça risque pas de marcher.

    A la limite tu peux faire "SELECT * FROM <nom de la table>", et ça devrait passer...

  3. #3
    Membre averti
    Homme Profil pro
    Inscrit en
    Avril 2010
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Avril 2010
    Messages : 52
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
                ' On applique les modifications sur la Table Oracle
                For Each dstable As DataTable In ds.Tables
                    Dim adapter As New Oracle.DataAccess.Client.OracleDataAdapter("SELECT * FROM " & dstable.TableName, ApplicationSomVac.obtenirConnexionOracle.connexionString.ConnectionString)
     
                    Dim commbuilder As New Oracle.DataAccess.Client.OracleCommandBuilder(adapter)
                    adapter.Update(ds, dstable.TableName)
                Next
    J'en suis donc a ça.

    J'ai vérifié avec les breakpoints et les spy... mon DS contient bien les données d'Access que je veux mettre dans oracle.

    C'est l'histoire du dataadapter avec lequel je suis pas trop a l'aise et je ne comprend pas vraiment ce que devrais faire / comment fonctionne le .Update(dataset, tablename)

    Il me semblait qu'il allait trouver les différences entre le DSet et lui-même et faire un update... mais au final il semble faire... rien du tout

    Du coup j'ai les données que je veux... mais j'arrive pas a mettre sur pied une bonne procédure pour atteindre mon objectif

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Bah un DataAdapter ne travaille que sur les lignes qui sont chargées dedans... mais comme tu ne fais pas de Fill, il n'y a rien à mettre à jour.

    En fait ce que tu cherches à faire n'est pas si simple... ça peut se faire, mais il y a quelques contraintes :

    - Il ne faut pas que les tables soient trop grosses, sinon tu ne pourras pas tout charger dans une DataTable
    - Il faut que la table ait une clé primaire

    En gros, voilà ce qu'il faut faire :
    • Crée une DataTable
    • Crée un DataAdapter pour la table de la base 1 (Access), et change la propriété AcceptChangesDuringFill à false. C'est très important, sinon les lignes seront marquées comme non modifiée dans la DataTable, et elle ne seront pas prises en compte pour l'update sur l'autre base.
    • Remplis la DataTable (Fill)
    • Définis la PrimaryKey pour la DataTable. Très important aussi, sinon le Fill à partir de l'autre table ne saura pas quelles lignes sont équivalentes
    • Crée un DataAdapter pour la table de la base 2 (Oracle) ; cette fois, ne touche pas à la propriété AcceptChangesDuringFill (qui est à true par défaut). Par contre, change la propriété FillLoadOption pour mettre la valeur PreserveChanges (de façon à ne pas écraser les valeurs actuellement dans la table)
    • Crée un CommandBuilder pour le DataAdapter
    • Remplis de nouveau la DataTable (Fill) avec le nouveau DataAdapter. Les lignes qui existent dans les 2 bases seront marquées comme modifiées; celles qui existent dans 1 et pas dans 2 seront marquées comme ajoutées ; celles qui sont dans 2 et pas dans 1 seront marquées comme non-modifiées
    • Pour finir, mets à jour la table dans la base 2 avec adapter.Update


    A noter quand même : avec cette technique les modifs de la base 1 sont prioritaires sur celles de la base 2, donc si une ligne a été modifiée séparément dans les 2 bases, c'est les modifs de la base 1 qui sont conservées. Et bien sûr ça n'ajoute pas à la base 1 les lignes de la base 2 qui sont absentes de la base 1.

    Je ne garantis pas que ça marche dans ton cas, mais j'ai fait un test rapide avec 2 bases SQLite, et ça semble bien se passer...

    Au début je te conseille de faire l'update dans une transaction que tu rollback à la fin, pour pas risquer de foutre en l'air ta base. Tu peux surveiller les instructions exécutées en gérant l'évènement RowUpdated du DataAdapter (ça contient la ligne concernée et la commande SQL)

  5. #5
    Membre averti
    Homme Profil pro
    Inscrit en
    Avril 2010
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Avril 2010
    Messages : 52
    Par défaut
    Citation Envoyé par tomlev Voir le message
    [...]

    A noter quand même : avec cette technique les modifs de la base 1 sont prioritaires sur celles de la base 2, donc si une ligne a été modifiée séparément dans les 2 bases, c'est les modifs de la base 1 qui sont conservées. Et bien sûr ça n'ajoute pas à la base 1 les lignes de la base 2 qui sont absentes de la base 1.

    Je ne garantis pas que ça marche dans ton cas, mais j'ai fait un test rapide avec 2 bases SQLite, et ça semble bien se passer...

    Au début je te conseille de faire l'update dans une transaction que tu rollback à la fin, pour pas risquer de foutre en l'air ta base. Tu peux surveiller les instructions exécutées en gérant l'évènement RowUpdated du DataAdapter (ça contient la ligne concernée et la commande SQL)
    C'est une partie du problème, ce n'est pas toujours le cas.

    C'est pourquoi j'ai mon bloc de code d'en haut, qui me permet de construire un DataSet avec toutes mes Tables a jour.

    L'étape qui me manque c'est vraiment celle de "pluggé" le DataSet et ses tables dans la base Oracle. Et ce DataSet construit presque ligne par ligne lui pourra avoir priorité sur la BD puisqu'il y aura déjà eu les vérifications nécessaire de faites.

    Rendu là l'objectif est presque de "remplacer" la BD par un DataSet, ou plus optimalement (?) de trouver les différence entre le DataSet et la BD actuelle et d'appliquer les modifications nécessaire pour qu'ils soient pareil.

    Sois ça, ou trouver un moyen de faire l'insertion/update dynamique d'une ligne en ayant un DataRow et le nom de la table ... ? (qui irait se placer directement dans le code du haut et remplacer la construction du fameux DataSet)

    Après y'a peut être une grosse lacune d'analyse dans ma tête, mais considérant que j'ai 12tables identique de chaque côté, et que la seule manière de validé si une ligne a la priorité sur une autre c'est par une procédure ou j'ai besoin de la clé de la dite ligne... c'est là que j'en suis arrivé. Mais je suis très loin d'être parfait

  6. #6
    Membre averti
    Homme Profil pro
    Inscrit en
    Avril 2010
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations forums :
    Inscription : Avril 2010
    Messages : 52
    Par défaut
    J'ai retravailler la chose, mais je réalise un de mes problème.
    Apparemment, mon DataTable.GetChanges ne retourne rien, donc forcément, il update rien.

    J'ai essayer de bouger un peu les trucs pour rassembler ca dans les même boucles; même résultat. GetChanges ne me retourne rien.

    On dirais que le DataTable.ImportRow(DataRow) n'est pas considéré comme une modification, et donc, ne change rien a ma table lorsque je fais un update... ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
                    TableAcc = connAccess.executerRequete(sql, CommandType.Text)
                    'TableOra = connOra.executerRequete(sql, CommandType.Text)
                    Dim adapter As New Oracle.DataAccess.Client.OracleDataAdapter(sql, connOra.connexionString.ConnectionString)
                    adapter.Fill(TableOra)
                    Dim comm As New Oracle.DataAccess.Client.OracleCommandBuilder(adapter)
                    For Each row As DataRow In TableAcc.Rows
                        Dim conflit As Boolean
                        For Each rowOra As DataRow In TableOra.Rows
                            If rowOra.Item(0).ToString = row.Item(0).ToString Then
                                conflit = True
                            End If
                        Next
                        If Not conflit Then
                            TableOra.ImportRow(row)
                        Else
                             'Gestion conflit
                        End If
                    Next
                    Dim dt As DataTable
                    dt = TableOra.GetChanges()
                    adapter.UpdateCommand = comm.GetUpdateCommand()
                    adapter.Update(TableOra)
                    'ds.Tables.Add(TableOra)

Discussions similaires

  1. Update sur une Table Oracle
    Par faressam dans le forum VBScript
    Réponses: 3
    Dernier message: 18/09/2008, 10h01
  2. Réponses: 4
    Dernier message: 05/12/2007, 19h06
  3. [C#/ADO.NET] Comment Updater une table via Datagrid ?
    Par Pierre_45 dans le forum Accès aux données
    Réponses: 4
    Dernier message: 06/07/2006, 11h40
  4. Réponses: 5
    Dernier message: 08/03/2006, 03h42
  5. supprimer un enregistrement vide dans une table oracle
    Par shurized dans le forum Bases de données
    Réponses: 11
    Dernier message: 07/09/2004, 16h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo