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 :

Firedac, transaction qui me pose problème


Sujet :

Bases de données Delphi

  1. #1
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 042
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 042
    Points : 40 955
    Points
    40 955
    Billets dans le blog
    62
    Par défaut Firedac, transaction qui me pose problème
    Bonsoir,

    J'ai du merdoyé quelque part, mais je ne vois pas où !

    J'ai un code de ce style :
    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
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
     
    procedure TFormPrestaShop.btnValiderClick(Sender: TObject);
    var
      Result: Boolean;
      msg: String;
      Rsql: Integer;
      AQuery : TFDQuery;
      SQL : String;
     
      function Lignes(saison: String; cmde: Integer; var msg: String): Boolean;
      var
        i: word;
        Rsql: Integer;
      begin
        Result := False;
        RD.FDMemLcmdcli.First;
        while not RD.FDMemLcmdcli.EOF do
        begin
          try
             Aquery.SQL.Text:='INSERT INTO LCMDCLI (SAISON_CMDE,NUM_CMDE,LIGNE,MODELE,ASSORTIMENT,'
              + 'PRENDRE_STOCK,MARQUE,QUINZ_LIV,DATE_LIV,' +
              'PT_1,PT_2,PT_3,PT_4,PT_5,PT_6,PT_7,PT_8,PT_9,PT_10,PT_11,PT_12,PT_13,PT_14,'
              + 'PT_15,PT_16,PT_17,PT_18,PT_19,PT_20,PT_21,PT_22,PT_23,PT_24,' +
              'QTECDE1,QTECDE2,QTECDE3,QTECDE4,QTECDE5,QTECDE6,QTECDE7,QTECDE8,' +
              'QTECDE9,QTECDE10,QTECDE11,QTECDE12,QTECDE13,QTECDE14,QTECDE15,QTECDE16,'
              + 'QTECDE17,QTECDE18,QTECDE19,QTECDE20,QTECDE21,QTECDE22,QTECDE23,QTECDE24,'
              + 'PRIX_UNITE,MODIFICATIONS,PARTICULARITE,ETAT_LIGNE,NOMENCLATURE,LAST_UTIL,'
              + 'LAST_MODIF,NOMEN_DOUANE,REMISE) VALUES (?,?,?,?,?,?,?,?,?,' +
              '?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,' +
              '?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,' +
              '?,?,NULL,NULL,?,CURRENT_TIMESTAMP,?,0.00)';
             AQuery.Params[0].AsString:=saison;
    // ......
              Rsql:=AQuery.ExecSQL('');
     
    //        Rsql := Datas.ConnexionBase.ExecSQL
    //          ('INSERT INTO LCMDCLI (SAISON_CMDE,NUM_CMDE,LIGNE,MODELE,ASSORTIMENT,' .....
            Result := Rsql = 1;
          except
            on E: Exception do
            begin
              msg := E.Message;
              break;
            end;
          end;
          RD.FDMemLcmdcli.Next;
        end;
      end;
     
    begin
      AQuery:=TFDQuery.Create(Self);
      try
        AQuery.Connection:=Datas.ConnexionBase;
       try
        Datas.ConnexionBase.StartTransaction;
        NumeroCmde := Datas.GetNumeroCommande(edtSaison.Text);
        AQuery.SQl.Text:='INSERT INTO ECMDCLI (SAISON_CMDE,NUM_CMDE,DATE_CMDE,NUM_CLIENT,NOM_1,' +
          'ADRESSE_1,ADRESSE_2,ADRESSE_3,CODE_POSTAL,VILLE,PAYS,PROVENANCE,' +
          'REPRESENTANT,COMMISSION,TYPE_VENTE,CODE_TVA,MODE_PAIEMENT,REMISE,' +
          'ESCOMPTE,DOMICILIATION,PORT,TRANSPORTEUR,ETAT_CMDE,REFERENCE,' +
          'LAST_UTIL,LAST_MODIF ,TYPE_PORT,COMPTE,SWIFT,IBAN,DATE_LIV,TEL_LIV,DEVISE,'
          + 'IDCLIENTB2C,TAUX_TVA,OBSERVATIONS) ' +
          ' VALUES (:SC,:NC,:DC,:C,:N,:A1,:A2,:A3,:CDP,:V,:P,:PRO,:REP,:COM,:TV,:TVA,:MP,'
          + ' :REM,:ESC,:DOM,:PORT,:TRSPT,:EC,:REF,:LU,CURRENT_TIMESTAMP,:TP,:CPT,:SW,:IB,:DL,'
          + ':TEL,:D,:ID,:TAUX,:OBS)';
        AQuery.Params[0].AsString:=RD.fdMemECmdcliSaison.AsString;
    ...
        try
        Rsql:= AQuery.ExecSQL('');
    //    Rsql := Datas.ConnexionBase.ExecSQL
    //      ('INSERT INTO ECMDCLI (SAISON_CMDE,NUM_CMDE,DATE_CMDE,NUM_CLIENT,NOM_1,' +.....
         Result := Rsql = 1;
        except
         on e:Exception do
          begin
           result:=false;
           showmessage(e.Message);
          end;
        end;
        if Result then
          Result := Result AND Lignes(RD.fdMemECmdcliSaison.AsString,NumeroCmde, msg);
        if not Result then showmessage(msg);
      except
        on E: Exception do
        begin
          msg := E.Message;
          Result := False;
        end;
      end;
      if Result then
      begin
        Aquery.SQL.Text:='INSERT INTO CMDE_PRESTASHOP ' +
          '(IDPRESTASHOP, SAISON, NUMERO, DATE_PEC) ' +
          ' VALUES (:I,:S,:N,CURRENT_TIMESTAMP)';
        AQuery.Params[0].AsInteger:=RD.FDOrders.FieldByName('ID').AsInteger;
        AQuery.Params[1].AsString:=edtSaison.Text;
        AQuery.Params[2].AsInteger:=NumeroCmde;
    //    Datas.ConnexionBase.ExecSQL('INSERT INTO CMDE_PRESTASHOP ' + .....
        try
          rsql:=AQuery.ExecSQL('');
        except
         on e:Exception do
          begin
           result:=false;
           showmessage(e.Message);
          end;
        end;
        result:=result and (rsql=1);
      end;
     
     
     
      if result then
       begin
        Datas.ConnexionBase.Commit;
        Datas.MessageService.MessageDialogSync
          (Format('Cette commande a été crée sous le numéro %s-%d',
          [edtSaison.Text, NumeroCmde]), TmsgDlgType.mtInformation,
          [TMsgDlgBtn.mbOK], TMsgDlgBtn.mbOK, 0);
        CommandesRestantes;
        TabControl1.ActiveTab := Commandes;
      end
      else
      begin
        Datas.ConnexionBase.Rollback;
        TabControl1.Previous();
      end;
    finally
      AQuery.Free;
    end;
    Comme vous le lirez j'ai "encadré" le tout dans une transaction, seulement je ne comprends pas ce n'est que lorsque je ferme le programme que les données ajoutées deviennent "visibles" par un programme tiers.
    Il y a donc un loup quelque part, mais ce soir rien ne me vient à l'esprit.
    Après avoir ajouté des FDTranscations, puis les avoir supprimées, j'en suis au point de vouloir supprimer et recréer le FDConnection mais avant j'aimerai comprendre où j'ai foiré !
    Nom : Capture.PNG
