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

Java Discussion :

Gros pb generic reflection, besoin d'idées


Sujet :

Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Avril 2007
    Messages
    41
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 41
    Par défaut Gros pb generic reflection, besoin d'idées
    Bonjour,

    on m'a demandé de parser un fichier et d'enregistrer les infos en base, le fichier correspond a une 100 aine de tables.

    On ma indiqué vouloir du générique, pour ne pas faire une méthode par type de données a enregistré (table) et afin qu'en cas d'ajout de modification ou autre du fichier à parser, les changements à faire soient minimes et ne quasi pas toucher au code. J'ai indiqué que c’était un peu usine à gaz et surtout que niveau perf c’était moyen.

    J'ai bossé la dessus, j'ai fais mes classes, j'ai une enum qui contient : nomDeTable("nomVariable1", "tailleDuChampDansLeFichier", "nomVariable2", "tailleDuChampDansLeFichier", etc...);

    Ca fonctionne pour la lecture et l'enregistrement, en fait je recupère la classe, je fais un entity = c.newInstance() ou c'est est la class. Je recupère dans l'enum de nom de la variable, je fais un set de la variable avec en paramétre un substring en utilisant la "taille du champ dans le fichier" (nombre de caractère à recuperer dans la ligne) et je fais ca avec tous les setters. Entre temps je donne un type à la variable pour que le setter ne m'envoi pas chi*r.

    Ca fonctionne, mais mon (mes) problèmes :

    - C'est bien d’enregistrer, mais si l'entité existe déjà la base, il faut la mettre à jour. Le problème, c'est la pk ! Lorsqu'elle correspond à une seule variable, pas de soucis, mais quand il s'agit d'une pk qui est un numéro attribué auto, ou qu'il s'agit d'un ID composé, je n'arrive pas à récupérer les ID. J'ai testé un truc qui fonctionne bien, mais niveau perf c'est catastrophique, c'est récupérer la totalité de la table en question et d'utiliser un equals que j'ai redéfini. Mais vous imaginez bien la cata lorsqu'il faut récupérer une table qui contient 2000 enregistrements. J'ai voulu utiliser l'embaddable et embedded id mais le problème, c'est que comme je set les variables une a une, je n'arrive pas a créer la pk puisque je ne passe pas par le constructeur. J'ai voulu tester (rapidement) la création d'une entité avec le constructeur non vide mais le problème, c'est qu'il n'y a jamais le même nombre de paramètres suivant l'entité, donc comment passer les données "découpées" dans le constructeur ?

    - On m'a dit, que vu la complexité et que les perf sont moins bonnes, que si je voulais je pouvais ne pas partir sur le generique mais en gardant toujours une enum ou autre qui defini comment decouper chaque ligne. Le problème, il me reste plus que 3 semaines, et j'aurais aimé avoir quelque chose à présenter au jury, sinon c'est la m**de.

    Donc vu que je n'ai personne pour m'aider la bas, que mon "tuteur" n'est jamais présent, qu'il n'est venu me voir qu'une seule fois (hier) depuis le début du stage, je me permet de vous solliciter afin de savoir si vous auriez une "solution" pour terminer en générique ou une solution assez rapide à mettre en place (sachant que les classes sont faites, l'enum aussi, et qu'il n'y a "que" le code métier a terminer) qui n'utiliserait pas la généricité ?

    Je vous remercie d'avance, ça me ferais ch*er de me planter alors que la formation se passe super bien, que je n'ai que des compliments, que je me donne a fond, mais que j'ai choisi en toute connaissance de cause, le stage ayant un niveau de difficulté le plus élevé pour en apprendre le plus possible (ce qui n'est pas le cas vu que je me retrouve seule, sans aide).

    J’élèverai un autel à votre gloire, prierai et sacrifierai des animaux en l'honneur au forum, si vous arrivez à m'extirper de se merd*er.

  2. #2
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Dans la mesure où tu dois écrire des données dans une base de données, je m'étonne de ne pas voir apparaître JDBC dans ton message, c'est fait pour, pas très compliqué, bref, tout ce qu'il te faut.
    Je te conseille vivement de jeter un œil sur cette techno, personnellement, je l'utilise dans une API faite... pour intégrer des données venant de fichiers CSV dans une base de données... pour te dire si c'est adapté !
    Pour ce qui est des contrôle, JDBC a des méthodes qui permettent d'extraire la structure des tables, longueur des champs, clé primaire, index etc...
    Tu peux regarder ce tutoriel pour te faire une idée.

    Pour le "super générique", tu pourrais partir sur un Statement réutilisé pour toutes les opérations mais bon, je te le déconseille, le risque d'injection est beaucoup trop élevé.
    Pour ma part, j'utilise des PreparedStatement (la seule chose à définir spécifiquement pour la table cible) et ensuite, y a plus qu'à...
    Pour savoir si ta clé existe déjà, tu peux par contre faire une méthode générique via un Statement. Il va de soi que la requête sur un ID auto incrément ne fonctionne que si tu as cet ID dans ton fichier source, sinon, il faut avoir des clés logiques pour savoir si ton enregistrement existe ou non.

    Bref, tu as du boulot
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre averti
    Inscrit en
    Avril 2007
    Messages
    41
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 41
    Par défaut
    Merci pour ta réponse.

    Je n'avais jamais utilisé JDBC excepté pour la connexion à la DB. Je savais pas qu'il y avait plus que ca.

    Par contre le framework de l'entreprise ne permet pas d'utiliser ce que l'on veut, ce qui m'est imposé c'est les EJB QL et les string builders pour créer les requêtes. J'avoue ne pas savoir si JDBC peut être utilisée dans le framework.

    Juste une question, plus niveau conception que dev, comment concevoir cela ? Des @NamedQueries dans chaque classe avec les requêtes pour Update, Insert. Puis dans le code métier un minimum de générique qui créée un classe selon la ligne du fichier à parser. Découpage de la ligne, et appel de la namedQuery ? Ou je suis dans le faux depuis le début ?

    Concernant les pk, j'ai essayé de définir une interface avec une méthode Recuperation_Id, mais pour les clés composées, j'ai tout passé en Embaddable et EmbeddedId mais je sais pas si c'est le framework ultra restrictif ou autre, mais ça marchait pas. Alors qu'il y a rien de plus simple qu'une clé composée que tu peux porter dans une classe, je l'ai utilisé je sais pas combien de fois depuis le début de la formation sur tous les projets auxquels j'ai participé. Enfin bref, j'étais pas fan de généricité, ça s'arrange pas.

    Tu pense qu'il y a moyen de refaire le code de parsing en 3 semaines ? Les classes et l'enum définissant les "curseurs" de position sont déjà fait !

    Merci encore.

  4. #4
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Si tu dois rester dans le monde JPA, la persistence est déjà entièrement générique puisque tu fais un persist(...) ou merge(...) via l'EntityManager, donc, de ce côté, c'est simple.
    Le problème est plutôt l'alimentation de la classe entity de manière générique.
    Ceci dit, via l'introspection, c'est tout à fait possible, si tu connais le nom de la colonne cible pour une données source de ton fichier d'entrée, c'est même relativement simple.
    Voici un exemple
    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
    public class MonEntity
    {
        private Integer uid;
        private String libelle;
     
        public Integer getUid()
        {
            return uid;
        }
     
        public void setUid(Integer uid)
        {
            this.uid = uid;
        }
     
        public String getLibelle()
        {
            return libelle;
        }
     
        public void setLibelle(String libelle)
        {
            this.libelle = libelle;
        }
     
        @Override
        public String toString()
        {
            return "MonEntity [uid=" + uid + ", libelle=" + libelle + "]";
        }
    }
    Le code utilisant l'introspection
    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
            try
            {
                Field fieldUid = MonEntity.class.getDeclaredField("uid");
                fieldUid.setAccessible(true);
                Field fieldLibelle = MonEntity.class.getDeclaredField("libelle");
                fieldLibelle.setAccessible(true);
     
                MonEntity entity = new MonEntity();
     
                fieldUid.set(entity, 1);
                fieldLibelle.set(entity, "libelle 1");
     
                System.out.println("Valeur de l'entity : " + entity.toString());
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre averti
    Inscrit en
    Avril 2007
    Messages
    41
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 41
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Le code utilisant l'introspection
    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
            try
            {
                Field fieldUid = MonEntity.class.getDeclaredField("uid");
                fieldUid.setAccessible(true);
                Field fieldLibelle = MonEntity.class.getDeclaredField("libelle");
                fieldLibelle.setAccessible(true);
     
                MonEntity entity = new MonEntity();
     
                fieldUid.set(entity, 1);
                fieldLibelle.set(entity, "libelle 1");
     
                System.out.println("Valeur de l'entity : " + entity.toString());
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
    C'est exactement ce que j'ai fais ! Aucun pb pour persist. Mon problème en fait, c'est de recuperer l'id, pour qu'apres parsing du fichier, verifier si l'entité existe déjà, afin de savoir s'il faut persist ou juste mettre à jour. Ca ne pose pas de problème, lorsque l'id correspond à une seule variable, c'est lorsque l'id est composé ou que l'id est generé par la DB que je suis bloqué.

    En fait, mon problème, je pense que c'est la création de la clé composée. Puisque j'appelle les setters de chaque variables, je ne passe pas par le constructeur, l'id ne se genère pas. C'est pour ca que je voulais faire des embeddedid et embeddable, mais pour une raison que j'ignore, je n'arrive pas à faire remonter de la DB l'entité qui correspond. Et je ne sais même plus si j'arrive a creer la pk (j'ai fais tellement d'essais, j'en suis perdu).

  6. #6
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Si je comprends bien, tu instancies un objet représentant la clé primaire et j'imagine que tu fais un entityManager.find(...) pour tester l'existance.
    Je ne vois pas trop l'intérêt de faire comme ça, tu n'as qu'à utiliser un Query, là, tu n'as qu'à construire ta requête dans le genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ...
    Query query = entityManager.createQuery("select a from MonEntite a where colonneCle1=:cle1 and colonneCle2=:cle2");
    Object entity = query.getSingleResult();
    Cette partie est presque générique, à part la clause where mais comme c'est une construction de chaîne ça reste assez "générique", ensuite, si tu as une entité en retour, tu fais un merge, sinon, un persist après avoir créé une instance de la classe, le code qui mettra à jour les attributs lui est générique via l'introspection.
    Pour identifier l'objet représentant la clé primaire, tu peux utiliser l'analyse des annotations (@ID en particulier).
    C'est un peu chiant mais bon, tu peux faire un truc comme ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    for (Method method : Entite.class.getMethods())
    {
        if (method.getAnnotation(Id.class) != null)
        {
            System.out.println(method.getName() + " est la méthode ID");
            System.out.println("Le type de l'ID est : " + method.getReturnType());
        }
    }
    Ensuite, je ne comprends pas trop ton problème avec les clés auto-générées, comme leur nom l'indique, tu n'as pas à t'en occuper, la base s'en chargera toute seule.... j'ai raté un truc ?

    Enfin bref, ça aurait été beaucoup plus simple en passant par JDBC, mais c'est mon avis
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

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

Discussions similaires

  1. popup à la mano, besoin d'idées
    Par Alec6 dans le forum JSF
    Réponses: 2
    Dernier message: 15/01/2007, 15h00
  2. Besoin d'idées pour macro word
    Par christel91 dans le forum VBA Word
    Réponses: 9
    Dernier message: 29/11/2006, 10h47
  3. Besoin da'ide pour le Déploiment d'une Application VB6 sur un Serveur d'application
    Par blowlagoon dans le forum Installation, Déploiement et Sécurité
    Réponses: 4
    Dernier message: 03/08/2006, 00h24

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