52 votes

Meilleures pratiques pour utiliser Entity Framework avec DataBinding WPF

Je suis en train de construire ma première véritable application WPF (c'est-à-dire la première destinée à être utilisée par quelqu'un d'autre que moi), et je suis encore en train de m'habituer à la meilleure façon de faire les choses en WPF. C'est une application d'accès aux données assez simple utilisant l'Entity Framework encore assez récent, mais je n'ai pas pu trouver beaucoup de conseils en ligne sur la meilleure façon d'utiliser ces deux technologies (WPF et EF) ensemble. J'ai donc pensé présenter ma façon de procéder et voir si quelqu'un a de meilleures suggestions.

  • J'utilise l'Entity Framework avec SQL Server 2008. L'EF me semble à la fois beaucoup plus compliqué qu'il ne devrait l'être et pas encore mature, mais Linq-to-SQL semble mort, donc autant utiliser la technologie sur laquelle Microsoft semble se concentrer.

  • C'est une application simple, donc je n'ai pas (encore) jugé bon de construire une couche de données distincte autour d'elle. Quand je veux accéder aux données, j'utilise des requêtes Linq-to-Entity assez simples, généralement directement depuis mon code-behind, par exemple :

    var families = from family in entities.Family.Include("Person")
               orderby family.PrimaryLastName, family.Tag
               select family;
  • Les requêtes Linq-to-Entity renvoient un résultat IOrderedQueryable, qui ne reflète pas automatiquement les changements dans les données sous-jacentes, par exemple, si j'ajoute un nouvel enregistrement via du code au modèle de données de l'entité, l'existence de ce nouvel enregistrement n'est pas automatiquement reflétée dans les divers contrôles référençant la requête Linq. Par conséquent, je place les résultats de ces requêtes dans une ObservableCollection pour capturer les changements des données sous-jacentes :

    familyOC = new ObservableCollection(families.ToList());
  • Je mappe ensuite l'ObservableCollection sur un CollectionViewSource, afin de pouvoir effectuer des filtres, des tris, etc., sans avoir à retourner à la base de données.

    familyCVS.Source = familyOC;
    familyCVS.View.Filter = new Predicate(ApplyFamilyFilter);
    familyCVS.View.SortDescriptions.Add(new System.ComponentModel.SortDescription("PrimaryLastName", System.ComponentModel.ListSortDirection.Ascending));
    familyCVS.View.SortDescriptions.Add(new System.ComponentModel.SortDescription("Tag", System.ComponentModel.ListSortDirection.Ascending));
    
    Je lie ensuite les divers contrôles et autres éléments à ce CollectionViewSource :
    
    Quand j'ai besoin d'ajouter ou de supprimer des enregistrements/objets, je le fais manuellement à la fois dans le modèle de données de l'entité et dans l'ObservableCollection :
    
    private void DeletePerson(Person person)
    {
        entities.DeleteObject(person);
        entities.SaveChanges();
        personOC.Remove(person);
    }
    
    J'utilise généralement des contrôles StackPanel et DockPanel pour positionner les éléments. Parfois j'utilise un Grid, mais il semble difficile à maintenir : si vous voulez ajouter une nouvelle ligne en haut de votre grille, vous devez toucher directement chaque contrôle hébergé par la grille pour lui dire d'utiliser une nouvelle ligne. Argh. (Microsoft n'a jamais vraiment semblé comprendre le concept DRY.)
    Je n'utilise presque jamais le designer WPF de VS pour ajouter, modifier ou positionner des contrôles. Le designer WPF fourni avec VS est vaguement utile pour voir à quoi votre formulaire va ressembler, mais là encore, pas vraiment, surtout si vous utilisez des modèles de données qui ne sont pas liés à des données disponibles au moment de la conception. Si je dois modifier mon XAML, je l'accepte et je le fais manuellement.
    La plupart de mon vrai code est en C# plutôt qu'en XAML. Comme je l'ai mentionné ailleurs, indépendamment du fait que je n'aie pas encore l'habitude de "penser" en XAML, XAML me semble être un langage maladroit et laid, qui vient aussi avec un support du designer et de l'intellisense médiocres, et qui ne peut pas être débogué. Argh. Par conséquent, chaque fois que je peux voir clairement comment faire quelque chose en code-behind C# que je ne peux pas facilement voir comment faire en XAML, je le fais en C#, sans faire d'excuses. Il a été écrit à profusion qu'il était une bonne pratique de presque ne jamais utiliser le code-behind dans une page WPF (disons, pour la gestion d'événements), mais pour l'instant du moins, cela ne me semble pas du tout logique. Pourquoi devrais-je faire quelque chose dans un langage laid et maladroit avec une syntaxe affreuse, un éditeur étonnamment mauvais et pratiquement aucune sécurité de type, quand je peux utiliser un langage agréable et propre comme le C# qui a un éditeur de classe mondiale, un intellisense presque parfait et une sécurité de type inégalée ?
    
    Voilà où j'en suis. Des suggestions ? Est-ce que j'ai oublié des éléments importants ? Est-ce que je devrais vraiment penser à faire les choses différemment ?