Affichages : 146
Taille : 22,6 Ko

    Au début je croyais qu'il s'agissait de ma première syntaxe (Datas.ConnexionBase.ExecSQL) d'où mon ajout d'un FDquery au runtime, mais non ce n'est pas ça .
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Je me souviens d'un cas identique, quoi que non pire, il n'y avait pas de donnée en Base, je crois qu'il y avait eu une boulete sur l'AutoCommit à False
    Cela me rappelle aussi Paradox et BDE, je n'avais que des données lors d'un Close (on avait remplacé à l'arrache par InterBase et IBX, lent mais sans ce problème)


    En dehors de l'indentation un peu curieuse mais je suppose que c'est un premier jet vite fait directement dans la code Vue pour valider le fonctionnement avant de séparer le code Vue du code Modèle.


    je remplacerais le break de la fonctions Lignes par un exit(False) car au second tour, Result est probablement déjà à True (Rsql = 1) donc la gestion de l'erreur doit en être perturbée mais ce n'est pas ton problème puisque c'est le cas normal qui t'intéresse.

    d'ailleurs dans Lignes, pourrais-tu affecter qu'une seule fois "Aquery.SQL.Text" en dehors la boucle, faire un Prepare puis dans la boucle ne faire que les Binds et ExecSQL ?

    le INSERT CMDE_PRESTASHOP ne vérifie par le Rsql ?

    Avant de faire le StartTransaction, que retourne InTransaction ?
    Utilisant plutôt des objets business (à base de TDataSet interne), tous mes objets ont une fonction Save, celle-ci pouvant être redéfini pour utiliser un SaveMeAndSaveChild qui gère le NestedTransaction, j'ai déjà 4 niveaux d'imbrication de Save redéfini qui utilise ainsi la Transaction du premier niveau.

    EnableNested ? c'est quoi ?

    AutoCommit à True ... pareil dans l'objet Connection (un TSliteDBConnection pouvant être TOraSession ou un TADOConnection)
    Cela gênait pas les Transactions explicites sur ces deux composants, on peut espérer de même sur un TFDConnection.

    AutoCommitUpdates, tu ne sembles pas en avoir besoin, c'est pour le cas où c'est FireDac qui génère les requêtes à partir d'un CachedUpdates à True dans le TFDDataSet

    Cependant, chacun des mes niveaux étant gérés par un objet collection différent, c'était aussi un Query différent, je ne crois pas que cela puisse avoir un impact sur les SQL lancés, car j'ai aussi pas mal pratiqué le Query réutilisé mais toujours explicitement préparé.


    DisconnectAction tu notes xdCommit ... en xdNone ... ça valide les données à la fin ou tu perds tout ?

    Isolation en iReadCommitted, cela concerne plutôt ce que tu lis durant la transaction qu'après donc je dirais sans effet (et une valeur par défaut assez classique)


    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
    //------------------------------------------------------------------------------
    function TSliteDBEntity.SaveMeAndSaveChild(AChild: TSliteDBEntity): Boolean;
    var
      NestedTransaction: Boolean;
    begin
      Result := False;
     
      NestedTransaction := Connection.InTransaction;
      if not NestedTransaction then
        Connection.BeginTransaction();
      try
        Result := FInternalEntity.Save(False) and AChild.Save();
        if not NestedTransaction then
        begin
          if Result then
            Result := Connection.CommitTransaction()
          else
            Abort;
        end;
      except
        on E: Exception do
        begin
          LogException(ExceptClass(E.ClassType), E.Message);
          DoSaveError(E.Message);
          if not NestedTransaction then
            Connection.RollbackTransaction();
        end;
      end;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 042
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 042
    Points : 40 955
    Points
    40 955
    Billets dans le blog
    62
    Par défaut
    Bonjour,
    Citation Envoyé par ShaiLeTroll Voir le message
    je crois qu'il y avait eu une boulette sur l'AutoCommit à False
    je crois que c'est aussi mon cas, après une nuit dessus j'ai diverses pistes à suivre.

    En dehors de l'indentation un peu curieuse mais je suppose que c'est un premier jet vite fait directement dans la code Vue pour valider le fonctionnement avant de séparer le code Vue du code Modèle.
    c'est exactement ça, la plupart pour ne pas dire tout, était (et est encore mais commenté) dans le datamodule. Ce "petit problème" m'a poussé à tout mettre dans le code vue pour essayer de montrer mon cas.

    je remplacerais le break de la fonctions Lignes par un exit(False) car au second tour, Result est probablement déjà à True (Rsql = 1) donc la gestion de l'erreur doit en être perturbée mais ce n'est pas ton problème puisque c'est le cas normal qui t'intéresse.
    Non, c'est bien ça, car je veux analyser aussi les autres lignes s'il y en a ("il ne peut pas y avoir d'erreur", quelques tests plu tard je tombais dessus ). Par contre, oui, il y a une erreur sur le result que je n'avais pas lue, dans mon traitement précédent je faisais un traitement ligne par ligne

    d'ailleurs dans Lignes, pourrais-tu affecter qu'une seule fois "Aquery.SQL.Text" en dehors la boucle
    oui bien sûr, cela ne m'avais pas sauter aux yeux (généralement il n'y a qu'un ligne)
    , faire un Prepare puis dans la boucle ne faire que les Binds et ExecSQL ?
    là, j'ai essayé, mais il y a une erreur de type de paramètres pour les dates qui me pose soucis. Pour l'instant je le remet à plus tard.

    le INSERT CMDE_PRESTASHOP ne vérifie par le Rsql ?
    si, après mon post, j'ai vu cette partie

    Avant de faire le StartTransaction, que retourne InTransaction ?
    Bonne question, je vais vérifier.

    EnableNested ? c'est quoi ?
    bonne question ! Il va falloir que je me plonge dans l'aide et ma bibile

    AutoCommitUpdates, tu ne sembles pas en avoir besoin, c'est pour le cas où c'est FireDac qui génère les requêtes à partir d'un CachedUpdates à True dans le TFDDataSet
    bien vu.

    DisconnectAction tu notes xdCommit ... ou tu perds tout ?
    Je ne perds rien. Et c'est peut-être là le point d'acchopement, car c'est certainement ça qui me sauve de la cata comme si les transactions restaient en Limbo jusqu'à ce DisconnectACtion.

    En NB, la plupart des options sont celles par défaut de FDConnection, c'est justement une de celles-ci que j'ai du changé par inattention qui me mets dans la m...e
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  4. #4
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 042
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 042
    Points : 40 955
    Points
    40 955
    Billets dans le blog
    62
    Par défaut
    Avant de faire le StartTransaction, que retourne InTransaction ?
    Bien vu, InTransaction était à true ! Il va me falloir voir où j'ai bien pu en ouvrir une , ça plus l'autorisation des transactions imbriquées (NestedTransaction) voilà où j'ai merdé.

    Merci ShaiLeTroll :tchin: tu mérites ta bière virtuelle.

    YAPLUKA trouver où s'est cachée cette transaction non clôturée et tout remettre dans les "bonnes" unités. Bon c'est pas encore gagné mais ouf, c'est
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Bien vu, InTransaction était à true ! Il va me falloir voir où j'ai bien pu en ouvrir une , ça plus l'autorisation des transactions imbriquées (NestedTransaction) voilà où j'ai merdé.
    NestedTransaction c'est une variable local de mon code, ce qui t'intéresse EnableNested semble-t-il

    Citation Envoyé par SergioMaster Voir le message
    Merci ShaiLeTroll :tchin: tu mérites ta bière virtuelle.
    Oui Virtuelle, je fais un sevrage de la vraie Bière ... plus de fut jusqu'à l'Oktober Fest !
    A la diète !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 042
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 042
    Points : 40 955
    Points
    40 955
    Billets dans le blog
    62
    Par défaut
    ce qui t'intéresse EnableNested semble-t-il
    oui, ma fourche à languer

    Citation Envoyé par sergiomaster
    Il va me falloir voir où j'ai bien pu en ouvrir une
    Eurêka ce démarrage était caché dans une autre fonction qui n'en avait plus besoin !

    A la diète !
    pas de bol (pour une bière une chope c'est mieux) alors à défaut tout aussi virtuel liquide restant à définir
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

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

Discussions similaires

  1. [MySQL] Condition where qui me pose problème
    Par Ikaly dans le forum PHP & Base de données
    Réponses: 6
    Dernier message: 27/05/2010, 10h09
  2. Réponses: 1
    Dernier message: 18/02/2008, 20h40
  3. Toggle qui me pose problème
    Par Ben-o dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 24/10/2007, 09h24
  4. Requête SQL qui me pose problème
    Par CB56 dans le forum Langage SQL
    Réponses: 4
    Dernier message: 04/02/2007, 16h07
  5. un trait qui me pose problème
    Par barbapapa2 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 22/11/2006, 12h32

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