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

Delphi Discussion :

TFDUpdateSQL et ses méthodes


Sujet :

Delphi

  1. #1
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut TFDUpdateSQL et ses méthodes
    Bonjour,

    je cherche une documentation synthétique pour utiliser le couple TFDQuery + TFDUpdateSQL. Jusqu'à présent en Lazarus comme en Delphi, j'utilisais 2 DataSet : un pour le rafraîchissement de la Grid (Open) et l'autre pour toutes les opérations d'insertion, suppression, modification et duplication (ExecSQL). L'avantage de ma solution étant de réduire les temps de chargement avec une méthode adaptée et la complication étant le rafraîchissement de la table. Par contre, je dispose de la duplication. Je ne sais pas si on peut l'émuler avec le TFDUpdateSQL.

    Après avoir lu un article récent dans ce forum, j'ai testé la TMSFMXLiveGrid et en effet même sur une table MySQL distante conséquente on peut rendre l'affichage des données assez rapide. C'est même assez surprenant. Le problème c'est que le FDUPdateSQL m'est totalement étranger. Je me lance, consulte des docs, mais non synthétiques et je ne suis pas loin d'abandonner... Je peux y passer une journée de mon WE pour faire le point mais guère plus. J'ai consommé 50% du temps et les lacunes sont encore très nombreuses.

    Le DataSet est en LiveBindings avec une TDGrid. La Grid est en lecture seule. Je voudrais supprimer et insérer des enregistrements. Dans le FDUpdateSQL, voici les requêtes de suppression
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DELETE FROM test WHERE teID = :OLD_teID LIMIT 1;
    et d'insertion
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    INSERT INTO test (teID, teNOM, tePRENOM) VALUES (:NEW_teID, :NEW_teNOM, :NEW_tePRENOM);
    Le code du bouton de suppression pour supprimer l'enregistrement sélectionné dans la Grid :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    procedure TForm1.BtDELClick(Sender: TObject);
    begin
    with FDQuery1 do
     try
         Delete;
       except
         on e: Exception do
         begin
           ShowMessage(e.Message);
         end;
       end;
    end;
    Cela semble fonctionnel (dans la Grid et dans la table). Trop simple certainement.

    Pour l'insertion, il me semble avoir compris à la lecture de la documentation éparpillée de Delphi que pour changer les paramètres, on utilise
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    FindField('teID').NewValue := 'AAAAA';
    FindField('teNOM').NewValue := 'NOM A ';
    FindField('tePRENOM').NewValue := 'Prénom A' ;
    Je vois en effet des changements dans la Grid.
    Postit : Et quid d'un champ NUL ? En Params, FireDac est mauvais (peu simple) pour cette gestion.
    Mais c'est après que cela se complique. Comment articule-ton la gestion de la transaction ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    with FDQuery 1 do begin
      Connection.StartTransaction;
      try
         [???]
    end;
    J'utilise quoi exactement dans les CachedUpdates := True; Insert; ApplyUpdates(); CommitUpdates; CachedUpdates := False; Connection.Commit; ?
    Pour l'instant mon FDQuery et son FDUpdateSQL sont réglés avec les réglages par défaut.

    Merci de votre aide. Zac.

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 045
    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 045
    Points : 40 963
    Points
    40 963
    Billets dans le blog
    62
    Par défaut
    Bonjour,
    Delete .....Cela semble fonctionnel (dans la Grid et dans la table). Trop simple certainement.
    pas trop simple, simple et efficace.

    Par contre, je dispose de la duplication.
    qu'est-ce que tu entends par duplication?

    Pour l'insertion, il me semble avoir compris à la lecture de la documentation ...
    pour rester simple.
    s'il y a un bouton pour l'action d'ajout
    procedure AjoutOnClick(sender : Object)
    Begin
    Query1.Insert;
    End;
    les Edits étant lié via livebindings
    reste plus qu'a valider l'insertion (idem en cas de Update)
    un autre Bouton et
    procedure ValiderOnClick(sender : Object)
    Begin
    Query1.Post;
    End;
    plus simplissime encore : un NavigatorBindSource peut remplacer les boutons => plus une ligne de code en théorie (je n'ai jamais essayé )


    s'il n'y a pas de TEdit, on peut faire de la manière suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure InsertionDirecteOnClick(sender : Object)
    Begin
    Query1.Insert;
    Query1.FieldByName('CHAMP1').asString:='AAAA';
    Query1.FieldByName('CHAMP2').asString:='B';
    ...
    Query1.Post;
    End;
    en bref, du pur BDE des débuts de Delphi

    je ne me suis même pas occupé des transactions en continuant dans le simplissime , un seul FDTransaction indiqué uniquement pour la FDConnexion, toutes options par défaut, fait l'affaire
    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

  3. #3
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut
    Bonjour,

    Merci pour tes renseignements. J'avais abandonné mais je regarderai demain. J'ai 2 questions supplémentaires.
    1. Quand tu codes dans tes boutons, es-tu obligé d'utiliser ces "fameuses" NewValues associées à :NEW_XXXX. Au départ, j'ai simplement voulu utiliser mes requêtes habituelles : INSERT (teID) VALUES (:teID) et cela n'est pas passé ? Erreur de déclaration sur le :teID
    2. Ensuite, le repositionnement de l'enregistrement sélectionné dans la Grid. Avec Delete, curieusement un enregistrement est re-sélectionné par défaut ce qui fait qu'en cliquant sur ton bouton associé à ton Delete tu peux effacer toute ta Grid "naturellement". En Insert et en Update, l'enregistrement créé est effectement (re-)sélectionné mais pourquoi le tri par défaut n'est-il pas appliqué ? Tu tries les teNOM : ton nom initial est ALPHA, normalement en début de liste. Tu le remplaces par DELTA (normalement en milieu de liste) et corrigé, il ne bouge pas dans la Grid. J'ai essayé Refresh en vain mais j'ai vu des requêtes d'insertion suivi dans la même requête, d'un code de repositionnement en Oracle et en MSSQL me semble-t-il.


    Cela me semble toujours aussi "moyennement" simple d'autant que BDE je ne connais pas non plus
    A demain et encore merci pour ton aide. Zac.

  4. #4
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 045
    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 045
    Points : 40 963
    Points
    40 963
    Billets dans le blog
    62
    Par défaut
    Bonjour,
    Citation Envoyé par Zacheus Voir le message
    [*]Quand tu codes dans tes boutons, es-tu obligé d'utiliser ces "fameuses" NewValues associées à :NEW_XXXX. Au départ, j'ai simplement voulu utiliser mes requêtes habituelles : INSERT (teID) VALUES (:teID) et cela n'est pas passé ? Erreur de déclaration sur le :teID
    où as tu vu dans le code que je t'ai fourni des NEW_XXXX, tu les trouveras (ainsi que les OLD_), et c'est logique, uniquement dans les différents SQL du SQLUpdate et comme ces SQL sont facilement "générables" quitte ensuite à les modifier je dirais que cela reste facile
    [*]Ensuite, le repositionnement de l'enregistrement sélectionné dans la Grid. Avec Delete, curieusement un enregistrement est re-sélectionné par défaut ce qui fait qu'en cliquant sur ton bouton associé à ton Delete tu peux effacer toute ta Grid "naturellement". En Insert et en Update, l'enregistrement créé est effectement (re-)sélectionné mais pourquoi le tri par défaut n'est-il pas appliqué ?
    peut être parce que le refresh (dans le SQLupdate est celui par défaut )

    Cela me semble toujours aussi "moyennement" simple d'autant que BDE je ne connais pas non plus
    Ce que je voulais aussi souligné par là c'est que toute documentation BDE (et ça il y en a beaucoup) est applicable à Firedac à l'exception près que Firedac a beaucoup plus de possibilités (savais tu, par exemple que l'on pouvait mettre plusieurs instructions SQL dans une même query )

    j'ai simplement voulu utiliser mes requêtes habituelles
    je pense qu'un de tes "problèmes" avec Firedac est justement de trop utiliser le "habituel" à vouloir faire par toi même plutôt qu'à l'aide des outils proposés.
    C'est très bien d'essayer de maitriser tous les mécanismes (transaction, requêtes etc...) mais pour aborder Firedac personnellement j'ai commencé avec le "tout par défaut" et le "au plus simple" pour ensuite, petit à petit fouiller dans ses entrailles (et je n'en suis qu'à la partie sous-cutanée l'opération prend du temps)

    Avec toutes les vidéos et tutoriels sur le net, je ne pensais pas avoir à dire cela, mais je crois qu'un tutoriel B.A.B.A. Firedac (autre que sur fishfactory) en français serait envisageable. Entre temps, je vais essayé de faire un petit programme (j'adore les petits programme ) permettant de répondre a tes 2 posts

    @+
    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
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    les Edits étant lié via livebindings
    Bonjour,

    je viens de comprendre le Quiproquo. Mes Edits ne sont pas sur la même Form que la Grid et n'utilisent pas le LB. Mais évidemment je pourrais l'envisager. J'ai l'impression que c'est toute la techno ou rien.

    Pour le reste tu as raison : Avec les natifs en Lazarus on peut avoir la même approche grosso-modo que FireDac. Et à l'époque, après un court passage par Zeos que j'ai rapidement abandonné, j'ai choisi de ne pas l'utiliser.

    Ne te donne pas le mal de me fabriquer un exemple. Je m'accorde encore 2H d'étude sur la question en essayant de réaliser un modèle fonctionnel fiable... mais je crois que je ne suis pas encore convaincu par cette nouvelle tentative.

    Mais il est vrai qu'une bonne doc synthétique fait (ferait) partie des instruments de persuasion.

    Cordialement. Zac.

  6. #6
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut
    Bon je n'insiste pas.

    j'ai réussi à insérer des enregistrements et à modifier avec les requêtes standards voire dynamiques passées dans le FDUpdateSQL. Des progrès donc. Mais des aides comme celle-ci ne me sont d'aucune utilité pour éliminer ce genre de message :
    Nom : Test030.png
