façon d'écrire la base de données Préférable Delphi applications avec les transactions et les composants de données au courant

StackOverflow https://stackoverflow.com/questions/3833432

Question

Quelle est la façon préférable d'écrire des applications de base de données Delphi utilisant les transactions et aussi des composants sensibles aux données?

Je dois écrire une application client qui ont accès à des tables InnoDB, et faire une sorte maître-détail des choses à l'intérieur des transactions. Après avoir fait des recherches sur les transactions (du point de vue général), je fais humblement une conclusion que les éléments de données non-Aware et SQL codés à la main serait le « match parfait » des transactions; Mais les composants de données ne seraient pas. Ils ne semblent pas être fait pour l'autre.

J'ai le besoin réel de transactions d'utilisation, mais d'autre part je ne pouvais pas simplement jeter les composants données au courant loin parce qu'ils les choses simplifiera grandement.

Quelqu'un pourrait-il me éclairer s'il vous plaît? Je suis googler, mais je ne l'ai pas trouvé une réponse utile. Peut-être parce que mon anglais est pas assez bon que mes mots-clés sont limités.

BTW, j'utilise Delphi 7 et évalue actuellement UniDAC comme la bibliothèque d'accès aux données.

Merci.

EDIT

Exemple pour décrire un aspect de ma question:

Imaginez un formulaire avec 2 DBGrids sur elle. La première grille est MasterGrid et au-dessus sont ces boutons: Ajouter, Modifier et Supprimer. La seconde grille est DetailGrid. Si l'utilisateur clique sur Ajouter, puis aller comme ceci:

  • Connection.StartTransaction
  • Master.Append puis Master.Post puis Master.Edit (donc le jeu de données maître a la clé primaire autoincrement, et il est modifiable maintenant)
  • Afficher la forme d'édition modalement, dans lequel l'utilisateur remplit les fiches, et également ajouter des enregistrements de détails en utilisant une autre forme.
  • Si le clic utilisateur OK, l'application ferait Master.Post et Connection.commit. Si l'utilisateur clique sur Annuler, puis l'application ferait Connection.Rollback.

Je sais que les transactions doivent être aussi courtes que possible, mais vous pouvez voir ci-dessus que la transaction est seulement aussi courte que la vitesse de l'utilisateur remplissant le formulaire.

Si j'utilise des composants non sensibles aux données, je fabriquerons insert SQLs sur la base de l'entrée d'utilisateur, puis exécuter le SQL entre StartTransaction et COMMIT. Je peux donc réaliser la transaction très court.

EDIT 2

Je vous remercie tous pour votre aimable participation. Je prends la réponse de vcldeveloper parce qu'il est la solution la plus proche de mon besoin actuel.

Était-ce utile?

La solution

D'autres ont mentionné en utilisant une combinaison de DataSetProvider et ClientDataSet d'avoir une mise à jour par lots, mais en cas d'utilisation de composants ADO ou UniDAC, vous n'avez pas besoin de la couche supplémentaire de DataSetProvider + ClientDataSet, parce que les deux mises à jour par lots de ADO et UniDAC.

ADO , ce que vous devez faire est de définir LockType de votre ensemble de données valeur ltBatchOptimistic . UniDAC , vous devez définir CacheUpdate propriété True .

Cette modification rend votre ensemble de données pour mettre en cache toutes les modifications apportées à son jeu d'enregistrements en mémoire, et de les envoyer alltogether à la base de données que lorsque vous appelez UpdateBatch méthode (ADO) ou ApplyUpdates méthode (UniDAC).

Maintenant que vous devez faire est de laisser votre insertion utilisateur / modifier un enregistrement dans l'ensemble de données maître et tout ce qu'il enregistre / elle veut dans les détails ensemble de données en utilisant tous les composants de données que vous le souhaitez. Toutes les modifications seraient mises en cache. Lorsque votre utilisateur est fait, vous pouvez commencer une nouvelle transaction, et le premier UpdateBatch d'appel (ou ApplyUpdate en cas de UniDAC) pour l'ensemble de données maître, et pour l'ensemble de données de détails, et si tout va bien, valider la transaction.

Cela rendra vos transactions à court sans avoir besoin de la couche supplémentaire de ClientDataSet.

Cordialement

Autres conseils

Je comprends votre question, je pense. Lors de l'ouverture d'un TADODataSet avec, par exemple 10 lignes de données à éditer sur un formulaire, avec des composants de données SENSIBLE, il y a des situations où vous voulez mettre en cache toutes les modifications apportées à l'ensemble des 10 lignes (et, éventuellement, des suppressions et des insertions) et engager comme un lot . Vous ne pouvez pas ouvrir la transaction au premier changement, car ce serait bloquer les autres utilisateurs changeant les mêmes données. Les transactions devraient être aussi courte que possible.

