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

Langage Delphi Discussion :

Création d'objets "par lots"


Sujet :

Langage Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de phplive
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 179
    Par défaut Création d'objets "par lots"
    Bjr

    Voilà j'aimerais savoir s'il existe un moyen de créer des objets par lots donc N objets à la fois sans avoir à faire N fois Create ni à allouer N blocs de mémoire.

    En effet j'essai de charger le contenu d'une table d'une base de données dans une liste d'objets

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Delphi               <-> Base de données 
     
    TItemList            <-> Table
    +-- TItem            <-> +-- Enregistrements
        +-- TAttribut    <->     +-- Champs
    Sachant que mon enregistrement comporte jusqu'à 30 champs lorsque je charge 1000 enregistrements j'ai déjà 30 000 attributs à créer : or c'est assez long ...

    Le problème provenant spécifiquement de l'allocation des attributs je me demandais s'il était possible d'en allouer par bloc de 1000 ou plus en une seule fois et de les instancier au travers d'un pattern factory par ex ?

    Ha oui en fait mes TAttributs utilisent les interfaces ainsi que le comptage de références mais ça doit pas changer grand chose au problème.

    merci

    XP - Delphi 7

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 086
    Par défaut
    Tu fais un système de persistante, tu devrais voir si InstantObjects ne répond pas à ton problème ... Sinon regarde autour des RTTI, pour mapper tes tables avec des objets, ... je l'ai déjà fait, c'est un sacré travail, faut d'ailleurs que je la ré-écrive pour la rendre indépendante de la lib de mon employeur, et ainsi la rendre compatible D2009 ... (c'est la lib interne qui la rend pour le moment non compatible)

    Pour l'allocation en masse, à part une boucle, ... pas d'allocation en masse

    Sinon, tu t'aperceveras que tout chargé, c'est une erreur, cela prendre du temps (ton problème justement), des ressources, la couche de persistance précédemment développé dans ma boite était comme ça, et c'est lourd pour les listings ! J'ai donc réécrit une Peristance sur le principe du LazyLoading qui ne charge que le minimum, ... cela charge par exemple, une liste d'ID, puis lorsque tu sollicites dans la collection une instance, cela lance la requête pour lire l'enregistrement entier
    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
    Membre Expert

    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 897
    Par défaut
    Je confirme que tout charger en mémoire n'est pas une bonne solution. J'utilise quotidiennement les InstantObjects, et je me suis également trouvé confronté au problème de manipuler des tables de plusieurs milliers de lignes ce qui n'est pourtant pas très volumineux. Cela prend pas mal de temps, même en désactivant les options de création automatique d'une instance pour un enregistement pour les composants InstanExposer (foObjects, et foThorough à False).
    Pour contourner ce problème, j'ai mis en place une solution qui ressemble à celle que nous a exposé ShaileTroll. J'utilise tout bêtement un ADOQuery pour lire une table volumineuse ou non, puis je crée les instances des enregistements dès que j'en ai besoin. Chaque enregistrement dispose d'un GUID, le rendant ainsi unique et les instantObjects proposent pour chaque classe une fonction retrieve qui permet d'instancier un enregistrement à partir de son GUID.
    De toute façon, il est rare que lors d'un traitement on ait réellement besoin d'utiliser tous les enregistrements d'une table. Et si ce n'est que pour l'afficher dans une grille. Pourquoi alors créer une instance pour chaque enregistrement dans ce cas ?
    En revanche, dans la couche métier l'instanciation des enregistrements simplifie l'écriture des traitements. Dans cette couche, on manipule qu'un nombre restreint d'objets en général.

  4. #4
    Membre confirmé Avatar de phplive
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 179
    Par défaut
    Bonjour

    Et merci pour vos réponses.

    C'est rassurant de voir que d'autres arrivent à la même conclusion : les objets c'est bien mais c'est ... lent !
    Enfin, lent, tout est relatif.

    J'ai effectivement jetté un coup d'oeil sur InstantObject en fait je m'en inspire, en bcp plus simple, mais chut ! lol !

    Naturellement je ne compte pas précharger le contenu de toutes mes tables dans des objets Delphi : pourquoi faire en effet ?


    Je me contente de :

    1 Chargement de certains objets depuis un espace de stockage
    2 L'affichage de mes objets en utilisant les composants standard de la VCL (mais pas les composants data-aware !)
    au travers d'un MVP (enfin cette partie là est pas encore mise au point T'Oh !)

    Les problèmes commencent à apparaître avec les affichages dans des ListViews : curieusement avec des TreeViews c'est
    beaucoup plus simple. Peut-être aussi parce que mes objets métiers s'organisent nativement sous la forme d'une arborescence.

    Donc pour en revenir à mes allocations d'objet en bloc (je sais j'y tiens) depuis j'ai pas mal fouiné dans le code du TObjet de l'unité system.pas histoire de voir comment Delphi instancie un objet.

    Lors de l'appel au constructeur il n'invoque pas directement la méthode Create() mais NewInstance()
    NewInstance() alloue la mémoire pour l'objet puis appelle InitInstance()
    InitInstance() initialise à zéro le bloc mémoire alloué, la VMT de l'objet ainsi que ses IMT (ce qui est mon cas car tous mes objets gèrent le comptage de références)
    Finalement la méthode Create() est exécutée

    Il apparaît donc qu'il est facile de
    1) gèrer l'allocation de mémoire soit même en surchargeant NewInstance() et FreeInstance()
    2) on peut même s'affranchir de l'appel à la méthode InitInstance si dans le constructeur on initialise aucune variable, on ne créé aucun autre objet (idem pour la méthode AfterConstruction)

    J'ai testé avec un objet que je créé comme modèle et que je recopie ensuite n fois de suite avec move() dans un buffer créé via GetMem()
    Puis un simple transtypage du style
    IMonObjet := TMonObjet( Pointer(Integer(Buffer)+i*TMonObjet.InstanceSize) ); et ça fonctionne l'objet est opérationnel.

    Je vais donc passer à des tests à grande échelle histoire de voir si je gagne en performance.

  5. #5
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 086
    Par défaut
    As tu pensé au BeginUpdate et EndUpdate de la TListView (aussi pour le TreeView) qui accélère grandement le remplissage en masse !

    Lorsque j'ai fait ma couche de persistance objet, j'ai utilisé le DBGrid qui pointent sur une Collection de la couche, la collection n'étant que l'encapsulation d'un DataSet), la DBGrid est évidemment en ReadOnly et un formulaire avec un controlleur avec se charger de mapper chaque propriété à un control (non-DBWare aussi),

    J'aurais du ensuite faire en sorte que l'objet envoie une notification à sa collection pour lui dire de remplacer ces données (le dataset doit être uniquement en mémoire genre TClientDataSet ou TMemoryDataSet), à partir de celle de l'objet pour que l'affichage soit à jour (en fait, je relance pas carrément la requête ), pense que tu devras aussi gérer des notifications si l'instance affiché a été changé ...

    Ensuite, surcharger InitInstance, bon courage, ça doit être un sacré boulot, ... commence d'abord par voir si c'est vraiement ça qui bloque, ... moi ça me surprendrait surtout si te ne charge pas 30 000 objets avec chacun 30 propriétés mais juste une petite liste ...

    Ton objet est opérationnel, mais si tu copie la zone mémoire, finalement, tous les objets pointent sur les mêmes choses, et si tu as des sous-objets ou des pointeurs, des tableau dynamique, des strings, tu as recopié l'adresse de tous ces pointeur, mais pas le contenu, as-tu pensé à les réallouer ... car sinon, une modification sur un "objet" modifiera le contenu d'une autre instance, ...

    Tu devrais mesurer les temps de chaque tache avec QueryPerformanceCounter, pour savoir où est vraiement la lenteur
    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 Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 933
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 933
    Par défaut
    Pourquoi ne pas essayer un TStringStream.ReadComponent
    Tu crées une simple chaîne formatée (style DFM) avec les infos de ta BD.

  7. #7
    Membre Expert

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Par défaut
    Citation Envoyé par phplive Voir le message
    Le problème provenant spécifiquement de l'allocation des attributs je me demandais s'il était possible d'en allouer par bloc de 1000 ou plus en une seule fois et de les instancier au travers d'un pattern factory par ex ?
    Il faudrait commencer par identifier précisément la raison des lenteurs. En particulier, s'il s'agit de l'allocation mémoire en elle-même ou ensuite de l'initialisation de l'instance.
    Si c'est l'allocation mémoire, je te conseillerais déjà de changer de gestionnaire de mémoire. Tu pourrais utiliser FastMM4. D'ailleurs maintenant, c'est le nouveau gestionnaire de Delphi depuis BDS2006.
    Mais, je pense que c'est plutôt l'initialisation autour qui doit te prendre le plus de temps.

    C'est rassurant de voir que d'autres arrivent à la même conclusion : les objets c'est bien mais c'est ... lent !
    Enfin, lent, tout est relatif.
    C'est vrai. Mais en même temps soyons honnête ! Les outils de mapping O/R et autres frameworks de persistances n'ont jamais été réputés pour leurs performances.
    Pour moi, ils ne se justifient que si c'est pour monter au dessus de la base un modèle objet radicalement différent de la structure des tables. Sinon, on dégrade considérablement les performances pour pas grand chose (à si pardon, pour ne pas montrer qu'on ne sait pas écrire une requête SQL).

    Je reste persuadé que le meilleur compromis entre la souplesse d'utilisation et les performances serait une architecture avec des services métiers d'un côté (et donc uniquement du code) qui travaillent sur des data-objects (en gros des records typés, structurés correspondant aux enregistrements des tables).
    Les data-objects sont générés plus ou moins automatiquement avec un générateur de code, à partir de la structure de la base. On peut ainsi les creer directements en lots avec des API bas niveau tel que OLEDB ou OCI, en s'affranchissant complètement de l'architecture DataSet de Delphi.
    Puis les services métiers présentent une interface objet sur ces structures et implémentent la logique métier...

    J'ai donc réécrit une Peristance sur le principe du LazyLoading qui ne charge que le minimum, ... cela charge par exemple, une liste d'ID, puis lorsque tu sollicites dans la collection une instance, cela lance la requête pour lire l'enregistrement entier
    C'est marrant, je fais exactement le contraire : J'essaie de précharger un maximum de données au début des traitements pour minimiser ensuite le nombre de requêtes nécessaires.
    Tu obtiens de meilleurs performances si tu exécutes une requête qui te retourne les 1000 enregistrements dont tu vas avoir besoin que si tu exécutes ta requête 1000 fois en ne recupérant qu'un seul enregistrement à la fois (surtout avec Delphi et les DataSets).

  8. #8
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 086
    Par défaut
    Citation Envoyé par Franck SORIANO Voir le message
    C'est marrant, je fais exactement le contraire : J'essaie de précharger un maximum de données au début des traitements pour minimiser ensuite le nombre de requêtes nécessaires.
    Tu obtiens de meilleurs performances si tu exécutes une requête qui te retourne les 1000 enregistrements dont tu vas avoir besoin que si tu exécutes ta requête 1000 fois en ne recupérant qu'un seul enregistrement à la fois (surtout avec Delphi et les DataSets).
    Ah mais j'ai les deux modes ! j'ai un système de collection qui va selon les options charger la requête au complet ou juste la liste des ID, ... et attention, il y a le LazingLoading pour la collection (ID ou *) mais tu peux aussi avoir le LazingLoading pour l'instance, je rempli l'instance de la collection qu'au moment où je vais l'utiliser, je ne lance pas de requête, je recopie le dataset interne de la collection (je relance une requête si il n'y a que l'ID), donc une seule requête SQL mais RTTI différé !

    Et donc pour les traitements de boucle, je peux appeler la collection via la méthode First qui fonctionne selon l'option général, ou alors la méthode Load qui supplentera l'option général pour tout charger. !

    Comme le dit Franck SORIANO, Pour les références publiées il y a FieldAdress qui permet le mapping, ... il y a des choses très interressantes aussi avec le Owner quand tu le retire, cela joue sur les références ... encore des trucs implicites !

    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
    procedure ChangeOwner(var AComponent: TComponent; AOwner: TComponent);
      var
        SaveComponent: TComponent;
        Field: ^TComponent;
        I: Integer;
      begin
        if Assigned(AComponent) and Assigned(AComponent.Owner) and Assigned(AOwner) then
        begin
          if AComponent.Owner <> AOwner then
          begin
            SaveComponent := AComponent; // Mémorise la référence avant qu'elle soit mis à nil
            AComponent.Owner.RemoveComponent(AComponent); // RemoveComponent mets la référence publiée de AComponent dans son Owner a nil !
            AOwner.InsertComponent(SaveComponent);
            AComponent := SaveComponent;
     
            if AComponent is TWinControl then
              for I := 0 to TWinControl(AComponent).ControlCount - 1 do
              begin
                SaveComponent := TComponent(TWinControl(AComponent).Controls[I]);
                Field := SaveComponent.Owner.FieldAddress(SaveComponent.Name);
                ChangeOwner(SaveComponent, AOwner);
                if Field <> nil then
                  Field^ := SaveComponent;
              end;
          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

  9. #9
    Membre confirmé Avatar de phplive
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 179
    Par défaut
    Bjr à tous

    Haha je vois que le persistent framework fait débat !

    Ha si seulement nos bases de données étaient objet ...

    Ha tient ça existe (en open source s'entend) : EyeDB quelqu'un connait ?


    C'est dingue le nombre de choses qu'il faut écrire rien que pour faire un modeste petit "framework" pour gérer des objets plutôt que ces fichus appels SQL direct ! Une gestion de listes, de cache, de messages, des algos de tri, de recherche, un générateur SQL et j'en passe ...

    Heureusement les interfaces me permettent de gèrer facilement la libération de tous mes objets (je suis sous D7 donc pas Garbage Collector )

    Afin de m'affranchir des problèmes de relative lenteur lorsque le nombre d'objets à créer augmente, j'ai commencé à tester les Listviews en mode virtuel : j'associe une liste d'objets métiers à ma LV. Ma LV ne connait (et encore pas directement) qu'un seul objet métier "maître" : la liste métier qui constitue en quelque sorte un point d'entrée dans le modèle.
    C'est cette liste métier qui indique à la LV ce qu'elle doit afficher. La liste métier, elle, reste reliée à un TQuery (pas directement en fait mais peu importe) et agit comme un sorte de curseur en chargeant dynamiquement les données de chaque enregistrement du TQuery dans 1 à N objets. Comme ce sont tjrs les mêmes objets ça va vite La liste métier reste donc vide tant qu'on ne sélectionne pas explicitement un objet auquel cas il est ajouté à la liste métier.

    Inconvénient : je conserve en permanence un connexion au TQuery et à la base de données.
    La LV attend un nombre d'items explicite.

    Pour le moment je n'ai pas encore trouver de moyen pour rendre les composants de la VCL "business object aware" comme dirait JCVD.
    Je pensais que ce serait la partie la plus facile hé ben non

  10. #10
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 086
    Par défaut
    Citation Envoyé par phplive Voir le message
    Heureusement les interfaces me permettent de gèrer facilement la libération de tous mes objets (je suis sous D7 donc pas Garbage Collector )
    Moi, j'ai tout basé sur un owner commun et la gestion d'un owner secondaire, les collections étant propriétaires des objets instanciés (sauf si demande d'extraction), et donc libère leur objet à leur propre libération, donc si l'on a un objet A, qui à une relation 0-N avec B, et B 0-C à avec C, si tu parcours tous les objets dans une boucle via le framework, libéré A, libère tous les petits B et C ... c'est tellement plus intéressant de maîtriser la mémoire, moi je trouve que c'est un aspect passionnant de la programmation, et oblige à un minimum de rigueur, ... qui se perd avec le GC ...

    Ensuite, quand tu as un DBGrid, la connexion Query reste ouverte, cela ne fait pas grande différence non ? Mets toutes les options que ton Query soit le moins gourmand (ReadOnly, Cache, ...)

    Pour faire une sorte ObjetSource (reprenant le DataSource), oui, c'est prise de tête, au bureau on a en fait un, j'ai du reprendre le code au moins une bonne dizaine de fois, et c'est moche moche moche dedans (toute ma persistance utilise du variants, et de plus le MappeurUI devait être compatible avec l'ancienne couche persistante, et aussi capable de gérer du DataSouce) ... sinon l'interface, ça va, pas top, mais bon ...
    MappeurUI intégré en ComponentEditor de Delphi

    En base Objet, tu as O2 (DB Orsay)

    Je vais être lourd, tu as testé BeginUpdate et EndUpdate ? Peux tu donner des ordres de temps pour 100, 1000 et 10000 enreg pour que se fasse un idée ce que tu considères comme lent ? 100ms ? 1s ? 10s ? 1minute ???
    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

  11. #11
    Membre Expert

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Par défaut
    Citation Envoyé par phplive Voir le message
    Ha si seulement nos bases de données étaient objet ...
    Comme l'as fait remarquer ShaiLeTroll. Ca existe, et depuis longtemps.
    Sauf que dans la pratique, elles n'ont pas réussi à séduire le marché (beaucoup trop lentes il me semble, mais je n'ai jamais essayé).

    Heureusement les interfaces me permettent de gèrer facilement la libération de tous mes objets (je suis sous D7 donc pas Garbage Collector )
    Fait attention. Les interfaces fonctionnent par comptage de références. Ce qui a pour effet que dès que tu as un cycle dans tes références (L'objet A est en relation avec B. Il possède une référence sur B. B est en relation avec C, qui a son tour est en relation avec A...), plus rien n'est libéré, même si tu ne possède plus aucune référénce sur le cycle (les vrais GC n'ont pas cette limitation).

    Afin de m'affranchir des problèmes de relative lenteur lorsque le nombre d'objets à créer augmente, j'ai commencé à tester les Listviews en mode virtuel : j'associe une liste d'objets métiers à ma LV. Ma LV ne connait (et encore pas directement) qu'un seul objet métier "maître" : la liste métier qui constitue en quelque sorte un point d'entrée dans le modèle.
    C'est cette liste métier qui indique à la LV ce qu'elle doit afficher. La liste métier, elle, reste reliée à un TQuery (pas directement en fait mais peu importe) et agit comme un sorte de curseur en chargeant dynamiquement les données de chaque enregistrement du TQuery dans 1 à N objets. Comme ce sont tjrs les mêmes objets ça va vite La liste métier reste donc vide tant qu'on ne sélectionne pas explicitement un objet auquel cas il est ajouté à la liste métier.
    Ca a l'air pas mal. Nous on fonctionne un peu sur le même principe : Nos objets métier sont en réalité une classe d'adaptation sur un dataset. Ils offrent une vue objet de l'enregistrement courant du dataset.
    Ca revient un peut au même, sauf que notre objet est à la fois un objet et une liste, et qu'on ne conserve en mémoire qu'une seule instance de l'objet, les données étant stockées dans le dataset.
    L'avantage c'est que selon nos besoins, on peut manipuler soit l'objet de gestion, soit directement le dataset.
    Par contre, ce n'est pas vraiment un modèle objet, mais c'est suffisant pour nos besoins.

    Pour le moment je n'ai pas encore trouver de moyen pour rendre les composants de la VCL "business object aware" comme dirait JCVD.
    Je pensais que ce serait la partie la plus facile hé ben non
    Une solution relativement simple consiste à passer par une classe d'adaptation que tu définis en créant un dataset personnalité (tu dérives la classe TDataset). Cette dernière se présente alors comme un dataset. Tu peux brancher un DataSource dessus. Par contre, lorsque le dataset se déplace d'une ligne à une autre, tu lui fait lire les données de ta liste d'objets métier. Lorsque le dataset lit un TField, tu lui fait lire un champ de l'objet métier... En écriture, tu mets à jour les champs de ton objet au moment du Post du dataset...
    J'ai un tuto en cours sur le fonctionnement du TDataSet.

  12. #12
    Membre confirmé Avatar de phplive
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 179
    Par défaut
    Bsr

    Hum vous proprosez tous des idées intéressantes dificile de choisir

    Oui j'utilise beginupdate/endupdate avec tous les composants qui possèdent ces méthodes : c'est clair que ca accélère un max

    Lent ?
    Hum sachant qu'au final j'ai des utilisateurs peu enclin à la patience je dirais est lent tout ce qui n'est pas perçu comme instantanné ou qui entraîne un clic rageur plusieurs fois de suite au même endroit dans l'espoir d'accélérer les choses

    personnellement
    1 min pour 10000 enreg c'est hors de question !
    10" c'est lent
    1" c'est correct
    en 100eme ou en 1000eme : idéal mais tout le monde n'a pas un Dual Core à 3GHz

    Pour l'utilisateur une seconde ça fini de toute façon par se traduire par un "mais qu'est ce qu'il rame ton prog !"


    Les interfaces : moi aussi au début j'étais réticent. C'est plus lourd (voir plus lent un QueryInterface ça coûte), de plus on ne sait jamais quelles sont les interfaces implémentées par un objet => faut documenter !
    Mais depuis j'ai changé d'avis et surtout j'ai définitivement adopté le comptage de références : les strings sous Delphi sont d'ailleurs gérées ainsi et tout va pour le mieux.
    Bien sur on va me dire les interfaces gaffe, les références circulaires danger !


    C'est vrai mais avec les objets classiques je ne compte plus le nombre de fois où un objet était détruit trop tôt et dans des situations plutôt délicates à tracer même au débogueur.

    Avec les interfaces c'est l'inverse : on risque de ne pas libérer certains objets voir certaines chaînes d'objets dès qu'on a une structure qui prend la forme d'un graphe.

    Pour parer à ce problème j'utilise des weaks références pour caser le références circulaires explicites.
    Ensuite comme j'ai créé ma propre classe d'objet interfacé je compte le nombre d'objets crées et libérés ainsi je peux detecter si des objets persistent en mémoire. Je peux faire la distinction par type de classe. Ca permet de voir quels sont les objets en cause.
    Enfin lorsque j'ai un doute tous mes objets implémentant par défaut le visitor pattern je parcours tous mes objets jusqu'à tomber sur un cycle

Discussions similaires

  1. Remplacer caractère ' ( quote ) par "\n"
    Par Eric45 dans le forum C++
    Réponses: 3
    Dernier message: 28/11/2007, 00h56
  2. Réponses: 5
    Dernier message: 30/05/2005, 16h58

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