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

Accès aux données Discussion :

Violation d'accès concurrentiel sur dt avec champs null + mise à jour champs père/fils dans une meme transac


Sujet :

Accès aux données

  1. #1
    Membre actif
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Mars 2008
    Messages : 464
    Points : 268
    Points
    268
    Par défaut Violation d'accès concurrentiel sur dt avec champs null + mise à jour champs père/fils dans une meme transac
    Bonjour,
    J'ai deux problèmes assez embêtant.

    Le premier est la gestion de l'accès conurentiel sur une mise à jour de table dans la BD. Je précise que je ne lis et modifie aucun champs de format date ou de floatant. Le problème est différent.

    Voilà j'utilise une base de données RDB (aucune importance) en ODBC.
    Et j'ai une requête du type

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    sqltext = "SELECT champs1, champs2, champs3 " +
                 "FROM table " +
                 "WHERE champs1 = ?"
    Ma requête de select fonctionne bien et ma dataTable me retourne des valeurs.
    Sauf que ... le champs 3 peut contenir une valeur NULL (j'ai le droit)

    Du coup quand je fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    bldr = new OdbcCommandBuilder(myDataAdapter)
    myDataAdapter.update(myDataSet.Tables[myTableToUpdate]
    j'ai une exception de type Accès concurentiel.

    Je pense que c'est dans mon champs nul (même si je ne le met pasd à jour car la commande de mon OdbcBuilder fait une requete de type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    "UPDATE table SET Champs1= ?, Champs2= ?, Champs3=   WHERE ((Champs1= ?) AND (Champs2= ?) AND (Champs3= ?) "
    Et Champs3 = null : je ne suis pas sur qu'il interprête ceci correctement.


    Mon deuxième problème est une violation de contrainte.
    En effet je veux mettre à jour plusieurs tables dans la meme transaction sauf que un des champs que je souhaite mettre à jour est un champs fils d'une table et je souhaite également mettre à jour le champs père de l'autre table.
    Je me suis dit naïvement que si je traite cette mise à jour dans la meme transaction je n'aurai pas de problème de violation de contrainte ... Apparemment ce n'est pas le cas.


    Quelqu'un peut il m'aider sur ces sujets ou à défaut me proposer un contournement.

    Merci

  2. #2
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Voilà ce que je fais:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    UPDATE table SET Champs1= ?, Champs2= ?, Champs3=?   
       WHERE (Champs1= ?) AND (Champs2= ?) AND
                  ((Champs3= ?) OR ((Champs3 IS NULL) AND (? IS NULL)))
    Mais, si il y a plus simple je suis preneur.

    Mon deuxième problème est une violation de contrainte.
    Le fait d'utiliser ou non une transaction n'a aucun impact.
    Les UPDATE sont-ils fait dans le bon ordre?
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  3. #3
    Membre actif
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Mars 2008
    Messages : 464
    Points : 268
    Points
    268
    Par défaut
    Pour les champs avec des nulls je m'attendais à ta réponse et en suis navré car je ne sais comment remplir les ? quand il y a n rows à modifier.

    Quant aux violation de contraintes : faut il faire fils avant parent ou parent avant fils ? Car si c'est fils avant parent c'est ce que j'ai fait et ça ne marche pas

    J'ai une table TABLE1 avec Champs1 et Champs 2 (Champs1 étant PRIMARY KEY) et une table TABLE2 avec ChampsA, ChampsB et ChampsC avec ChampsC FOREIGN KEY sur le Champs1 de la table Table1...
    Et je souhaite mettre en meme temps le Champs1 de la TABLE1 et le ChampsC de la TABLE2.
    Comment dois je procéder sans faire de DELETE et INSERT?

  4. #4
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    J'ai une table TABLE1 avec Champs1 et Champs 2 (Champs1 étant PRIMARY KEY) et une table TABLE2 avec ChampsA, ChampsB et ChampsC avec ChampsC FOREIGN KEY sur le Champs1 de la table Table1...
    Heureusement, pas de foreign key croisées....
    Donc, Update table 1, puis update table2.

    j'en suis navré car je ne sais comment remplir les ?
    A chaque "?", tu ajoutes un paramètre. Dans le cas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    UPDATE table SET Champs1= ?, Champs2= ?, Champs3=?   
       WHERE (Champs1= ?) AND (Champs2= ?) AND
                  ((Champs3= ?) OR ((Champs3 IS NULL) AND (? IS NULL)))
    ...
    3 params standard nouvelle valeur pour champs 1,2,3
    3 params avec ancienne valeur pour champs 1,2,3(avec "oldparam.SourceVersion=DataRowVersion.Original" si DataAdapter)
    1 param avec ancienne valeur pour champs 3
    quand il y a n rows à modifier.
    Soit tu travailles avec DataTable et DataAdapter et il il y a juste à définir l'updatecommand de chaque table.
    Soit tu travailles en créant/exécutant directement une commande simple ou multiple et tu définis autant de paramètres que de ? dans la(les) commande(s).
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  5. #5
    Membre actif
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Mars 2008
    Messages : 464
    Points : 268
    Points
    268
    Par défaut
    Merci je crois que je vais avoir me débrouiller : je te tiens au courant mais ça me parait crédible comme solution... Même si ça complexifie mon code car je n'ai qu'une classe qui met à jour les BD (elle fonctionne en générique)...
    Je te tiens au courant quand je testerai

  6. #6
    Membre actif
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Mars 2008
    Messages : 464
    Points : 268
    Points
    268
    Par défaut
    J'ai tout de même une question à poser :
    Ok pour un ordre SQL de type
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    "UPDATE table SET champs1 = ?, champs2 = ?, champs3 = ? " +
    "WHERE  (champs1 = ? or champs1 IS NULL and ? IS NULL ) and " + 
    "           (champs2 = ? or champs2 IS NULL and ? IS NULL ) and " +
    "           (champs3 = ? or champs3 IS NULL and ? IS NULL )"
    Ca ça me va très bien... Mais voilà en face j'ai un DataTable qui va bien avec sa collection de rows et de column.. Tout est OK

    Mais...
    Avec quoi je remplit mon adapter. Est ce que tu peux donner un exemple.
    Je m'explique la commande de la UPDATECOMMANDE est vrai pour tous les rows de la datatable. Or si je veux la version original d'un paramètre dans la clause where, cette propriété est définie dans la classe row.

    Cela veut il dire que je dois faire un enregistrement ligne à ligne.

    Exemple : imaginons ma table "table". Imaginons que je souhaite mettre les enregistrements où champs1 contient "A" et "B". Je souhaite remplacer "A" par "C" et "B" par "D". J'ai donc deux enregistrement à mettre à jour.

    Question comment seront paramétrés mes paramètres de mon adapter

  7. #7
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Question comment seront paramétrés mes paramètres de mon adapter
    La commande est paramétrée pour une ligne unique.
    C'est le DataSet/DataTable qui s'occupe de créér/exécuter les requètes pour toutes les lignes ajoutées, modifiées ou supprimées.

    De mémoire, on fait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    MyDataAdapter.Update(MyDataSet) ;
    MyDataTable.AcceptChanges();
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  8. #8
    Membre actif
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Mars 2008
    Messages : 464
    Points : 268
    Points
    268
    Par défaut
    Bon j'ai essayé de faire ainsi : création de mon ObdcCommandBuilder avec Mon Data Adapter.
    J'ai ensuite redéfinie la UpdateCommande de mon DataAdapter pour inclure la possibilité de champs null mais ....


    J'ai un problème de transaction...


    Alors autant ma transaction fonctionne quand je travaille avec mon OdbcCommandBuilder sans redéfinition de la UpdateCommande autant quand je redéfinit celle ci et que le lui affecte la transaction qui va bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MyAdapter.UpdateCommand.Transaction = Transaction /*Transaction définie avt*/
    Rien ne va plus

  9. #9
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MyAdapter.UpdateCommand.CommandText = Transaction /*Transaction définie avt*/
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  10. #10
    Membre actif
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Mars 2008
    Messages : 464
    Points : 268
    Points
    268
    Par défaut Pour mettre les idées au clair
    Bon voilà comment j'ai procédé :

    Admettons ma fameuse table mytable avec 2 champs : col1, col2.

    Je souhaite mettre les lignes à jour suivantes :
    row 1 : (col1=1, col2 = Null) à remplacer par (col1 = 2, col2=Null)
    row 2 : (col1=3, col2 = Null) à remplacer par (col1 = 4, col2=Null)


    Voilà le bout de code écrit :

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
     
    //// Partie du code correspond à la sélection
     
    // Ma chine de connexion définit dans le settings du projet
    private OdbcConnection maCnx=Systems.Settings.Default.ChaineConnexion;
     
    // Transaction
    private OdbcTransaction maTrans= maCnx.BeginTransaction();
     
    // Ma Commande pour le select
    private OdbcCommand maCmd = new OdbcCommand();
     
    // Mon Adapter
    private OdbcDataAdapter myAdp;
     
    // Mon DataSet de remplissage
    private DataSet myDS = new DataSet();
     
    // Paramétrage de ma commande:
    Cmd.Connection = maCnx;
    Cmd.CommandType=CommandType.Text;
    Cmd.CommandText = "SELECT * FROM mytable";
    Cmd.Transaction = maTrans;
     
    myAdp = new OdbcDataAdapter(Cmd);
    myAdp.Fill(DS, "MaTable");
     
    // Fermeture de la transaction
    maTrans.Rollback();
     
    //// Partie du code ou je modifie mes DataRow
    foreach (DataRow dr in DS.Tables["MaTable"].Rows)
    {
        if ((int)dr["col1"]==1)
              dr["col1"] = (int)2;
        if ((int)dr["col1"]==3)
              dr["col1"] = (int)4;
    }
     
    //// Partie du code ou je met à jour la base de données
    /* maTrans = maCnx.BeginTransaction();
        myCmd.Trans = maTrans;
        OdbcCommandBuilder bldr = new OdbcCommandBuilder(myAdp);
        myAdp.Update(DS.Table["maTable"]);
    Si j'avais fonctionné de la sorte ça n'aurait pas marché pour cause de violation d'accès concurentiel. En effet : ma commande updateCommande de mon DataAdapter à une commandText de la façon suivante : (je l'ai vu en debug) ; "UPDATE mytable set col1= ?, col2 = ? where col1 = ? and col2 = ?"
    Si ma valeur originale de col2 = Null, il ne sait pas tester correctement le test.
    J'ai donc redéfinit l'update command de la manière suivante : */
     
    myAdp.UpdateCommand = new OdbcCommand();
    myAdp.UpdateCommand.Connexion = maCnx;
    maTrans = maCnx.BeginTransaction();
    myAdp.Transaction = maTrans;
    myAdp.UpdateCommand.CommandText = "UPDATE mytable SET col1 = ? " +
                                                           " WHERE col1 = ?, (col2 = ? or " +
                                                           " col2 IS NULL and ? IS NULL";
     
    //Configuration de mes paramètres
    OdbcParameter Prm = new OdbcParameter();
    Prm.SourceVersion = DataRowState.Current;
    Prm.SourceColumn = DS.Tables["MyTable"].Columns["col1"].ColumnName;
    myAdp.UpdateCommand.Parameters.Add(Prm);
     
    Prm = new OdbcParameter();
    Prm.SourceVersion = DataRowState.Originale;
    Prm.SourceColumn = DS.Tables["MyTable"].Columns["col1"].ColumnName;
    myAdp.UpdateCommand.Parameters.Add(Prm);
     
    Prm = new OdbcParameter();
    Prm.SourceVersion = DataRowState.Originale;
    Prm.SourceColumn = DS.Tables["MyTable"].Columns["col2"].ColumnName;
    myAdp.UpdateCommand.Parameters.Add(Prm);
     
    Prm = new OdbcParameter();
    Prm.SourceVersion = DataRowState.Originale;
    Prm.SourceColumn = DS.Tables["MyTable"].Columns["col2"].ColumnName;
    myAdp.UpdateCommand.Parameters.Add(Prm);
     
    // Lancement de la requete
    myAdp.UpdateCommand.ExecuteNonQuery();
    Je me suis inspiré de ce que tu m'avais présenté pour configurer mes paramètres

    En fonctionnant de la sorte; je suis content de ne pas avoir d'erreur mais ...
    En fait j'enregistre rien du tout et ça me parait normal car à aucun moment dans la configuration de mes paramètres je lie mes paramètres à ma collection de DataRow précédemment sélectionné dans ma requete de SELECT et modifié dans mon programme.

  11. #11
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    // Lancement de la requete
    myAdp.UpdateCommand.ExecuteNonQuery();
    Cette ligne est inutile.
    c'est la commande myAdp.Update(DS) qui exécute automatiquement les instructions SQL de mise à jour (UPDATE, INSERT et DELETE) de ta table du DataSet.

    Donc, la solution serait de modifier myAdp.UpdateCommand
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    OdbcCommandBuilder bldr = new OdbcCommandBuilder(myAdp);
    myAdp.UpdateCommand = new OdbcCommand();
    myAdp.UpdateCommand.Connexion = maCnx;
    myAdp.UpdateCommand.CommandText = 
      "UPDATE mytable SET col1 = ? " +
      " WHERE col1 = ?, (col2 = ? or " +
      " col2 IS NULL and ? IS NULL";
    //Configuration de mes paramètres (ton code)
    ... 
    // et pour valider les modif de la DataTable :
    myAdp.Update(DS);
    DS.Table["maTable"].AcceptChanges();
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  12. #12
    Membre actif
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2008
    Messages
    464
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Mars 2008
    Messages : 464
    Points : 268
    Points
    268
    Par défaut
    C'est ce que je pensais faire au début. Mais il s'avère que dans ce cas j'a un problème de transaction même si je paramètre la Transaction de mon UpdateCommand de mon DataAdapter ou si, plus simplement, je paramètre la transaction de ma Command (celle avec laquelle la DataAdapter a été initialisé)

    Du coup je ne sais pas bien quoi faire.

    Ceci dit je dois être franc : la base que j'attaque en Odbc est une base RDB (une vieille base de données de Digital sur system VAX/VMS). J'ai testé la commande DataAdapter.Update avec une base Access en Odbc (et non en Oledb) avec des champs null et dans ce cas je n'ai pas eu de problème.

    Je me demande s'il ne s'agit pas de la base. J'aimerai testé en simulant une base en Odbc avec Excel (avec champs null : je ne sais pas comment en simule un champs null avec des cellules).

  13. #13
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Les "?" marchent dans Access. Mais pour d'autres bases, c'est différent : on nomme les paramètres.
    • En Oracle, on remplace "?" par ":Nom_du_param"
    • En mySQL et dans la plupart des SGBD, on remplace "?" par "@Nom_du_param"
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

Discussions similaires

  1. Réponses: 0
    Dernier message: 27/01/2010, 18h04
  2. Accès concurrentiel sur une base SQL Server 2005
    Par Nixar dans le forum ASP.NET
    Réponses: 6
    Dernier message: 21/07/2008, 17h07
  3. Liste déroulante avec mise à jour champ en dynamique
    Par B-Pascal dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 05/07/2006, 15h53
  4. INSTR sur un champ vide, Detecter un champ null
    Par rodolphedj dans le forum ASP
    Réponses: 4
    Dernier message: 06/09/2004, 15h24

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