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

Windows Presentation Foundation Discussion :

[MVVM EF] Comment mettre à jour une relation entre 2 entités?


Sujet :

Windows Presentation Foundation

  1. #1
    Membre régulier Avatar de Nixar
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 302
    Points : 85
    Points
    85
    Par défaut [MVVM EF] Comment mettre à jour une relation entre 2 entités?
    Bpnjour,
    Je débute avec le triptyque WPF/MVVM/EF pour la couche d'accès aux données.

    Voici mon modèle (très simple) :

    J'ai un UserControl qui possède tous les champs détails d'un objet 'Project'. Parmi ces champs, une ComboBox qui se peuple avec toutes les instances de l'entité 'Customer' (relation 0.*).

    Tout se passe bien jusqu'à ce que j'essaie de changer le client pour un projet : J'ai d'abord (naïvement je pense ) tenté de faire :
    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
     
    // Délégué exécuté grâce à une EventToCommand
        public class DetailedProjectViewModel : ViewModelBase
        {
            #region Variables
     
            readonly DataBaseModel_Container _context = new DataBaseModel_Container();
            #endregion  
     
    private void CustomerChanged(SelectionChangedEventArgs parameter)
            {
                var newCustomer = (Customer)parameter.AddedItems[0];
                _selectedProject.Customer = newCustomer;                                                          
                _context.SaveChanges();
                }                        
            }
    }

    Plantage avec l'exception suivante :
    InvalidOperationException :Impossible de définir la relation entre les deux objets, car ils sont attachés à des objets ObjectContext différents.
    _selectedProject est la variable locale qui est exposée par la propriété SelectedProject, laquelle est mise à jour via le système de messaging du MVVM light Toolkit :

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     /// <summary>
            /// Initializes a new instance of the DetailedProjectViewModel class.
            /// </summary>
            public DetailedProjectViewModel()
            {            
                // Message subscription
                Messenger.Default.Register<PropertyChangedMessage<Project>>(
                                            this,
                                            (action) => DispatcherHelper.CheckBeginInvokeOnUI(() => SelectedProject = action.NewValue)
                                            );
    ...
    }

    Donc ce que je comprends c'est que je ne peux pas faire des opérations d'assignations aussi simplement parce que mon contexte Entity Framework (déclaré en variable locale à la classe dans chacun de mes ViewModel, un pour la ViewModel Maitre, l'autre pour la ViewModel Details) est différent dans mes 2 UserControl maitre et détail...

    J'ai 2 questions :
    1) Y a-t-il un moyen "propre" d'avoir un contexte Entity Framework commun à tous les ViewModel? Le mettre en propriété de la classe ViewModelBase dont hérite tous les ViewsModel est une bonne idée ou pas? Est-ce que ça va régler mon problème?
    2) J'ai vu que pour une mise à jour de ma base via Entity Framework (typiquement changement de Customer pour un projet donné), pour les propriétés de navigation, je semble devoir xréer une nouvelle EntityKey : je n'ai pas trouvé la façon de le faire, avez-vous des exemples que je pourrais appliquer à mon cas?

    Merci beaucoup d'avance du temps que vous prendrez à me répondre.

    Cordialement,

    Nixar

  2. #2
    Membre régulier Avatar de Nixar
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 302
    Points : 85
    Points
    85
    Par défaut
    Je met le sujet a jour pour tenir au courant de mes tests et me sortir de ce problème de mise à jour d'entités avec Entity Framework :

    J'ai essayé de créer une classe statique contenant une propriété publique statique qui expose ma classe généré par EF et qui dérive d'ObjectContext :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    namespace TrackTime.Database
    {
        static class DbContext
        {
            private static DataBaseModel_Container _context;
            public static DataBaseModel_Container Context
            {
                get { return _context ?? (_context = new DataBaseModel_Container()); }
                set { _context = value; }
            }
        }
    }
    Lors de la tentative de changement de Customer pour un Project donné (cf. post ci-dessus), j'obtiens l'exception suivante :

    Une nouvelle transaction n'est pas autorisée parce que d'autres threads sont en cours d'exécution dans la session
    Soit je suis dans la bonne direction et je dois persister avec des locks (via System.Mutex ?) soit je fais n'importe quoi et je suis preneur de vos idées ... Pour rappel : j'ai un modèle généré via EF et je souhaite mettre à jour une Entité Customer reliée à une entité Project (choix d'un autre Customer pour un Project donné).

    Meci vraiment d'avance pour le temps que vous passerez à me répondre !

    Cordialement,

    Nixar

  3. #3
    Membre régulier Avatar de Nixar
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 302
    Points : 85
    Points
    85
    Par défaut
    Bonjour,
    Je reviens à la charge avec mon souci : comme personne ne répond, j'ai du mal me faire comprendre sur ce qui coince... donc je récapitule :
    • 2 Views (Master/Details) et leurs ViewModel associées. Le modèle est généré avec Entity Framework (OK, cf. diagramme des entités dans le premier post du fil).
    • Lors de la sélection d'un Project dans la ListBox de la View Master, peuplement de la View Detail avec les infos (OK, via les messages du MVVM Light Toolkit)
    • La combobox (de la View Detail) contenant tous les Customers disponibles est chargée via un autre ObjectContext que celui des projets : du coup, si on tente de changer de Customer pour le Project sélectionné, exception car impossible de créer un lien entre 2 entités qui ne sont pas dans le même ObjectContext.


    Je viens d'implémenter des repositories (un pour Customer et un pour Projects) avec une UnitOfWork, en suivant ce qui est fait ici.

    Cependant, je cherche à présent un exemple clair de comment l'utiliser dans mon contexte : car même avec ces 2 patterns, mon ObjectContext qui sert à charger les Projects dans ma View Master (et donc celui qui passe le Project sélectionné à la vue Detail) sera différent de celui qui charge les Customer dans la combobox (celui de la vue Detail).

    Quelqu'un aurait-il un exemple qui résoudrait mon cas? Comment utiliser ces 2 patterns pour mettre à jour la relation entre 2 entités (changer le Customer d'un Project, cf schéma entités dans le 1er post) ?

    Merci vraiment d'avance pour tout ceux qui prendront le temps de me répondre... Si je ne suis pas clair, ou si vous souhaitez une partie ou toutes mes sources, c'est avec plaisir !

    Nicolas

  4. #4
    Membre éprouvé Avatar de jmix90
    Homme Profil pro
    Consultant .Net
    Inscrit en
    Juillet 2007
    Messages
    576
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Juillet 2007
    Messages : 576
    Points : 998
    Points
    998
    Par défaut
    Hello,

    Je n'ai pas eu le temps de tout lire en détail mais voici deux propositions qui me viennent en tête:
    1. Charger les projets et les customers dans le même DataContext.
    2. Implémenter une méthode dans ton repository de Projet pour pouvoir assigner un Customer à un projet.


    Je ne connais pas très bien EF mais ne peut'on pas détacher une entité d'un contexte et la rattacher à un autre ?

    Bon courage,

  5. #5
    Membre régulier Avatar de Nixar
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 302
    Points : 85
    Points
    85
    Par défaut
    Bonjour Jonathan et merci pour ta réponse,

    Charger les projets et les customers dans le même DataContext.
    J'ai pas mal cherché à faire ça : la solution que j'avais trouvé c'était d'exposer mon DataContext dans un classe statique, mais ce n'est pas bon pour 2 raisons :
    1. le mot-clé "static" rend la ressource accessible à travers les classes mais aussi les threads... Résultat, j'obtenais des exceptions au moment de mettre le Customer d'un Project à jour parceque les différentes opérations LINQ précédentes s'étaient faites sur un autre thread.
    2. De ce que j'ai lu, le DataContext grossit petit-à-petit en fonction des requêtes et demandes qui lui sont faites, jusqu'à avoir toute la base en mémoire. En termes de perfs ce n'était pas bon de toute manière.


    Si tu vois d'autres manières de partager mon DataContext entre 2 ViewModels différents, je suis plus que preneur .

    Implémenter une méthode dans ton repository de Projet pour pouvoir assigner un Customer à un projet.
    C'est une bonne idée ! Mais compte-tenu que mon repository de Projects et celui de Customer ne sont pas instanciés dans la même ViewModel, il faudrait que je repasse par les messages c'est ça?


    Je ne connais pas très bien EF mais ne peut'on pas détacher une entité d'un contexte et la rattacher à un autre ?
    Si, c'est possible, mais de ce que j'ai lu ça ne propage pas aux entités définies dans les propriétés de navigation... Mon modèle est très simple et ça pourrait suffire en l'état, mais je cherche une solution qui répondent aux bonnes pratiques et que je pourrais réutiliser quelle que soit la complexité du modèle.

    Merci beaucoup pour tes pistes en tout cas !

Discussions similaires

  1. Comment mettre à jour une page jsp chaque seconde
    Par zizoux5 dans le forum Struts 1
    Réponses: 6
    Dernier message: 25/05/2007, 18h37
  2. Réponses: 14
    Dernier message: 26/03/2007, 16h52
  3. Réponses: 1
    Dernier message: 15/09/2006, 11h24
  4. Comment mettre à jour une date ?
    Par Hokagge dans le forum MFC
    Réponses: 6
    Dernier message: 22/03/2006, 12h30
  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