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

Bases de données Delphi Discussion :

[ADO&SQLSERVER] Problème avec la propriété RowsAffected et les Trigger


Sujet :

Bases de données Delphi

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut [ADO&SQLSERVER] Problème avec la propriété RowsAffected et les Trigger
    Bonjour,

    Dans le cadre d'une migration BDE vers les ADO, je rencontre le problème
    suivant:

    Après un ExecSQL , la valeur que me retourne RowsAffected n'est pas correcte.

    En regardant de plus près, je me suis aperçu que cette table possède un trigger sur les insertions qui effectue plusieurs mise à jour.

    La valeur retournée par RowsAffected est dans ce cas précis le nombre de lignes manipulées par le premier trigger et non par mon insert initial. Ce qui ne fait pas du tout mon affaire.

    Bien entendu : Ce problème ne se pose avec le BDE, qui lui renvoie la bonne valeur.

    Peut être avez vous une idée pour résoudre, ou contourner ce problème ?

    Je vous remercie

    Pour info : j'utilise les TADOQUERY, et je travaille avec Delphi 7.1 et SQLServer 7.
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut
    Pour contourner ce problème, je reprends pour le moment la requête de mise à jour pour en faire un select et récupérer le recordcount. (Qui lui me donnera la valeur qu'aurait du me communiquer le rowsaffected)

    Mais cela n'est pas possible pour toutes les situations, et notamment sur les
    requêtes dynamiques. De plus , passer 2 requêtes au lieu d'une seule ce n'est vraiment pas extra.

    Si vous avez une autre solution ? , je suis vraiment preneur.

    Merci

    A+
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

  3. #3
    Modérateur
    Avatar de Rayek
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2005
    Messages
    5 235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 235
    Points : 8 504
    Points
    8 504
    Par défaut
    Peux tu nous montrer ton code ?

    La récupération du nombre d'enregistrements modifiés est elle importante pour le programme ?
    Modérateur Delphi

    Le guide du bon forumeur :
    __________
    Rayek World : Youtube Facebook

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut
    Bonjour Rayek,

    La récupération du nombre d'enregistrements est effectivement importante.

    Je te prépare un exemple montrant l'erreur constatée.

    A+
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut
    Re bonjour

    Voici un exemple simple qui vous permettra de reproduire facilement le problème que je constate.

    Je vous laisse le soin de poser sur la form les composants Tadoconnection (ici ADOConnection) et Tdatabase (ici 'BDE') et de les connecter à une base SQL Serveur.
    Vous n'avez plus ensuite qu'à coller le code suivant derrière 3 boutons.

    Voici un premier code à executer pour préparer les données

    Création de 2 tables matable_1, matable_2.
    Création d'un trigger sur la matable_1, et insertion de 2 lignes dans matable_2.

    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
     
    procedure TForm1.PreparationClick(Sender: TObject);
    var MaRequete: TADOQuery;
    begin
     
      MaRequete := TADOQuery.Create(Self);
      try
        MaRequete.Connection := ADOConnection;
     
        // 0*** Nettoyage des tables (inclus du trigger) si nécessaire
     
         MaRequete.SQL.Add('SELECT name FROM sysobjects WHERE type=''U'' and name = ''matable_1''');
         MaRequete.Open;
         if MaRequete.RecordCount > 0 then
         begin
           MaRequete.Close;
           MaRequete.SQL.Clear;
           MaRequete.SQL.Add('drop table matable_1');
           MaRequete.ExecSQL;
         end;
     
         if MaRequete.Active then MaRequete.Close;
         MaRequete.SQL.Clear;
         MaRequete.SQL.Add('SELECT name FROM sysobjects WHERE type=''U'' and name = ''matable_2''');
         MaRequete.Open;
         if MaRequete.RecordCount > 0 then
         begin
           MaRequete.Close;
           MaRequete.SQL.Clear;
           MaRequete.SQL.Add('drop table matable_2');
           MaRequete.ExecSQL;
         end;
     
        // 1*** Création de la table 1 et de son trigger
        if MaRequete.Active then MaRequete.Close;
        MaRequete.SQL.Clear;
        MaRequete.SQL.Add('CREATE TABLE matable_1(col_1 INT)');
        MaRequete.ExecSQL;
     
        if MaRequete.Active then MaRequete.Close;
        MaRequete.SQL.Clear;
        MaRequete.SQL.Add(
        'create trigger mon_trigger_en_insertion on matable_1 '+
        'for insert as '+
        'begin '+
        'update matable_2 set matable_2.col_1 = 2 '+
        'update matable_2 set matable_2.col_1 = 2'+
        ' end');
        MaRequete.ExecSQL;
     
        // 2*** Création de la table 2 et insert de quelques lignes
        if MaRequete.Active then MaRequete.Close;
        MaRequete.SQL.Clear;
        MaRequete.SQL.Add('CREATE TABLE matable_2(col_1 INT)');
        MaRequete.ExecSQL;
     
        if MaRequete.Active then MaRequete.Close;
        MaRequete.SQL.Clear;
        MaRequete.SQL.Add('insert into matable_2 values(2)');
        MaRequete.ExecSQL;
        MaRequete.ExecSQL; // insertion d'une deuxième ligne
     
    finally
      MaRequete.Free;
    end;
     
    end;
    Ensuite après avoir executer le code précédent, on effectue une insertion (une seule ligne) dans la table matable_1

    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
    procedure TForm1.ADOClick(Sender: TObject);
    var MaRequete: TADOQuery;
    begin
     MaRequete := TADOQuery.Create(Self);
     try
        MaRequete.Connection:=ADOConnection;
    
        // 3*** Insertion dans la table 1 et controle de ROWSAFFECTED
        if MaRequete.Active then MaRequete.Close;
        MaRequete.SQL.Clear;
        MaRequete.SQL.Add('insert into matable_1 values(1)');
        MaRequete.ExecSQL;
        //4*** Resultat ADO
        ShowMessage(IntToStr(MaRequete.rowsaffected)); //  Resultat 2
     finally
       MaRequete.Free;
     end;
    end;
    On constate que rowsaffected renvoie 2 au lieu de 1.

    Alors que si l'on execute le même code avec le BDE

    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
    procedure TForm1.BDEClick(Sender: TObject);
    var MaRequete: TQuery;
    begin
     MaRequete := TQuery.Create(Self);
     try
        MaRequete.DatabaseName:='BDE';
    
        // 3*** Insertion dans la table 1 et controle de ROWSAFFECTED
        if MaRequete.Active then MaRequete.Close;
        MaRequete.SQL.Clear;
        MaRequete.SQL.Add('insert into matable_1 values(1)');
        MaRequete.ExecSQL;
        //4*** Resultat BDE
        ShowMessage(IntToStr(MaRequete.rowsaffected)); // 1 c'est correct
     finally
       MaRequete.Free;
     end;
    Rowsaffected renvoie bien 1

    A+
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

  6. #6
    Modérateur
    Avatar de Rayek
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2005
    Messages
    5 235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 235
    Points : 8 504
    Points
    8 504
    Par défaut
    [QUOTE=pitango;2590601]Re bonjour

    Petite remarque : Comment peut fonctionner cette partie du code (voir dessous) sachant que matable_2 n'existe pas (elle est créée après)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    if MaRequete.Active then MaRequete.Close;
        MaRequete.SQL.Clear;
        MaRequete.SQL.Add(
        'create trigger mon_trigger_en_insertion on matable_1 '+
        'for insert as '+
        'begin '+
        'update matable_2 set matable_2.col_1 = 2 '+
        'update matable_2 set matable_2.col_1 = 2'+ // normal que cette ligne soit la deux fois ?
        ' end');
        MaRequete.ExecSQL;
    Sinon, je vais voir pour un test (j'ai un serveur SQL 2005 Express sur un des postes de mon réseau)
    Modérateur Delphi

    Le guide du bon forumeur :
    __________
    Rayek World : Youtube Facebook

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut
    Je te remercie Rayek de te pencher sur ce problème

    Concernant ta remarque sur matable_2 : le code peut fonctionner car
    c'est juste l'enregistrement du trigger.

    Le code du trigger s'executera lors de l'insertion sur la table matable_1.
    (matable_2 sera alors crée)

    A+
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

  8. #8
    Modérateur
    Avatar de Rayek
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2005
    Messages
    5 235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 235
    Points : 8 504
    Points
    8 504
    Par défaut
    Je viens de tester avec le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
      With TADOQuery.Create(self) do
      try
        Connection := ADOConnection1;
        Close;
        SQL.add('Insert into table_1');
        SQL.Add('values(''montest'',1)');
        ExecSQL;
        Memo3.Lines.Add('Nombre : ' + IntToStr(RowsAffected));
      finally
        free;
      end;
    Et j'ai bien 1 en réponse

    J'ai testé ceci après

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
     With TADOQuery.Create(self) do
      try
        Connection := ADOConnection1;
        Close;
        SQL.add('delete from table_1');
    //    SQL.Add('values(''montest'',1)');
        ExecSQL;
        Memo3.Lines.Add('Nombre : ' + IntToStr(RowsAffected));
      finally
        free;
      end;
    J'avais 3 lignes dans ma table et j'ai bien eu 3 en réponse

    Ma configuration de test : Delphi 2005 + SQL Server Express 2005
    Modérateur Delphi

    Le guide du bon forumeur :
    __________
    Rayek World : Youtube Facebook

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut
    Peux tu me montrer le code de ton trigger, s'il te plait ?

    Merci
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

  10. #10
    Modérateur
    Avatar de Rayek
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2005
    Messages
    5 235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 235
    Points : 8 504
    Points
    8 504
    Par défaut
    ce qui est bizarre

    C'est que si avec ton code, je mets qu'un seul update dans le trigger, j'ai bien 1 alors que si je laisse tel quel, j'ai 2
    Modérateur Delphi

    Le guide du bon forumeur :
    __________
    Rayek World : Youtube Facebook

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut
    Ca y est, je vois que tu as reproduit le problème. (Ce qui n'est pas forcément une bonne nouvelle, car
    on aurait pu imaginer qu'avec une version plus récente de delphi et de SQL Server, le problème aurait
    été réglé).

    Je suis d'accord avec toi, c'est vraiment curieux.
    Le code que je t'ai mis n'avait aucun sens fonctionnel, (double update) mais c'était pour reproduire l'erreur.

    Dans ma migration, le trigger comporte de nombreuses mise à jour qui, elles ont un sens.

    Mais quoi qu'il en soit le BDE lui fait bien le boulot et remonte le bon nombre de lignes mise à jour dans la table 1.

    J'èspère que tu auras peut être une idée ?
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

  12. #12
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut
    En encadrant les triggers par
    set nocount on et set nocount off cela évite qu'ils de renvoient
    le nombre de ligne manipulées et de polluer le ROWSAFFECTED du EXECSQL.

    Dommage qu'il faille pour autant intervenir sur la base de donnée.

    Si quelqu'un a une autre idée , j'attends encore un peu avant de clôturer
    cette discussion

    Merci
    A+
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

  13. #13
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    158
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2005
    Messages : 158
    Points : 158
    Points
    158
    Par défaut
    Je cloture donc ce post.

    En résumé.

    Il faut donc faire attention si vous utiliser les ADO sur une base SQLServer , avec l'utilisation de la propriété RowsAffected qui en cas de déclenchement de trigger ne retourne pas la bonne valeur.

    Pour ma part, je viens d'encadrer tous mes triggers par un set nocount on /off.

    A+.
    Pitango
    -------------------------------------------------
    [Delphi7.1 Entreprise][MYSQL 5.0.27][SQL SERVER 7][W2000/NT4]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 9
    Dernier message: 30/12/2012, 17h10
  2. problème avec la propriété rendered
    Par gaet_045 dans le forum JSF
    Réponses: 9
    Dernier message: 06/06/2007, 09h28
  3. [VBA_E] problème avec la propriété SelectedItem
    Par jamelie dans le forum Macros et VBA Excel
    Réponses: 14
    Dernier message: 17/04/2007, 06h09
  4. [Migration BDE en ADO][SQLServer] Problème avec les types char
    Par pitango dans le forum Bases de données
    Réponses: 3
    Dernier message: 15/03/2007, 17h17
  5. [Delphi 6] Problème avec la propriété Text d'un composant
    Par bionoir dans le forum Composants VCL
    Réponses: 4
    Dernier message: 08/12/2005, 11h23

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