Affichages : 865
Taille : 6,5 Ko
    Et une recherche avec le type d'erreur signalée [un parmi d'autres] ne donne rien. Bref difficile d'avancer parce qu'en plus, au fur et à mesure, qu'on complique le code (activation des tris, replacement,..) les erreurs défilent : les 2xx j'ai donné. Ensuite le paramétrage des propriétés est déjà intrinsèquement délicat et leurs associations entre elles relèvent d'un tâtonnement aux trop multiples possibilités. Impossible de les essayer une par une.

    Je verrai une autre fois peut-être quand il ne faudra pas être passé par BDE et que la doc FireDac sera à la hauteur : une simple recherche Firedac com ds -218 qui est l'intitulé de l'erreur est édifiante, notamment les liens docwiki.embarcadero.com. Et peut-être aussi que mon approche n'est pas compatible avec l'usage des FDUpdateSQL. Un dernier petit tour par UniDACDemo avant de jeter l'éponge...

    Encore merci pour l'aide apportée. Cordialement. Zac

  7. #7
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut
    Finalement résolu dans les grandes lignes grâce à cette aide trouvée dans la FAQ FireDac et m'en appuyant sur les pratiques Lazarus.

    Je me fais un petit postit. Je le mettrai à dispo. Pour mon message d'erreur, c'est là :
    Q4 : En mode CachedUpdates, pourquoi le fait d'appeler ApplyUpdates plusieurs fois tente à nouveau de valider des enregistrements insérés ?
    R : Après avoir appelé ApplyUpdate, vous devez appeler CommitUpdates. Après cet appel, toutes les modifications sont supprimées du cache interne.
    La question n'est pas celle-là dans mon cas, mais la réponse explique l'apparition du problème et son contournement.

    Donc résolu.

  8. #8
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 045
    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 045
    Points : 40 963
    Points
    40 963
    Billets dans le blog
    62
    Par défaut
    Re,

    Quiproquos. Mes Edits ne sont pas sur la même Form que la Grid et n'utilisent pas le LB.
    Comme j'en étais resté sur FMX (à cause du mot sur TMSFMXGrid) et donc pour moi relativement indissociable de LiveBindings (sauf à coder beaucoup) évidement je ne pouvait pas vraiment savoir

    Mes Edits ne sont pas sur la même Form que la Grid
    comme en général je mets toutes mes données dans une DataUnit je n'y fais jamais plus attention que ça

    pour ce qui est des CacheUpdates, CommitUpdates ApplyUpdates et consorts, joker je n'en suis pas encore là de la maitrise de Firedac
    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

  9. #9
    Membre du Club
    Homme Profil pro
    Programmeur
    Inscrit en
    Octobre 2015
    Messages
    80
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Programmeur
    Secteur : Boutique - Magasin

    Informations forums :
    Inscription : Octobre 2015
    Messages : 80
    Points : 46
    Points
    46
    Par défaut
    Bonsoir,

    j'ai repris un peu de temps ce soir après mon travail pour résumer mes quelques connaissances sur la question. Je n'exploiterai pas cette piste immédiatement mais le sujet est irritant (pour moi) et cela attise ma curiosité :
    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
    procedure TForm1.Button5Click(Sender: TObject);
    var
      sERR: string;
      oErr: EFDException;
      iErrors : integer;
    begin
    with mySQLQuery do begin
       Connection.StartTransaction;
     
       try
     
        if not CachedUpdates then CachedUpdates := true;
        Insert;
        {La clé primaire}
        FieldByName('teID').AsString :=  'aaaa'; // AleaID();
        {Les valeurs}
        FieldByName('teNOM').AsString := 'NOM ' + 
        FieldByName('tePRENOM').AsString := 'Prénom ' +  AleaID();
        {ToDo ... Affect Null Values }
     
     
    //  Approche 1
    //  iErrors := ApplyUpdates();
    //    oErr := RowError;
    //    if Oerr = nil then showmessage('nil');
    //
    //    if oErr <> nil then sErr := oErr.Message;
    //    if iErrors = 0 then begin
    //      CommitUpdates;
    //      Connection.Commit;
    //      Refresh;
    //      Locate('teID', FieldByName('teID').AsString,[]);
    //    end else begin
    //       CancelUpdates;
    //       Connection.Rollback;
    //       Showmessage('Error' + sErr);
    //    end;
     
    //Approche 2 (sans DisabledControls)
     
        ApplyUpdates();
        oErr := RowError;
     
        if oErr <> nil then
          begin
            sErr := oErr.Message;
            CancelUpdates;
            Connection.Rollback;
            Showmessage('Error ' + sErr);
          end
        else
          begin
            CommitUpdates;
            Connection.Commit;
            Refresh;
            Locate('teID', FieldByName('teID').AsString,[]);
          end;
     
      except
         on E: EFDDBEngineException do begin
           {$IFDEF DEBUG}
            Showmessage(E.Message + ' Failed SQL: ' + E.SQL);
           {$ENDIF}
            Connection.Rollback;
         end;
       end;
     
    end;
    Essentiel : le TFDUpdateSQL ne gère pas les exceptions. Donc quand vous créez un doublon sur une clé unique, il ne se passe... rien d'explicite.
    Alors, on a 2 approches :
    • une sur le résultat de ApplyUpdates() : 0 si OK mais on n'a pas la nature de l'erreur.
    • une sur RowError. On utilise un oErr: EFDException dont on récupère le message. Je suppose que cette méthode est fiable. Si oErr = nil, c'est qu'il n'y a pas d'erreur.

    Evidemment, je laisse une exception sur le TFDQuery (ici mySQLquery). Par exemple si aucun Open n'a été utilisé, c'est l'exception du DataSet qui oeuvre.

    Deuxième point : pour l'instant, il y a peu de code par rapport à la solution avec 2 Datasets même si j'ai conservé mes requêtes initiales, mais l'ensemble est plus lent notamment au replacement de l'INSERT surtout s'il est vers la fin de la table. J'ai joué avec les DisableControls mais, c'est moins rapide.

    Je vais encore passer un petit de temps pour étudier cette option. J'ai vu aussi "passer" un bug et un patch.

    Je l'avoue, la non-gestion des exceptions me rappelle la bidouille Qt (ce n'est pas nécessairement un compliment). Le patch est tardif : FireDac date de la première version de Delphi XE. Et j'ai surtout l'impression en lisant le peu de question posée sur ce thème que ce n'est pas si utilisé que cela et que les approches sont diverses, variées souvent "pifométriques".

    Je résume : à étudier absolument ne serait-ce que pour ne pas rester dans la routine. Je laisse la discussion ouverte !

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

Discussions similaires

  1. [Multimédia] Phonon et ses méthodes ne m'obéissent pas !
    Par betonfrance dans le forum Débuter
    Réponses: 13
    Dernier message: 08/12/2011, 13h28
  2. Réponses: 0
    Dernier message: 08/12/2011, 09h15
  3. Réponses: 14
    Dernier message: 25/02/2011, 00h06
  4. Réponses: 5
    Dernier message: 12/09/2007, 09h18
  5. Réponses: 2
    Dernier message: 14/05/2007, 23h11

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