Ce que je fais dans le scénario ébauché est d'utiliser les composants suivants dans une chaîne:

TADOConnection >> TADODataSet >> TDataSetProvider >> TClientDataSet >> >> TDataSource TDBEdits etc.

Maintenant, toutes les modifications sont mises en cache dans TClientDataSet et vous pouvez l'appeler de méthode ApplyUpdates pour afficher tous les changements dans une transaction rapide. L'esprit qu'il est également possible d'utiliser plusieurs TADODataSets et plusieurs TClientDataSets pour un maître-détail la structure (de -detail-etc) avec des ensembles de données imbriqués. Toutes les modifications maître détail peuvent également être mises en cache et appliquées en un seul lot en une seule transaction. Voir l'aide et des ressources ailleurs pour tous les détails sur la mise en œuvre de cette. Au début, il est pas facile. Mais si vous l'ont vu, il est facile et offre des tonnes de possibilités. (Édition hors ligne examiner les modifications avant de les appliquer, etc.)

Pour éviter la nécessité d'effectuer des transactions importantes que j'utilise DataSetProviders et ClientDatasets (même localement).

Envisagez d'utiliser cela comme une sorte de cache et il vous donne le meilleur des deux mondes. Vous pouvez utiliser les commandes SENSIBLE données pour simplifier les choses tout en travaillant sur l'interface utilisateur. Actions de l'utilisateur sur les ensembles de données sont « enregistrées » par les ClientDataSets (sorte de cache de base de données).

Lorsque votre utilisateur sont prêts à Enregistrer les modifications apportées à la base de données (par exemple, les données de la facture est tout en place), vous appelez la méthode ApplyUpdates pour l'ensemble de données (s).

Dans le scénario le plus simple, où tous les ensembles de données sont en relation maître-détail (imbriqué par le fournisseur), le fournisseur démarre et commits / rollbacks la transaction par lui-même, de sorte que vous êtes dans une situation de automatiquement tout ou rien.

Si vous avez des relations plus complexes, vous pouvez appeler StartTransaction commencer avant d'appliquer les mises à jour pour chaque jeux CONCERNÉES ClientDataSet et à l'Raccrocher valider ou annuler au besoin). La logique du fournisseur si la connexion a une transaction active lorsque ApplyUpdates est appelé, il ne fait rien avec la transaction, mais change simplement poste à la base de données, en supposant êtes en contrôle de la transaction.

Vous devez lire TClientDataSet et comment gérer la OnReconcileError et d'expérimenter avec la technologie avant de le mettre dans des environnements de production, mais il fonctionne très, très bien pour moi.

Mes 2 cents.

Vous êtes tout à fait raison qu'une transaction write doit être aussi courte que possible, et il ne devrait pas être en vie tout le temps alors qu'un utilisateur remplit le formulaire.

La solution générale, comme cela a déjà répondu, consiste à utiliser un étage intermédiaire (un ClientDataSet). Mais le vrai problème avec votre scénario est que vous ne pouvez pas obtenir une valeur autoincrement pour la table principale sans Master.Append et Master.Post, et par conséquent vous commencez une écriture transaction bien avant qu'il ne soit réellement nécessaire.

Donc, si vous ne voulez pas utiliser le niveau intermédiaire et toujours utiliser des composants sensibles aux données avec court write les transactions que vous devriez penser à une base de données qui permet l'obtention d'une valeur auto-incrémentée sans exécuter INSERT (à table maître). L'exemple est Firebird base de données et des composants d'accès aux données FIBPlus pour Firebird appuient pleinement cette fonction.

Les transactions doivent être aussi courte que nécessaires . Le problème est de savoir comment les différentes bases de données la poignée de blocage. Les bases de données qui font essentiellement le verrouillage de ligne et peut revenir immédiatement d'une serrure sans attendre ont beaucoup moins probabilty à une impasse. En général, les inserts sont moins problématiques (bien que d'autres utilisateur ne voit pas de nouvelles lignes jusqu'à ce que déterminé, en fonction du niveau d'isolement), les mises à jour et les suppressions sont plus problématiques. Trop souvent pourrait commettre être « mauvais » aussi bien. Mise en cache des changements et de les appliquer dans une exploitation unique est une autre possibilité - mais vous avez des problèmes de poignée en raison d'autres utilisateurs de modification des enregistrements entre-temps. Il n'y a pas une solution « meilleure » - tout dépend des besoins réels. Pour certaines applications (et certaines bases de données) en gardant le dossier verrouillé tant qu'ils sont en train de changer est ok, pour d'autres non. les mises à jour de lot peut être ok dans certains scénarios et non dans d'autres. Vous devez sélectionner le modèle qui fonctionne le mieux pour votre application et base de données.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top