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 :

[TDataSetProvider] Mise à jour BD


Sujet :

Bases de données Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut [TDataSetProvider] Mise à jour BD
    Sauriez- vous m'expliquer comment un TDataSetProvider procède pour:
    - Insérer un nouvel enregistrement dans la BD,
    - Supprimer un enregistrement existant,
    - Modifier un enregistrement.
    Pour l'insertion, est-ce une simple commande SQL INSERT ?
    Pour la modification et la suppression, UPDATE DELETE, quelle est la condition utilisée dans la clause WHERE ?
    Généralement, il s'agit de la clé primaire ou une colonne de type ROWID. Mais je ne vois pas ou cette condition est indiquée ?
    J'ai parcouru l'aide en ligne en long et en travers mais je n'ai rien trouvé.
    Merci pour vos réponses.
    [/quote]

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    520
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 520
    Par défaut
    Le TDataSetProvider reçoit le paquet de modifications provenant du clientDataset, après que ce dernier ait exécuté sa méthode ApplyUpdates.
    Le paquet en question contient la liste des enregs modifiés et indique pour chaque enreg, celui qui a été inséré, modifié ou supprimé.
    En fonction de cette information, le provider va générer lui même les requêtes INSERT, UPDATE et DELETE et les envoyer au Dataset côté serveur qui va les exécuter.
    La clause WHERE est générée en fonction de la propriété ProviderFlags de chaque champ du Dataset côté serveur. Pour plus d'infos, regarde la doc sur cette propriété.

    Sylvain

  3. #3
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut
    Merci pour tes précision, c'est beaucoup plus claire à présent.
    tu dis que:
    La clause WHERE est générée en fonction de la propriété ProviderFlags de chaque champ du Dataset côté serveur.
    Je n'utilise pas de serveur d'application et donc la source de données de mon TDataSetProvider se trouve dans un DataModule coté client, la source de données est entre autres un TADODataSet.
    Par ailleurs, j'ai initialiser la propriété ResolveToDataSet de mon TDataSetprovider à False, comme indiquer dans la Doc, pour que les MAJ se fassent directement dans la base de données.
    Mon TADODataSet ne me sert que de moyen d'accès aux données de la base au travers d'une connection TADOConnection, et donc je n'ai pas besoin de champs persistants pour mon TADODataSet.
    Comment le TDataSetProvider fait-il dans ce cas pour constituer la condition dans la clause WHERE ?
    Dans mon appli, les mises à jour se font très bien, ce n'est pas la question, j'aimerai seulement comprendre et la Doc Delphi n'est pas très explicite.
    Merci d'avance.

  4. #4
    Membre émérite

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    520
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 520
    Par défaut
    je n'ai pas besoin de champs persistants pour mon TADODataSet.
    Si justement là ça peut servir pour définir visuellement leur propriété ProviderFlags sachant qu'en général le champ à qui on marque la propriété pfInKey est la clé primaire. Du coup le WHERE résultant se fait sur ce champ là dans les update et delete.
    Si tu veux pas créer de champs persistants, alors il faut modifier la propriété par code à la volée.

    Sylvain

  5. #5
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut
    il faut modifier la propriété par code à la volée.
    De quelle propriété parles-tu ?
    La propriété de quel objet ?
    Jusque là, je suis...

  6. #6
    Membre émérite

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    520
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 520
    Par défaut
    La propriété TField.ProviderFlags
    Quand tu sélectionnes un champ dans l'éditeur de champ (double click sur le dataset) tu accèdes aux props de l'objet TField respectif.

    Sylvain

  7. #7
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut
    Justement, dans mon cas il n'y a pas de champs dans mon TADODataSet.
    Donc quand tu me dis
    il faut modifier la propriété par code à la volée.
    De quoi tu parles ?
    A moins que tu ne fasses allusion aux champs générés dynamiquement ?

  8. #8
    Membre émérite

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    520
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 520
    Par défaut
    oui il s'agit des champs dynamiques.
    accès par exemple comme çà :

    monDataSet.FieldByName('unchamp').ProviderFlags := ...

    Sylvain

  9. #9
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut
    OK, merci de ton aide Sylvain, c'est super, hormis tes réponses il n'y a pas beaucoup d'amateurs à en donner.
    Cependant, tant que je t'ai sous la main, peux-tu m'expliquer comment TDataSetProvider fait par défaut lorsque aucune initialisation n'est faite sur les propriétés ProviderFlags des champs du DataSet ?
    Comment fait-il pour identifier les enregistrement à mettre à jour dans la BD ?
    Merci encore

  10. #10
    Membre émérite

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    520
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 520
    Par défaut
    Par default il utilise tous les champs dans la clause where car sa propriété UpdateMode (j'avais oublié de te citer ce point important) est positionné à UpWhereAll par default.
    Le mode le plus fin est UpWhereKeyOnly ou seuls les champs.ProviderFlags = pfInkey seront spécifiés dans la clause WHERE générée par le provider.

    Sylvain

  11. #11
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut
    Si j'ai bien compris, dans le cas où la propriété UpdateMode de mon TDataSetProvider est positionné à UpWhereAll, alors il utilise tous les champs dans la clause WHERE.
    C'est pas terrible ça !, je dirais même plus c'est carrement NULL !

    Si je modifie les valeurs de champs d'un enregistrement de mon TClientDataSet, comment fait-il à ce moment là pour retrouver l'enregistrement dans la BD vu que les valeurs des champs, qui serviront de critère dans la clause WHERE pour le UPDATE, auront changé ?
    A moin qu'il ait une astuce...

    Une autre chose,
    Si je ne crée pas de champs persistants pour mon TADODataSet, tu me suggère d'initialiser la propriété ProviderFlags des champs dynamiques dans le code.
    Alors j'ai essayé de le faire dans le gestionnaire d'événement BeforeUpdateRecord de mon TDataSetProvider avec le code suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Self.DataSetUsers.FieldByName('OPERATEUR_ID').ProviderFlags := [pfInWhere, pfInKey];
    Problème, une exception est levée.
    En vérifiant, je me suis apperçu que mon TADODataSet est fermé.
    Effectivement, lorsque je fais un Open de mon TClientDataSet, mon TADODataSet est ouvert simultanément mais est refermé automatiquement après lorsque l'opération de récupération des données dans mon TClientDataSet est terminée.
    Aurais-tu ou auriez-vous, la discussion est ouverte à qui veut y participer (on n'est pas raciste), une autre idée sur comment initialiser la propriété ProviderFlags d'un champ dynamique d'un ensemble de données source associée à un composant TDataSetProvider ?
    Merci pour votre patience.

  12. #12
    Membre émérite

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    520
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 520
    Par défaut
    Pour upWhereAll effectivement ce n'est pas ce qu'on utilise le plus souvent. Ca serait nul si on avait pas le choix mais il existe des cas où ça peut servir.
    Mais tu as bien compris les implication de UpdateMode me semble-t-il :-)

    Pour providerFlags, ça serait plutôt dans TADODataSet.AfterOpen, donc au niveau du Dataset qui commande les requêtes.

    Sylvain

  13. #13
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut
    J'ai pourtant compris que les champs dynamiques d'un DataSet ne sont créés qu'à l'Open, et qu'ils disparaissent au Close du DataSet.
    Dans mon cas, comme je le disais précédemment, mon TADODataSet est automatiquement fermé lorsque mon TClientDataSet a fini de recevoir le paquet de données du TDataSetProvider.
    Donc initialiser la propriété ProviderFlags dans l'AfterOpen de mon TADODataSet ne sert à rien étant donné que les champs sont détruits à la fermeture.

  14. #14
    Membre émérite

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    520
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 520
    Par défaut
    Essaie quand même :-)
    Pourquoi ça servirait à rien ? Il faut bien pouvoir en disposer et si ce n'est pas à ce moment là, ça serait à quel moment ?
    Il faut savoir aussi que dans ton exemple, lorsque le clientdataset reçoit les enreg de la part du fournisseur, les propriétés de chaque champ du ADODataset sont propagés vers le clientdataset. Ce sont les propriétés de TFields côté ADODataset qui font foi, rien ne sert de modifier ProviderFlags côté clientdataset.

    Mais au dela de tout ça, le plus simple reste de créer des champs persistant sur ADODataSet... pourquoi tu ne pourrais pas le faire ?

    Sylvain

  15. #15
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut
    Pourquoi ça servirait à rien ?
    Au moment de l'application des mises à jour, l'ensemble de données source est fermé et donc ne dispose d'aucun champ dynamique. Cela veut dire donc que le fournisseur ne peut se référer aux objets TField de l'ensemble de données source étant donné qu'ils n'existent pas.

    Ce sont les propriétés de TFields côté ADODataset qui font foi, rien ne sert de modifier ProviderFlags côté clientdataset
    J'ai bien compris que les propriétés ProviderFlags des champs de l'ensemble de données client ne contribuaient aucunement au processus de mise à jour.
    Je crois comprendre que seuls les objets TField de l'ensemble de données source sont utilisés par le fournisseur dans la phase de génération des instructions SQL. Du moment où, quand même, l'ensemble de données source dispose de champs persistants (crées dans l'EDI à la conception ou par programme à la création de l'ensemble de données).

    le plus simple reste de créer des champs persistant sur ADODataSet... pourquoi tu ne pourrais pas le faire ?
    Je suis bien d'accord avec toi, la première idée serait de créer des champs persistants.
    Avant d'en arriver là, j'aimerai étudier d'autres solutions.

    Il faut bien pouvoir en disposer et si ce n'est pas à ce moment là, ça serait à quel moment ?
    On pourrait imaginer qu'au moment de l'application des mises à jour par le fournisseur, dans le gestionnaire d'événement OnUpdateData, on ouvre l'ensemble de données source pour qu'il construise les champs dynamiques et que l'on initialise alors les propriétés ProviderFlags de ces champs.
    Je ne pense pas que ça soit la bonne solution car cela implique l'exécution d'une requete sur la base même si l'on pourrait aménager l'instruction de sort à ce qu'elle ne ramène aucun résultat.

    La solution que tu préconises serait de créer des champs persistants, effectivement les objets TField existeraient même si l'ensemble de données source est fermé au moment de l'application des mises à jour, le fournisseur pourrait de ce fait générer les instructions SQL suivant les propriétés ProviderFlags de ces champs.
    Je n'est pas encore essayé à vrai dire, je crois avoir trouver une autre manière de faire.

    Avant de vous l'exposer, petite question.
    Est ce que ça vous intéresse de savoir de quelle manière on pourrait faire autrement ?
    Sinon, ce n'est pas la peine que je me fatigue...

    Je ne dois pas être le seul à me poser des questions sur le fonctionnement d'un fournisseur surtout lorsque l'on parle de SI (Banques, Assurances, Défense...) à moins que mes questions ne soient triviales pour le commun des mortels que nous sommes.
    Dans ce cas, excusez-moi.
    .

  16. #16
    Membre émérite

    Profil pro
    Inscrit en
    Mars 2002
    Messages
    520
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 520
    Par défaut
    Je crois comprendre que seuls les objets TField de l'ensemble de données source sont utilisés par le fournisseur dans la phase de génération des instructions SQL. Du moment où, quand même, l'ensemble de données source dispose de champs persistants (crées dans l'EDI à la conception ou par programme à la création de l'ensemble de données).
    Allez je suis retourné faire un tour dans la VCL, et j'ai bien fait, ça a rafraichit un peu le schmilblick et ça m'a permis de voir que je t'ai pas fourni de réponse complètement exacte. Sorry, j'ai trop pensé à "ma" méthode basée sur l'initialisation de ProviderFlags côté source de données (ADODataSet pour toi).

    Je vais donc résumer :

    Lorsque le cliendataset récupère les données provenant d'une source de données dataset situées sur le serveur (ex. : clientdataset1.Open), le datasetprovider lui renvoie les données ainsi que les propriétés des champs (TFields) côté serveur, qui surchargent celle sur le client. C'est pour ça que même si on a spécifié au design les TField.ProviderFlags côté clientdataset, il seront remplacés par ceux définis côté serveur (ensemble de données source ADODataSet dans ton cas). Et si tu n'as pas spécifié de propriétés côté serveur - parce que tu n'as pas de champs persistants - , les TFields seront créés dynamiquement et ce seront les props par défault qui seront transmis soit [pfInUpdate,pfInWhere].
    Etape suivante :
    Lorsque on a effectué des modifications côté client, on appelle ApplyUpdates() à partir du clientdataset. Celui-ci va transmettre le paquet d'enregs modifiés au provider auquel il est "attaché" ainsi que la collection de TFields à prendre en compte pour qu'il puisse générer les requêtes SQL. Et il s'agit bien de TFields provenant du clientdataset.
    C'est là où je me suis emmelé car en pensant que les propriétés de ces champs étant surchargés par les TFields provenant de la source...j'ai pris le raccourci de dire que les TFields côté serveur faisaient foi pour la génération de la requête SQL.
    Or ce raisonnement n'est valable que si on a des champs persistants définis sur la source de données.
    Dans ton cas, tu veux définir les propriétés ProviderFlags des TFields de façon dynamique ce qui t'évite de définir des champs persistants côté ADODataSet. Il suffit - tu n'étais pas loin - d'implémenter le gestionnaire d'évènement OnUpdateData sur le provider de la sorte :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    procedure TForm1.DataSetProvider1UpdateData(Sender: TObject;
      DataSet: TCustomClientDataSet);
    begin
      DataSet.FindField('ID_TOTO').ProviderFlags := [pfInKey, ...];
    end;
    On voit dans cet exemple que je modifie TField.ProviderFlags d'un champ provenant de la source de données (paquet d'enregs à modifier sur le serveur) issue du clientdataset.
    C'est tout :-)

    Si tu veux vérifier les ordres SQL générés, je te conseille les composants de Dan Miser : Midas Essentiel Pack => MidEss, parmi lesquels figurent TLogProvider : il hérite de => TProvider => TDataSetProvider et en plus, log tous les ordres SQL envoyés à l'ensemble de données source (ou direct serveur selon ResolveToDataSet).

    Avant de vous l'exposer, petite question.
    Est ce que ça vous intéresse de savoir de quelle manière on pourrait faire autrement ?
    Sinon, ce n'est pas la peine que je me fatigue...
    Je crois que beaucoup devraient s'intéresser à la mise en place d'architectures n-tiers au lieu de développer comme des cochons à poser des TTables à tour de bras sur tous leur écrans.
    Je salue au passage ton envie de comprendre et d'optimiser. Félicitations, ça fait du bien de voir qu'il reste des développeurs qui cherchent à faire propre.

    Je ne dois pas être le seul à me poser des questions sur le fonctionnement d'un fournisseur surtout lorsque l'on parle de SI (Banques, Assurances, Défense...) à moins que mes questions ne soient triviales pour le commun des mortels que nous sommes.
    Justement c'est loin d'être trivial il faut bien le reconnaître, mais une fois qu'on comprend les tenants et les aboutissant, on est en mesure de fournir des applis à la hauteur des SI dont tu parles...

    J'espère que ce coup là, c'est plus clair 8)

    Sylvain

    =========
    Rédaction developpez.com
    4Cent Agency
    Conseil / Developpement / Formation

  17. #17
    Membre très actif Avatar de star
    Homme Profil pro
    .
    Inscrit en
    Février 2004
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Corée Du Nord

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Février 2004
    Messages : 941
    Par défaut
    Je vois que chez developpez.com on sait de quoi l'on parle. Tu réponds d'un coup d'un seul à toutes mes interrogations et j'applaudis la pertinence de tes réponses, merci Sylvain.
    Entre temps j'en avais préparée une à mon dernier post, mais finalement, je vois que c'est peine perdue car les réponses vous les avez déjà, encore merci Sylvain.

    Aller si ça peut servir à d'autre:

    ---------------------------

    Alors, il s'agit d'initialiser dans le gestionnaire d'événement OnUpdateData du fournisseur les propriétés ProviderFlags des champs du paquet delta transmis en paramètre.
    En initialisant ces propriétés, il est possible de conditionner l'utilisation ou non de certains champs dans les clauses UPDATE et WHERE des instructions générées par le fournisseur.

    Il a fallu que je relise la Doc "Développement d'applications de bases de données - Comment controler l'application des mises à jour" pour trouver, et la Doc dit :

    ...
    Vous pouvez avoir besoin d'un contrôle encore plus précis. Par exemple, dans l'instruction précédente, vous pouvez empêcher que le champ EMPNO ne soit modifié en le retirant de la clause UPDATE et enlever les champs TITLE et DEPT de la clause WHERE pour empêcher des conflits de mise à jour quand d'autres applications ont modifié les données. Pour spécifier la clause dans laquelle un champ spécifique apparaît, utilisez la propriété ProviderFlags.

    Par exemple, le gestionnaire d'événement OnUpdateData suivant permet au champ TITLE d'être mis à jour et utilise les champs EMPNO et DEPT pour rechercher l'enregistrement désiré. Si une erreur se produit et qu'une seconde tentative de recherche est effectuée uniquement basée sur la clé, l'instruction SQL générée recherche uniquement le champ EMPNO*:

    procedure TMyDataModule1.Provider1UpdateData(Sender: TObject; DataSet: TCustomClientDataSet);
    begin
    with DataSet do
    begin
    FieldByName('TITLE').ProviderFlags := [pfInUpdate];
    FieldByName('EMPNO').ProviderFlags := [pfInWhere, pfInKey];
    FieldByName('DEPT').ProviderFlags := [pfInWhere];
    end;
    end;
    ...

    Il fallait comprendre : Le paramètre formel DataSet représente le paquet delta.

    C'est tout de même étrange, d'un côté on aurait à faire à l'ensemble de données source, et de l'autre au paquet delta provenant de l'ensemble de données client ?

    Les composants Delphi sont vraiment, mais vraiment très forts, Ouf!

    ---------------------------

    Je corrige l'avant dernier paragraphe en rejoignant les explications de Sylvain, cela nous évitera une lecture inutile.

    Merci pour le tuyau, je vais me rencarder sur MidEss, je comptais te poser la question à ce propos, mais encore une fois, ce ne sera pas la peine. merci beaucoup.

    Les choses deviennent triviales qu'à partir du moment où l'on a compris. C'est souvent le mal que l'on se donne lorsque l'on cherche à utiliser un outil à bon escient.

    Je considère ce post comme résolu, ce coup-ci c'est beaucoup beaucoup plus clair, merci à vous tous et à toi Sylvain surtout.
    Bye
    .

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

Discussions similaires

  1. Comment empêcher la mise à jour d'un contrôle à l'écran ?
    Par JojoLaFripouille dans le forum Composants VCL
    Réponses: 4
    Dernier message: 19/09/2003, 12h52
  2. [mise à jour]Comment procéder sans tout péter...
    Par FFF dans le forum Installation
    Réponses: 3
    Dernier message: 10/09/2003, 08h11
  3. Mise à jour de la version de MySQL
    Par jobstar dans le forum Administration
    Réponses: 8
    Dernier message: 18/08/2003, 10h45
  4. mise à jour de champs time (interbase)
    Par pram dans le forum XMLRAD
    Réponses: 6
    Dernier message: 04/03/2003, 10h25
  5. Réponses: 2
    Dernier message: 12/02/2003, 15h26

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