19voto

user73993 Points 414

Vous devez implémenter un modèle de répertoire pour séparer les préoccupations de WPF d'EF

Ensuite, vous pouvez utiliser des génériques pour réduire la complexité de la manipulation d'EF avec CollectionViewSource

Un modèle de répertoire bien conçu devrait réduire les niveaux de code et permettre à tout ORM d'être substitué (nécessaire pour des tests décents)

Quelques idées à ce sujet se trouvent ici

http://blog.nicktown.info/2008/12/10/using-a-collectionviewsource-to-display-a-sorted-entitycollection.aspx

7voto

NotDan Points 9519

Aussi, je ne pense pas que vous ayez besoin de faire un ToList() ici. Je crois que ObservableCollection() prend un IEnumerable qui est déjà ce que families est. Si vous faites un ToList, et que vous passez cela à ObservableCollection, alors je pense que vous allez parcourir tous vos enregistrements deux fois.

familyOC = new ObservableCollection(families.ToList());

À la place, essayez ceci, ce qui devrait être un peu plus rapide :

familyOC = new ObservableCollection(families);

5voto

amaca Points 751

Je comprends d'où tu viens. Cet article de Josh Smith m'a aidé à changer (ou à commencer à changer) d'état d'esprit pour que vous puissiez tirer des avantages de WPF plutôt que de le voir comme un framework étrange, obstructif, difficile à déboguer et peu convivial!

4voto

NotDan Points 9519

Mes recommandations sont les suivantes : si possible, utilisez Expression Blend pour concevoir votre interface, au lieu de Code Behind et au lieu d'utiliser le concepteur Visual Studio, cela vous fera gagner beaucoup de temps. Essayez également de repenser à l'utilisation de C# au lieu de xaml. Xaml n'est pas si laid si vous le faites de la "manière WPF". Souvent, lorsque je pense qu'il est plus facile d'utiliser le code derrière au lieu de xaml, c'est parce que je le fais de la mauvaise manière et j'ai besoin de repenser à la meilleure façon de fonctionner avec WPF/xaml. Une fois que vous vous y habituez, xaml est génial. J'ai également utilisé Entity Framework qui n'est pas encore génial. Je préfère NHibernate.

2voto

J'ai suivi ce lien depuis mon blog et je voulais mentionner quelque chose d'autre que j'ai trouvé avec EF. Un peu hors sujet, mais pas totalement.

J'ai remarqué des problèmes de performance fous avec EF lorsque j'utilise le .Include. MS explique pourquoi dans un article sur leur site Web, j'ai donc en fait commencé à déplacer la plupart de mon code pour utiliser la méthode .Load à la place.

Parce que c'est une tâche fastidieuse à faire et parce que je n'ai pas trouvé d'autre moyen de le faire... J'ai créé ma propre méthode appelée "IncludeByRoundTrip". Ce qu'elle fait, c'est prendre un chemin d'objet et s'assurer que l'intégralité du chemin est chargée. Le résultat final est le même que lors de l'utilisation de l'inclusion, cependant en coulisses, j'appelle simplement Load sur toutes les propriétés dans le graphe d'objets.

Cela serait similaire à faire quelque chose comme order.Load("Customer.Address") si un tel mécanisme existait. Quoi qu'il en soit, allez voir sur mon blog et faites-moi part de vos découvertes. Je serais curieux de savoir si d'autres ont remarqué des ralentissements en utilisant Include et si vous avez d'autres approches pour attaquer la situation.

Il y a plus d'informations sur ma solution à l'adresse suivante : http://blog.nicktown.info/2009/07/27/method-to-load-an-entire-object-graph-using-adonet-entity-framework.aspx.

Encore une fois, désolé pour ce léger hors-sujet, mais je suis impatient de lire vos réponses.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X