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

Entity Framework Discussion :

EF4 avec T4 template POCO Entity Generator


Sujet :

Entity Framework

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2003
    Messages : 93
    Par défaut EF4 avec T4 template POCO Entity Generator
    Bonjour,

    J'ai voulu pousser un peu plus loin mon utilisation d'EF4 mais je me retrouve face a plein d'ennui...

    et une belle exception:
    The ObjectContext instance has been disposed and can no longer be used for operations that require a connection
    J'ai une solution sur 4 couches (projets) :

    - Data
    qui contient l'edmx

    - Common
    qui contient mes POCO.
    Ils ont été construit automatiquement a l'Aide du T4 templates (POCO) via l'edmx.
    J'ai juste déplacer le fichier tt contenant tout les modeles dans un projet a part.
    Les liaisons sont bonnes et fonctionne bien.

    - Services
    C'est juste le requétage des données.

    - un projet windows forms de test ... pour s'assurer du bon fonctionnement des méthodes contenus dans Services.
    Plus tard, j'utiliserais un projet web...


    bref...
    Reprenons le projet Services et sa classe EntitiesProvider et la 1ere méthode à tester:

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public static IList<Schedule> GetSchedules() {
                using (var context = new CapBookingEntities()) {
                    return (context.Schedules.OrderBy(s => s.Name).ToList());
                }
            }

    Le Schedule est bien l'objet model dans le projet common (POCO).

    Pour ceux qui ont déjà utilisés le ADO.NET POCO Entity Generator... le code généré utilise une classe supplémentaire FixupCollection pour faire le lien entre toutes les entités.

    Code C# : 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
    87
    88
    89
    90
    91
    92
    //------------------------------------------------------------------------------
    // <auto-generated>
    //     This code was generated from a template.
    //
    //     Changes to this file may cause incorrect behavior and will be lost if
    //     the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
     
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
     
    namespace CapBooking.Common
    {
        public partial class Schedule
        {
            #region Primitive Properties
     
            public virtual int ID
            {
                get;
                set;
            }
     
            public virtual string Name
            {
                get;
                set;
            }
     
            #endregion
            #region Navigation Properties
     
            public virtual ICollection<Service> Services
            {
                get
                {
                    if (_services == null)
                    {
                        var newCollection = new FixupCollection<Service>();
                        newCollection.CollectionChanged += FixupServices;
                        _services = newCollection;
                    }
                    return _services;
                }
                set
                {
                    if (!ReferenceEquals(_services, value))
                    {
                        var previousValue = _services as FixupCollection<Service>;
                        if (previousValue != null)
                        {
                            previousValue.CollectionChanged -= FixupServices;
                        }
                        _services = value;
                        var newValue = value as FixupCollection<Service>;
                        if (newValue != null)
                        {
                            newValue.CollectionChanged += FixupServices;
                        }
                    }
                }
            }
            private ICollection<Service> _services;
     
            #endregion
            #region Association Fixup
     
            private void FixupServices(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.NewItems != null)
                {
                    foreach (Service item in e.NewItems)
                    {
                        item.Schedule_ID = ID;
                    }
                }
     
                if (e.OldItems != null)
                {
                    foreach (Service item in e.OldItems)
                    {
                    }
                }
            }
     
            #endregion
        }
    }


    Maintenant, venons en a mon exception (dans le form.cs du projet winform):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dgvResult.DataSource = EntitiesProvider.GetSchedules();
    A l'exécution, ça plante avec le:
    The ObjectContext instance has been disposed and can no longer be used for operations that require a connection
    en bouche car La collection de Services dans l'objet Schedules n'est plus disponible...

    euh.. l'utilisation des POCO n'est pas censé ne pas se soucier de le connexion et des mappage avec la BDD ?

    bref, je sais pas comment régler ce problème...

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par flolem Voir le message
    euh.. l'utilisation des POCO n'est pas censé ne pas se soucier de le connexion et des mappage avec la BDD ?
    Oui, si tu désactives le lazy-loading et la génération de proxy :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    context.ContextOptions.LazyLoadingEnabled = false;
    context.ContextOptions.ProxyCreationEnabled = false;

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2003
    Messages : 93
    Par défaut
    merci, ça fonctionne

    apparemment, je n'ai pas besoin d'ajouter la ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    context.ContextOptions.ProxyCreationEnabled = false;
    seul sur le LazyLoading suffit.


    Autrement, pour ma culture: A quoi sert exactement le Lazy Loading ?

    Car j'ai lu que c'était une chose très attendu dans EF4.
    Que le SQL généré derrière n'est plus exactement le même... Mais a part ça, je n'ai rien trouvé qui m'explique vraiment son utilité et dans quel scenarii l'utiliser...

    merci



    edit:
    En enlevant le LazyLoading, quelquechose du genre:
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public static IList<Service> GetServices(int ScheduleID) {
                using (var context = new CapBookingEntities()) {
                    Schedule schedule = context.Schedules.FirstOrDefault(s => s.ID == ScheduleID);
                    if (schedule != null)
                        return schedule.Services.ToList();
                }
                return null;
            }

    ne fonctionne plus... du moins renvoi une liste vide.

    Et j'ai besoin d'utiliser ses collections dans certains cas :/
    par exemple, pour faire un:

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    .Where(slot => slot.Services.Any(serv => serv.ID == serviceID))

    Je perd espoir a utiliser des objets POCO et la génération par template au lieu du comportement par défaut (juste l'edmx avec tout généré)

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par flolem Voir le message
    Autrement, pour ma culture: A quoi sert exactement le Lazy Loading ?
    C'est ce qui permet de ne pas charger immédiatement les entités associées.

    Par exemple, si tu as des entités Customer et CustomerOrder, avec une propriété de navigation comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public class Customer
    {
        public virtual IList<CustomerOrder> Orders { get; set; }
    }
    Lorsque tu vas récupérer un Customer, les CustomerOrder associées ne seront chargées qu'au dernier moment, quand tu vas accéder à la propriété Orders

    Si tu le désactives, il faut charger explicitement les propriétés d'association:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    var query =
        from c in  context.Customers.Include("Orders")
        select new
        {
            CustomerName = c.Name,
            Total = c.Orders.Sum(o => o.Total)
        };
    Pour charger plusieurs propriétés d'association, il suffit de chainer les appels à Include :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    context.Customers.Include("Orders").Include("Address").Include("Category")
    Sinon tu peux aussi charger explicitement une propriété associée pour une entité spécifique (plutot que de le faire au niveau de la requête) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Customer c = ...
     
    context.LoadProperty(c, "Orders");
     
    // ou encore (plus propre)
    context.LoadProperty(c, c => c.Orders);

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2003
    Messages
    93
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2003
    Messages : 93
    Par défaut
    merci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    context.LoadProperty(c, c => c.Orders);
    j'aime cette ligne de code.

    Je cherchais également un moyen de me passer des include ou tout autre moyen ou il faut passer une chaine en paramètre

    Lorsque tu vas récupérer un Customer, les CustomerOrder associées ne seront chargées qu'au dernier moment, quand tu vas accéder à la propriété Orders
    Merci de l'éclaircissement.

    Donc ça implique de conserver la connexion a la BDD, du moins laisser le context ouvert.
    Donc pas utilisable avec une clause using...

    Les scenarii d'utilisation me dépasse encore cela dit...

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par flolem Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    context.LoadProperty(c, c => c.Orders);
    j'aime cette ligne de code.

    Je cherchais également un moyen de me passer des include ou tout autre moyen ou il faut passer une chaine en paramètre
    Bizarrement, ils n'ont pas inclus une surcharge pour faire ça... je sais pas trop pourquoi. Ce serait pas très difficile à faire avec une méthode d'extension :

    Code C# : 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
    public static class ExtensionMethods
    {
        public static ObjectSet<TEntity> Include(this ObjectSet<TEntity> objSet,     Expression<Func<TEntity, Object>> selector)
        {
            string propertyName = GetPropertyName(selector);
            return Include(propertyName);
        }
     
        private string GetPropertyName(Expression<Func<TEntity, Object>> expr)
        {
            var memberExpr = expr.Body as MemberExpression;
            if (memberExpr == null)
                throw new ArgumentException("expr", "Expression body must be a member expression");
            return memberExpr.Member.Name;
        }
    }
    ...
     
    from c in context.Customers.Include(c => c.Orders)
    ...

    Par contre le code ci-dessus ne fonctionne que pour les chemin "simples". Par exemple, ça ne gère pas l'équivalent de ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    context.Customers.Include("Orders.OrderDetails")
    (OrderDetails étant une propriété de Orders)

    Ce serait possible de le faire, mais un peu plus compliqué car il faut analyser toute l'expression...

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par flolem Voir le message
    Je cherchais également un moyen de me passer des include ou tout autre moyen ou il faut passer une chaine en paramètre
    Je viens de tomber sur ce billet ; apparemment la CTP 4 inclue une surcharge de Include qui prend en paramètre une expression lambda.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var blogsWithPosts = context.Blogs.Include(b => b.Posts);
    En gros c'est comme la méthode d'extension que je t'ai montrée, mais ça permet aussi de gérer plusieurs niveaux :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var commentsWithPostAndBlog = context.Comments.Include(c => c.Post.Blog);
    Ou même :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    var blogsWithPostsAndComments = context.Blogs.Include(b => b.Posts.Select(p => p.Comments));

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

Discussions similaires

  1. [EF4] Cancel avec les Self Tracking Entities
    Par chrisdot dans le forum Entity Framework
    Réponses: 2
    Dernier message: 22/03/2010, 09h39
  2. Probleme avec les templates
    Par TeC_MaN dans le forum C++
    Réponses: 2
    Dernier message: 08/01/2006, 14h53
  3. [XSLT] Problème avec apply-templates
    Par NeoMan dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 29/12/2005, 14h45
  4. [phpBB] Function avec le Template phpBB
    Par mangafan dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 5
    Dernier message: 27/09/2005, 16h32
  5. Réponses: 3
    Dernier message: 22/08/2005, 18h28

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