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

C# Discussion :

[C#] Parcourir TreeNode TRES vite ! Besoin de conseils avisés


Sujet :

C#

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Par défaut [C#] Parcourir TreeNode TRES vite ! Besoin de conseils avisés
    Bonjour,

    J'ai un projet c# sur lequel on m'a demandé d'améliorer les temps de chargement et surtout de relecture d'un treeview dans lequel sont affichés des temps.

    Actuellement, le temps de chargement est de 10 secondes pour 1 000 enregistrements. Ceci est long car il y a une lecture de base sql serveur (par DataTable, puis affiné sur DataRow en fonction de la position dans l'arbre).

    Je cherche la meilleure méthode pour améliorer ce temps de chargement et je suis ouvert à tout conseils avisés.

    Merci,
    Potus.

  2. #2
    Membre Expert
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    793
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Mayenne (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 793
    Par défaut
    Peut-on avoir du code et un peu plus de contexte ?

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Par défaut
    Citation Envoyé par asmduty Voir le message
    Peut-on avoir du code et un peu plus de contexte ?
    Ok, mais je vais vous donner les principales fonctions et les principaux paramètres qui nous intéressent dans le contexte de cette question :

    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
    public void calcule_temps(TreeView tree)
    {
     // LOG : J'écris dans un fichier texte ici le temps de départ (0)
     //* for (int i=0; i< tree.Nodes.Count; i++)
     //* {  
      DataTable mesTemps = new DataTable
      String maReq = "SELECT dateDebut, dateFin, ... champ5 FROM temps ";
      mesTemps = cnx.execute_req_dataTable(maReq);
    
      enfants_calcul(tree.Nodes[i], mesTemps)
     // LOG : J'écris dans un fichier texte ici le temps d'arrivée (10 s. + tard)
     //* } 
     // NB : On a vu que le code avec en préfixe //* ne sert à rien}
    
    public void enfants_calcul(TreeNode parent, DataTable prmTemps)
    {
     TimeSpan heures = new TimeSpan(0,0,0);
     DataRow[] DR_Heures;
    
     for (int j=0; j < parent.Nodes.Count; j++)
     {
       DR_heures = calcul_Temps_DataRow(parent.Nodes[j], prmTemps)
       heures = Calcul_heures(DR_Heures);
     }
    }
    public DataRow[] Calcul_Temps_DataRow(TreeNode parent, DataTable DtTemps)
    {
    for (int k=0; k< parent.Nodes.Count; k++)
     {
      // monNoeud : Identifiants initialisés avant et TRES rapide pour 
      // les affecter, le problème n'est pas là.
       string monNoeud = parent.Nodes[k].Tag.ToString(); 
       DataRow[] DrTemps = null;
       DataRow[] lignes_tosendback = null;
       try
        {
           string maSelection = " idNoeud = " + monNoeud;
           DrTemps = DtTemps.Select(mySelect);
           lignes_tosendback = new DataRow[DrTemps.Length];
        }
        catch{}
    
        int i = 0;
        foreach (DataRow ligne in DrTemps)
        {
          if ( ici comparaison de plage de dates pour une période donnée)
          {
             lignes_tosendback.SetValue(ligne, i++)
          }
          if (lignes_tosendback[0] == null)
            return new DataRow[0];
    
          return lignes_tosendback;
        }
     }
    }
    public TimeSpan Calcul_Heures(DataRow[] parent)
    {
      TimeSpan dif = new TimeSpan();
      for (int i=0; i < parent.Length; i++)
      {
        // Nouvelle TRACE DEBUT ici suite aux dernières demandes (BlueDeep & Nathanael)
        DateTime d1 = (DateTime)parent[i]["datedebut"];
        DateTime d2 = (DateTime)parent[i]["datefin"];
        dif += d2.Subtract(d1);
        // Nouvelle TRACE FIN ici suite aux dernières demandes (BlueDeep & Nathanael)
      }
      if (dif.TotalSeconds <= 0)
        return new TimeSpan(0,0,0);
      else
        return dif;
    }
    NB : cnx.execute_req_dataTable correspond à une fonction qui exécute une requete et la retourne vers un dataTable.

    Il faut rendre à César ce qui est à lui, je suis le 4 ou 5ème programmeur depuis le début de ce projet et ce code n'est pas de moi. Donc vous pouvez vous lacher si vous voulez, mais je cherche surtout une méthodologie pour aller plus vite comme vous avez du le comprendre.

    J'ai besoin de cette fonction de recalcul de temps global à chaque ajout de temps. S'il s'agissait d'une simple initialisation, on pourrait se contenter d'un premier temps long, mais là ca devient lourd à chaque fois qu'il faut recalculer ces temps.

  4. #4
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Potus Voir le message
    ce code n'est pas de moi.
    Il est en effet exceptionnellement pourrave.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    Il est en effet exceptionnellement pourrave.
    Comme vous l'avez compris, c'est une des raisons qui fait que je vais le ré-écrire.

    Si on sort du contexte de cette programmation, où j'essaye de vous porter. Le principe de lecture d'un DataTable, affiné par la suite par un DataRow ne semble pas trop stupide. Mais on s'apperçoit rapidement que cela devient lourd si on a un arbre qui devient plus complexe. Autrement dit, avec 100 enregistrements ça va vite, avec 1 000 ça devient lourd !

    A part ré-écrire ce code (ce qui est déjà acquis pour moi), vous voyez d'autres méthodes plus rapide ?

  6. #6
    Modérateur

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2007
    Messages
    1 996
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 996
    Par défaut
    Je pense qu'il va en effet falloir penser à revoir le code.
    Autre piste d'amélioration : dans ta requête, remplace le par un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select champ1, champ2, etc.
    (Bon, ce n'est pas ça qui divisera le temps d'exécution par 2 non plus. C'est une optimisation mineure. Il faut que tu en passes par une amélioration du code...)

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Par défaut
    Citation Envoyé par calagan99 Voir le message
    Bon, ce n'est pas ça qui divisera le temps d'exécution par 2 non plus. C'est une optimisation mineure. Il faut que tu en passes par une amélioration du code...
    En fait, c'est déjà sur le principe champ1, champ2, ... champ5. Je n'ai pas voulu vous saouler avec des << détails >> de code, car je cherche carrément une autre façon d'attaquer ce sujet.

    Comme personne ne se lance, je vais vous donner des pistes auxquels j'ai déjà pensé et que je ne voulais pas vous donner pour ne pas vous influencer (dans le bon ou le mauvais sens, car je ne suis pas sûr de ces pistes) :
    - utilisation de thread ? La question étant là, est-ce que l'on va vraiment gagner du temps ? Pas de risque de conflit à première vue puisqu'on consulte des données différentes.
    - recalculer uniquement le temps correspondant aux racines parentes les plus hautes (ce que je voulais éviter à la base, mais je ne vois pas beaucoup d'autres solutions); Cela revient à faire des refresh partiels.

  8. #8
    Membre éprouvé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Avril 2006
    Messages
    1 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2006
    Messages : 1 627
    Par défaut
    Et faire cumuler les temps par le serveur SQL ? Avec une requête judicieuse tu dois pouvoir récupérer l'ensemble de tes nœuds et leur valeur, il ne te restera que la présentation.

  9. #9
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Potus Voir le message
    Comme personne ne se lance, je vais vous donner des pistes auxquels j'ai déjà pensé et que je ne voulais pas vous donner pour ne pas vous influencer (dans le bon ou le mauvais sens, car je ne suis pas sur de ces pistes) :
    - utilisation de thread ? La question étant là, est-ce que l'on va vraiment gagner du temps ? Pas de risque de conflit à première vue puisqu'on consulte des données différentes.
    - recalculer uniquement le temps corresondant aux racines parentes les plus hautes (ce que je voulais éviter à la base, mais je ne vois pas beaucoup d'autres solutions); Cela revient à faire des refresh partiels.
    Bon, commençons par le commencement : identifier les parties de code chronophage.

    Pour cela tu vas mettre des variables de temps un peu en limite de tous les blocs interessant et nous donner les résultats.

    A partir du moment où on aura identifier le/les chronophages, ce sera plus facile et en tout cas à faire avant de partir sur les solutions exotiques (d'autant que les optims "exotiques" ne sont intéressantes que si on identifie ce qui consomme du temps).

    Donc tu vas mettre des trucs tout bête du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    DateTime begin1 = DateTime.Now;
    //**** mon code que je soupçone de crouter du temps */
    DateTime end1 = DateTime.Now;
    TimeSpan elapsedTime = end1 - begin1;
    Et tu nous mets ensuite les valeurs des "elapsed" avec les blocs en cause.

  10. #10
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    A noter que l'utilisation de Stopwatch est preferable pour du debug

  11. #11
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Nathanael Marchand Voir le message
    A noter que l'utilisation de Stopwatch est preferable pour du debug
    Yes, mais là on est pas au quart de milliseconde près, on veut juste une indication; donc je lui suggère une solution simplissime capable d'être mise en oeuvre sans même aller voir de la doc.

    Par ce que, pour l'instant on parle de problème de temps de réponse mais on a pas encore identifié ce qui posait problème.

    Il faut donc commencer par là.

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Par défaut
    Je suis parti à la pêche aux chronophages, et je vous ai ajouté la fonction de calcul de temps (deuxième message de ce sujet) où je pense que le problème réside. Si je ne vous l'avais pas mis auparavant c'est plus du à un oubli que pour vous induire en erreur. En fait, c'est justement parceque vous m'avez demandé plus de précisions que j'ai vu que j'avais oublié de vous la mettre.

    La fonction s'appele donc Calcul_Heures et je vous ai mis en rouge les deux endroits où je fais appel à une fonction de trace qui écrit dans un fichier texte (que je vous mets en lien ici [trop gros pour être mis en pièce jointe]).

    Vous constaterez que le temps de départ et à 24 secondes et termine à 42 secondes. Cela fait 18 secondes, comptez 8 secondes pour écrire dans le fichier texte et vous retombez bien sur les 10 secondes que je vous indiquais au départ.
    Pour chaque ligne, la dernière valeur correspond à l'identifiant du noeud, celle entre parenthèses correspond à l'indice (cas où on a plusieurs temps pour un même noeud).

    Je ne fais pas de conclusion hative, mais il semble que le plus long soit bien de cumuler le temps. Il ne faut pas oublier que tout cela doit être dynamique et que l'on doit avoir un temps sur chaque noeud (parents, grand-parents, etc ... compris).

  13. #13
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Potus Voir le message

    Je ne fais pas de conclusion hative, mais il semble que le plus long soit bien de cumuler le temps. Il ne faut pas oublier que tout cela doit être dynamique et que l'on doit avoir un temps sur chaque noeud (parents, grand-parents, etc ... compris).
    Bon, la réponse est absolument évidente : un contrôle sert à interagir avec l'utilisateur mais surtout pas à être utilisé comme stockage de données.

    Ici, le problème vient manisfestement du fait que les choses sont faites en dépit du bon sens : lecture depusi la DB vers les controles, puis calcul à partir des données écrites dans les controles, alors que l'odre normal des opérations eut été :

    - lecture depuis la DB
    - calcul sur les données lu (et pas écrites dans les controles écrans).
    - affichage.

    De plus, si tu as posté un code complet,on ne comprend pas pourquoi l'ensemble de la table temps est relue à chaque noeud. (dans caclul_temps).

    Bref, le flux d'opérations est aberrant. Déja metter en cache les données de la table temps à la première lecture ferait gagner 90% du temps.

    je pense que cela résoudra le problème.

  14. #14
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    C'est vraiment utile l'écriture dans un fichier? Ca a l'air de parasiter plus qu'autre chose les tests

  15. #15
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Nathanael Marchand Voir le message
    C'est vraiment utile l'écriture dans un fichier? Ca a l'air de parasiter plus qu'autre chose les tests
    C'est pas l'écriture dans le fichier le problème; le problème c'est ce truc débile :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     for (int i=0; i< tree.Nodes.Count; i++)
     {
      DataTable mesTemps = new DataTable
      String maReq = "SELECT * FROM temps ";
      mesTemps = cnx.execute_req_dataTable(maReq);
     
      enfants_calcul(tree.Nodes[i], mesTemps)
     // LOG : J'écris dans un fichier texte ici le temps d'arrivée (10 s. + tard)
     }

  16. #16
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    C'est pas l'écriture dans le fichier le problème; le problème c'est ce truc débile :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     for (int i=0; i< tree.Nodes.Count; i++)
     {
      DataTable mesTemps = new DataTable
      String maReq = "SELECT * FROM temps ";
      mesTemps = cnx.execute_req_dataTable(maReq);
     
      enfants_calcul(tree.Nodes[i], mesTemps)
     // LOG : J'écris dans un fichier texte ici le temps d'arrivée (10 s. + tard)
     }
    Oh une boucle de requête!
    Bon à vrai dire j'ai pas trop capté ce qu'il cherche à faire le mossieur avec son code la...
    Et les datatables et datarow c'est utile aussi?

  17. #17
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Nathanael Marchand Voir le message
    Et les datatables et datarow c'est utile aussi?
    C'est pas très élégant, mais après tout, c'est un stockage mémoire comme un autre; mais ce n'est pas le souci principal ici.

  18. #18
    Rédacteur
    Avatar de WOLO Laurent
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    Mars 2003
    Messages
    2 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Congo-Brazzaville

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2003
    Messages : 2 741
    Par défaut
    Je suis d'accord avec bluedeep, pourquoi jouer ce code 1000 fois ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    DataTable mesTemps = new DataTable
      String maReq = "SELECT * FROM temps ";
      mesTemps = cnx.execute_req_dataTable(maReq);
    En plus si l'on refléchit bien, l'on peut faire tous les calculs depuis la base de données et il ne restera plus qu'à afficher le code.

    Découvrez la FAQ de MS SQL Server.
    La chance accorde ses faveurs aux esprits avertis !

  19. #19
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Par défaut
    Citation Envoyé par Nathanael Marchand Voir le message
    C'est vraiment utile l'écriture dans un fichier? Ca a l'air de parasiter plus qu'autre chose les tests
    Je confirme que l'écriture du fichier ne parasite pas, quand je l'enlève je retombe à 10 secondes. En fait, c'était pour vous fournir des données que je vous l'ai mis dans un fichier texte.

    Citation Envoyé par Bluedeep Voir le message
    Bon, la réponse est absolument évidente : un contrôle sert à interagir avec l'utilisateur mais surtout pas à être utilisé comme stockage de données.
    Là malheureusement, j'ai un boulet sur lequel il va falloir que je me batte avec des personnes non informaticiennes qui on demandé aux premiers programmeurs de faire ce genre d'abération. Et bien sûr comme c'était au début du projet, sans beaucoup de données, et sans doute des débutants sur ce sujet ils ont dit amen. C'est joli d'avoir un contrôle avec des temps stockés sur toute l'arborescence, ca le devient moins quand ça met trois plombe à s'afficher !

    Citation Envoyé par Bluedeep Voir le message
    Ici, le problème vient manisfestement du fait que les choses sont faites en dépit du bon sens : lecture depuis la DB vers les controles, puis calcul à partir des données écrites dans les controles
    Je vais détailler ce que tu as analysé :
    - lecture depuis la DB (vrai pour les temps)
    - puis calcul à partir des données écrites dans les controles (faux, ce qui est fait c'est que l'on récupère les noeuds dans les controles pour se positionner à chaque fois sur les << bons enfants >> de l'arborescence).

  20. #20
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2009
    Messages
    122
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 122
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    De plus, si tu as posté un code complet,on ne comprend pas pourquoi l'ensemble de la table temps est relue à chaque noeud. (dans caclul_temps).
    En fait je viens de voir l'abération.

    La première boucle ne sert absolument à rien car le tree.Nodes.Count est toujours à 1 !

    Donc il n'y a qu'une lecture !!

    TreeNode.Racine = 1
    |- Enfant 1
    | |- Enfant 1.1
    | |- Enfant 1.2
    |- Enfant 2
    etc ...

    Désolé pour ce code qui polue.

    Je vais vous corriger aussi le code de départ, car comme je l'ai dit plus haut (4ème message où je répond à calagan) il n'y a pas Select *, mais Select champ1, champ2, ... champ5. J'avais << simplifié >> le code pour ne pas vous poluer avec cela.

Discussions similaires

  1. [Newsletter][PEAR > Mail] Besoin de conseils pour ne pas être spam (erreur 550)
    Par kopros2 dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 0
    Dernier message: 23/06/2014, 16h13
  2. [Tableaux] Besoin de conseils avisés
    Par dridri dans le forum Langage
    Réponses: 2
    Dernier message: 21/02/2008, 13h29
  3. [C#] [ADO.NET] Besoin de conseil
    Par djsbens dans le forum Accès aux données
    Réponses: 8
    Dernier message: 01/04/2005, 15h04
  4. Réponses: 3
    Dernier message: 24/12/2004, 12h21
  5. Réponses: 1
    Dernier message: 06/01/2003, 07h55

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