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 :

[NHibernate] Problème Récupération Jointure


Sujet :

C#

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 14
    Points : 30
    Points
    30
    Par défaut [NHibernate] Problème Récupération Jointure
    Bonjour,

    Je suis confronté à un problème en utilisant NHibernate(je précise, je suis débutant en C#)

    J'execute en 1er :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    this.fiamEnCours = ReqFiam.Get(comboBoxSociete.SelectedItem as Societe, this.anneeMois.ToString("MMyyyy"));
    fiamEnCours est un champ privé de ma classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    private Fiam fiamEnCours;
    Voici le Code de ReqFiam.Get() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     public static Fiam Get(Societe societe, string mois)
            {
                Fiam f;
                using (ISession session = Program.SessionFactory.OpenSession())
                {
                    ICriteria critere = session.CreateCriteria<Fiam>();
                    critere.Add(Restrictions.Eq("Mois", mois));
                    critere.Add(Restrictions.Eq("Societe", societe));
                    f = critere.UniqueResult<Fiam>();
                    return f;
                }            
            }
    Voici la structure de la classe Fiam

    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
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
      public partial class Fiam {
     
            private int _IdFiam;
     
            private string _Mois;
     
            private Societe _Societe;
     
            private Iesi.Collections.ISet _FiamDetails;
     
            #region Extensibility Method Definitions
     
            partial void OnCreated();
     
            #endregion
     
            public Fiam()
            {
                this._FiamDetails = new Iesi.Collections.HashedSet();
                OnCreated();
            }
     
     
            /// <summary>
            /// There are no comments for IdFiam in the schema.
            /// </summary>
            public virtual int IdFiam
            {
                get
                {
                    return this._IdFiam;
                }
                set
                {
                    this._IdFiam = value;
                }
            }
     
     
            /// <summary>
            /// There are no comments for Mois in the schema.
            /// </summary>
            public virtual string Mois
            {
                get
                {
                    return this._Mois;
                }
                set
                {
                    this._Mois = value;
                }
            }
     
     
            /// <summary>
            /// There are no comments for Societe in the schema.
            /// </summary>
            public virtual Societe Societe
            {
                get
                {
                    return this._Societe;
                }
                set
                {
                    this._Societe = value;
                }
            }
     
     
            /// <summary>
            /// There are no comments for FiamDetails in the schema.
            /// </summary>
            public virtual Iesi.Collections.ISet FiamDetails
            {
                get
                {
                    return this._FiamDetails;
                }
                set
                {
                    this._FiamDetails = value;
                }
            }
        }
    Et enfin mon problème :

    Lorsque je rentre en débogage,

    Un point d'arrêt sur return f dans ReqFiam.Get
    J'ai bien ma collection f.FiamDetails qui contient des datas.

    Par contre dès que je sort de ReqFiam.Get,
    this.fiamEnCours.FiamDetails ne contient plus de données

    Par ailleurs, voici ce que je vois noté dans this.FiamEncours.FiamDetails
    base {NHibernate.HibernateException} = {"Initializing[FiamCollaborateurs.Entites.Fiam#5]-failed to lazily initialize a collection of role: FiamCollaborateurs.Entites.Fiam.FiamDetails, no session or session was closed"}
    Doit je comprendre que comme ma session Hibernate a été fermé dans ReqFiam.Get, je peux plus conserver ma collection (qui viens d'une jointure de table) ? Les autres data (hors jointure) sont bien conservé.

    Pourriez-vous m'éclairer sur ce sujet, et comment faire en sorte que mon
    this.fiamEnCours soit toujours égale à mon f retourné du Get()

    Merci d'avance,

  2. #2
    Membre habitué
    Homme Profil pro
    Architecte C#
    Inscrit en
    Février 2003
    Messages
    78
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte C#

    Informations forums :
    Inscription : Février 2003
    Messages : 78
    Points : 144
    Points
    144
    Par défaut
    Bonjour, NHibernate se comporte par défaut en Lazy loading.
    Cela signifie que ta propriété FiamDetails sera chargée uniquement lorsque tu y accèdera, et pour cela, elle aura besoin de la session. hors tu consomme cet objet hors de ton using. ta session est disposée et tu en as besoin pour accèder aux enfants => exception.

    Tu peux faire une verrue en forcant la collection à lazy="false", mais je te recommande de te documenter sur la gestion de la session.

    tu aura ensuite comme option : les implémentations de ICurrentSessionContext si tu es en web ou service WCF
    le pattern UnitOfWork si tu es en appli riche.

    C'est un point assez ardu a appréhender sachant que la session doit etre ouverte assez longtemps pour te permettre de parcourir, modifier, supprimer tes objets metiers mais pas trop longtemps car elle va garder en cache mémoire tous les objets qu'elle va récupérer de la base => risque OutOfMemoryException.

    Bonne journée.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 14
    Points : 30
    Points
    30
    Par défaut
    Tu peux faire une verrue en forcant la collection à lazy="false", mais je te recommande de te documenter sur la gestion de la session.
    J'ai effectivement mis un defaut-lazy = false et je ne constate plus ce problème.

    C'est en restant à False que je risque des problèmes de OutOfMemoryException ?

    Mon application est légère donc pas de risque mais, si j'ai bien compris, il faudrait que je me documente sur le pattern UnitOfWork (je travail sur du winform) pour essayer de pallier ces pb ?

  4. #4
    Membre habitué
    Homme Profil pro
    Architecte C#
    Inscrit en
    Février 2003
    Messages
    78
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte C#

    Informations forums :
    Inscription : Février 2003
    Messages : 78
    Points : 144
    Points
    144
    Par défaut
    Oui, le UnitOfWork est adapté à ton cas.
    Le out of memory risque de survenir si tu garde une session ouverte pour toute ton application, ce qui au vu de ton code n'a pas l'air d'être le cas.

    Le concept derrière nhibernate pour les mises à jour et la bonne pratique est de fonctionner en transactionnel :

    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
     
    using(var session = SessionFactory.OpenSession())
    // ou using(var session = MonUnitOfWork.MaSessionEnCours)
    {
        using(var transaction = session.BeginTransaction()) // Sauf si géré par l'Unit Of Work
        try
        {
            // Je charge l'objet
            var obj = session.Get<MonObjet>(objectId);
     
            // Je modifie mon objet
            obj.Nom = "Tagada";
            obj.Prenom = "Tsoin Tsoin";
     
           // Je commite ma transaction (et tous les changements que j'ai fait sur les objets chargés depuis sa création, pas besoin d'update. En revanche, si il y a des save ou delete, il faut les coder).
          transaction.Commit();
        }
        catch
        {
            transaction.Rollback();
            throw;
        }
    }

    Pour l'UnitOfWork, cet article n'est pas mal pour appréhender le concept et une mise en oeuvre rapide :

    http://nhforge.org/wikis/patternsand...k-pattern.aspx

    tu risque d'etre redirigé dessus, alors, sache aussi qu'utiliser un pattern repository ou dal en plus de NHibernate n'a pas trop de sens : l'objet ISession étant déjà tout ca a part entière.

    en fait, le lazy n'a d'intéret qu'en cas de grappe complexe pour éviter de charger toute la base de données en demandant un objet.

    Pour des sous propriétés auquelles tu accèdera systématiquement, il n'a pas d'utilité. En revanche, en général, il est recommandé de partir avec et de l'enlever si besoin selon les infos d'un analyseur de performances.
    (NHibernateProfiler est une mine d'informations sur les bonnes pratiques et le fonctionnement interne de NHibernate : http://nhprof.com/, il y a une version d'essai de 30 jours, je le recommande très chaudement)

    tu trouvera aussi une mine d'informations sur le blog http://ayende.com/blog même si elles commencent à dater un peu, elles restent d'actualité.

    Enfin, dernière recommandation : fais toi les dents sur les fichiers de mapping à la main avant d'utiliser un outil. la courbe d'apprentissage est rude, mais tu verra après a quel points ces outils sont verbeux sans forcément de raisons (quoique devart soit le plus complet que j'ai utilisé jusqu'à présent).

    Bonne soirée

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 14
    Points : 30
    Points
    30
    Par défaut
    Vimaire, Merci beaucoup pour toutes ces informations.

    Juste une dernière question.

    J'avait intentionnellement enlever la transaction car je ne voyait pas trop l’intérêt de la mettre pour faire des SELECT.

    Est-il mieux d'en mettre une quelque soit le type de requêtes ?

  6. #6
    Membre habitué
    Homme Profil pro
    Architecte C#
    Inscrit en
    Février 2003
    Messages
    78
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte C#

    Informations forums :
    Inscription : Février 2003
    Messages : 78
    Points : 144
    Points
    144
    Par défaut
    Le profiler le recommande systématiquement, arguant que, de toutes manières, la récupération se fera de toute manièredans une transaction pour l'isoler au cas où des updates se passent "en meme temps".

    En spécifiant toi même la transaction, c'est un peu comme si tu spécifiais le scope pendant lequel tu as besoin de travailler sur l'objet. (si ce n'est que la récupération, c'est "juste le temps de le récupérer et le mapper (pour permettre le lazy loading)".
    Cependant, ça peut être également "le temps de le récupérer, et le modifier ou l'effacer (auquel cas, en cas d'erreur, tu pourra faire un rollback sur la transaction et garder tes objets dans un état pérenne)"

    Vois la transaction comme pour l'unit of work : le processus métier effectif qui correspond a la demande de l'utilisateur.

    Si ca passe, le commit sera transparent.

    Si ça pète en revanche, on peut revenir à l'état initial puis faire remonter l'erreur à l'utilisateur qui lui indiquera que son processus ne s'est pas déroulé correctement, mais tout ceci, sans impacter les données existantes.

    Un très bon livre pour appréhender la mécanique de NHibernate est "NHibernate in Action" très détaillé sur tous les points

    et brancher le profiler t'aidera énormément également.

Discussions similaires

  1. Probléme de jointure
    Par Ajrarn dans le forum Langage SQL
    Réponses: 14
    Dernier message: 24/02/2005, 14h57
  2. Vraisemblable problème de jointure
    Par pimousse76 dans le forum Langage SQL
    Réponses: 3
    Dernier message: 23/02/2005, 15h34
  3. [MS Access] Problème de jointure
    Par Erakis dans le forum Langage SQL
    Réponses: 3
    Dernier message: 07/02/2005, 21h15
  4. Problème de jointure ?!
    Par ebaynaud dans le forum Langage SQL
    Réponses: 8
    Dernier message: 03/11/2004, 11h27
  5. [Débutant] Problème récupération de données
    Par flogreg dans le forum Servlets/JSP
    Réponses: 26
    Dernier message: 20/08/2004, 17h29

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