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 :

Entity Framework + ObservableCollection => Comment mettre à jour ?


Sujet :

Entity Framework

  1. #1
    Membre habitué

    Inscrit en
    Février 2007
    Messages
    250
    Détails du profil
    Informations personnelles :
    Âge : 53

    Informations forums :
    Inscription : Février 2007
    Messages : 250
    Points : 162
    Points
    162
    Par défaut Entity Framework + ObservableCollection => Comment mettre à jour ?
    Bonjour à tous et à toutes.

    Je réalise une application basée sur Entity Framework Code first.
    Jusque là, pas de problèmes.

    J'ai découpé mon projet en différentes librairies :

    DTO (Data Transfer Objects) / DAL (Data Object Layer) / Puis l'application découpée en MVVM avec MVVM Light.

    En (très) gros, DTO contient les classes.
    DAL contient les accesseurs aux tables (liste de classes du DTO).
    L'application se charge de gérer la base.

    Le problème que j'ai actuellement, c'est que via le DAL, je récupère des listes de ObservableCollection

    Exemple : La classe DTO : EntityProfile qui contient un nom, une description, un type de profile.
    Un classe DAL qui peut récupérer la liste des profiles :
    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
    public class ProfileProvider
        {
     
            /// <summary>
            /// Récupérer la liste des profiles.
            /// </summary>
            /// <returns>La liste des profiles utilisateurs.</param>
            public ObservableCollection<EntityProfile> GetProfiles()
            {
                ObservableCollection<EntityProfile> lstEntityProfile = null;
     
                using(DatabaseManagerContext context = DatabaseManagerContext.CreateInstance())
                {
                    lstEntityProfile = context.Profiles.ToObservableCollection();
                }
     
                return lstEntityProfile;
            }
        }
    La fonction DatabaseManagerContext.CreateInstance() se charge de créer une instance DbContext qui est disposée à chaque utilisation.

    Ici, cette fonction retourne tout la liste des profiles disponibles. Je l'ajoute dans un grid via WPF et la liste des profiles s'affiche dans ma grid.
    Une fois édité dans l'IHM, on peut modifier le nom, le commentaire du profile. Puis sauver en base et c'est là que j'ai un problème :
    Je met à jour la base via ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
            /// <summary>
            /// Mise à jour d'un profile.
            /// </summary>
            /// <param name="_objProfile">Objet profile à mettre à jour</param>
            /// </summary>
            public void UpdateProfile(EntityProfile _objProfile)
            {
                using(DatabaseManagerContext context = DatabaseManagerContext.CreateInstance())
                {
                    context.Entry(_objProfile).State = EntityState.Modified;
                    context.SaveChanges();
                }
            }
    Sauf qu'entre le code de mise à jour de la base et mon IHM il y un monde.
    Normalement context.SaveChanges(); devrait envoyer une notification de la liste ObservableCollection afin que l'IHM reflète toutes les modifications de la base.
    Et là je ne sais pas faire ce lien. Déjà, le contexte est recréé systématiquement car using créé un dispose qui libère l'instance, l'instance qui lit et celle qui écrit n'est donc pas la même (dur dans ce cas de notifier l'Observable collection) !
    Bien sur je pourrais dans l'IHM recharger la liste des profiles et remettre à jour l'IHM mais ce que je souhaite c'est d'avoir un mécanisme plus générique car modifier un profile peut se relèter dans une autre vue, différente de celle qui a modifié le profile.

    Je ne sais pas si c'est clair, je voulais utiliser le CRUD de la base ou quelque chose comme ça mais je ne sais pas comment faire.
    Si vous avez une idée ou un tutoriel ça m'intéresse...

    Merci d'avance.

  2. #2
    Membre expert
    Avatar de GuruuMeditation
    Homme Profil pro
    .Net Architect
    Inscrit en
    Octobre 2010
    Messages
    1 705
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net Architect
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2010
    Messages : 1 705
    Points : 3 568
    Points
    3 568
    Par défaut
    Ça peut peut-être t'aider: http://msdn.microsoft.com/en-US/data/jj574514
    Microsoft MVP : Windows Platform

    MCPD - Windows Phone Developer
    MCPD - Windows Developer 4

    http://www.guruumeditation.net

    “If debugging is the process of removing bugs, then programming must be the process of putting them in.”
    (Edsger W. Dijkstra)

  3. #3
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2010
    Messages
    64
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2010
    Messages : 64
    Points : 155
    Points
    155
    Par défaut
    Bonjour,

    Il me semble que la bonne pratique pour le DbContext c'est de le créer et le maintenir pour la durée de vie d'une page.

    Si on le garde plus longtemp (un singleton sur la durée de vie de l'app par exemple) on vas avoir des problèmes de perf parcequ'etant donné qu'il track tous les changement sur les objets qu'il a récupéré il risque de devenir trop gros.
    Si on le garde moins longtemp (un par requete dans ton cas) on risque d'avoir aussi de problèmes de perf en cas de nombreuse requete.

    De plus en adoptant cette methode ton context.SaveChange() vas passer directement puisque cette fois on as bien la meme instance du dbContext qui lit et qui ecrit

    Sinon je pense qu'il faut que tu regarde du coté de attach() et detach() pour lier tes objet au bon context.

  4. #4
    Membre habitué

    Inscrit en
    Février 2007
    Messages
    250
    Détails du profil
    Informations personnelles :
    Âge : 53

    Informations forums :
    Inscription : Février 2007
    Messages : 250
    Points : 162
    Points
    162
    Par défaut
    Le problème c'est que j'ai plein de pages ouvertes au même moment (ribbon) doc cette solution va être compliquée.

  5. #5
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2010
    Messages
    64
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2010
    Messages : 64
    Points : 155
    Points
    155
    Par défaut
    Un context par page donc par lot de donnée cohérent (au niveau fonctionnel)te semble envisageable?

    Sinon tu n'as plus qu'a réattacher manuellement tous tes objets a ton nouveau context avant de faire ton SaveChange() mais c'est source d'erreur et complexe pour peu que ta structure de donnée ne soit pas triviale.
    A noter que dans ce cas la tu dois modifier manuellement l'entityState de ton objet si tu veux qu'il soit sauver en base au SaveChange()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    context.Unicorns.Attach(existingUnicorn); // Entity is in Unchanged state
    context.Entry(existingUnicorn).State = EntityState.Modified;
    Tu trouveras de la doc en googlant sur la question , par exemple
    http://blogs.msdn.com/b/adonet/archi...ty-states.aspx

  6. #6
    Membre habitué

    Inscrit en
    Février 2007
    Messages
    250
    Détails du profil
    Informations personnelles :
    Âge : 53

    Informations forums :
    Inscription : Février 2007
    Messages : 250
    Points : 162
    Points
    162
    Par défaut
    Ecoute, je vais examiner ta solution.
    Ma base n'est pas complexe.
    Tout passe par des classes de base et j'ai une seule classe de contexte qui est créée à chaque fois.
    Je pense que chaque vue peut s'abonner et à la classe mère qui gère la connexion peut réatacher tous les contexte 'abonnés' à chaque contexte créé.
    C'est une solution envisageable relativement facilement.
    Je pense que le contexte envoie des notification de type CRUD ?
    Si c'est le cas j'ai une chance de mettre en place un processus général.

    Je ne met pas en résolu mais j'examine cette solution et je reviens poster si je trouve une réponse.

    Merci.

  7. #7
    Membre habitué

    Inscrit en
    Février 2007
    Messages
    250
    Détails du profil
    Informations personnelles :
    Âge : 53

    Informations forums :
    Inscription : Février 2007
    Messages : 250
    Points : 162
    Points
    162
    Par défaut
    Pour faire plus simple et ne pas garder mes contextes ouverts je pense que je suis sur une piste.

    Dans le SaveChanges du DbContext, on peut savoir avant de sauver quels sont les entités qui vont être impactées grace à la fonction :
    IEnumerable<DbEntityEntry> lst = ChangeTracker.Entries();

    Lorsque l'on sauve, et qu'aucune exception n'est pas levée, il suffit de prévenir les VueModel abonnées que certains objets ont changés.

    Est-ce facile ? Je ne sais pas.
    Bizzare que ça ne soit pas déjà fait au niveau du DbContext : genre il notifie qu'il modifie ça ou ça...

  8. #8
    Membre habitué
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2010
    Messages
    64
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2010
    Messages : 64
    Points : 155
    Points
    155
    Par défaut
    Tu peux le savoir au niveau du DbContext directement.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     IEnumerable<ObjectStateEntry> entries =((IObjectContextAdapter)_dbContext).ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted);
    Soit dit si tu utilise ton DbContext pour remonter tes objects puis le dispose immédiatement derrière tes object ne sont plus attachés a aucun contexte il n'y a donc plus de "tracking" des modifs et ce seras a toi de le faire a la mano......

    Lorsque tu instanciears un nouveau context il n'auras aucune "mémoire" de ce qui c'est passé précedement dans les autres dbContext.

  9. #9
    Membre habitué

    Inscrit en
    Février 2007
    Messages
    250
    Détails du profil
    Informations personnelles :
    Âge : 53

    Informations forums :
    Inscription : Février 2007
    Messages : 250
    Points : 162
    Points
    162
    Par défaut
    C'est exactement ce que je compte faire. Une classe CRUDManager qui contient un singleton.
    On abonne sa liste (mais certainement par la suite ses entités ou autre), pour le moment je commence avec des ObservableCollection.
    A chaque fois que je sauve je fais un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
            public override int SaveChanges()
            {
                var changes = CRUDManager.Instance.RecordChanged(this);
     
                int iRet = base.SaveChanges();
                CRUDManager.Instance.ApplyChanged(changes);
     
                return iRet;
            }
    Et chaque collection sera notifiée par ce système.
    Il est possible que je livre ce code si certains sont intéressés...
    Le problème c'est que je ne peux pas notifier APRES le save car tous les états après le save sont mis à jours.

  10. #10
    Membre habitué

    Inscrit en
    Février 2007
    Messages
    250
    Détails du profil
    Informations personnelles :
    Âge : 53

    Informations forums :
    Inscription : Février 2007
    Messages : 250
    Points : 162
    Points
    162
    Par défaut
    Mon CRUD manager fonctionne très bien (mise à part une petite limitation) sur les observables collections et sur les Eléments.
    Si ça intéresse du monde je pourrais le publier ici mais le code est assez long.

  11. #11
    Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Points : 67
    Points
    67
    Par défaut
    Bonjour,

    étant bloqué sur un problème similaire, un coup d'oeil sur ta solution pourrait au moins me donner des indices pour résoudre mes petits soucis.

    Serait-il encore possible d'y avoir accès s'il te plait ?

Discussions similaires

  1. NET 3.0 : comment mettre à jour le framework?
    Par raton_laveur dans le forum Framework .NET
    Réponses: 1
    Dernier message: 02/04/2009, 08h39
  2. Réponses: 2
    Dernier message: 13/09/2006, 10h23
  3. [Rave Report] Comment mettre à jour le produit
    Par Leesox dans le forum Rave
    Réponses: 2
    Dernier message: 11/04/2005, 21h00
  4. Comment mettre à jour un exécutable ?
    Par rvzip64 dans le forum Langage
    Réponses: 10
    Dernier message: 09/12/2004, 18h43
  5. Comment mettre à jour une ligne sans doublon via déclencheur
    Par fuelcontact dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 02/08/2004, 15h56

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